<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>John Guenin</title>
    <link>http://john.guen.in</link>
    <language>en</language>
    <webMaster>john@guen.in (John)</webMaster>
    <copyright>Copyright 2007-2010</copyright>
    <ttl>60</ttl>
    <pubDate>Tue, 17 Apr 2007 00:21:00 GMT</pubDate>
    <description>Human factors, Rails and other Webbery</description>
    <item>
      <title>Send files faster with X-Sendfile</title>
      <link>http://john.guen.in/past/2007/4/17/send_files_faster_with_xsendfile/</link>
      <pubDate>Mon, 16 Apr 2007 20:51:00 GMT</pubDate>
      <guid>http://john.guen.in/past/2007/4/17/send_files_faster_with_xsendfile/</guid>
      <description>&lt;div class="note"&gt;&lt;p&gt;Please don&amp;#8217;t let this post scare you away from &lt;a href="http://mongrel.rubyforge.org/"&gt;Mongrel&lt;/a&gt;.  I have found it much more stable and easier to set up than FCGI.  Mongrel + Capistrano saved me from the brink of insanity when deployment came around.  The memory issue with &lt;code&gt;send_file&lt;/code&gt; is indicative of a bigger issue with Ruby&amp;#8217;s garbage collection&amp;#8212;not a problem with Mongrel itself.&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;There&amp;#8217;s this slick HTTP header called &amp;#8220;X-Sendfile&amp;#8221; that Apache and Lighttpd support.  It was made to address this kind of problem (isn&amp;#8217;t that convenient?).  Now, when you send an HTTP response, all you have to do is tack on an X-Sendfile header with the path of the file you need to send&amp;#8212;don&amp;#8217;t worry about actually reading the file or sending any of those bytes yourself. The web server will load the file you specified and send it downstream.&lt;/p&gt;

&lt;p&gt;This is loads easier on your Rails process (it just sets the headers and gets on with life), and you get all the cool file transfer functionality already baked into your web server (like proper caching, resuming, etc).  Of course, you can send any file that the web server can read, not just files in your normal public directory.  This makes it perfect for sending private or protected content to specific users of your app.&lt;/p&gt;

&lt;h2&gt;Setting those magical headers&lt;/h2&gt;

&lt;p&gt;You shouldn&amp;#8217;t be too surprised that Rails makes it easy to set this header correctly.  You could do something like this:&lt;/p&gt;

&lt;p class="note"&gt;This code sample has been excerpted from the &lt;a href="http://wiki.rubyonrails.org/rails/pages/HowtoSendFilesFast"&gt;Ruby on Rails Wiki&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;filename = "/var/www/myfile.xyz" 
response.headers['Content-Type'] = "application/force-download" 
response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filename)}\"" 
response.headers["X-Sendfile"] = filename
response.headers['Content-length'] = File.size(filename)
render :nothing =&amp;gt; true
&lt;/code&gt;&lt;/pre&gt;

&lt;p class="note"&gt;Apache users will need &lt;a href="http://celebnamer.celebworld.ws/stuff/mod_xsendfile"&gt;mod_xsendfile&lt;/a&gt;.  Lighttpd users should look into &lt;a href="http://blog.lighttpd.net/articles/2006/07/02/x-sendfile"&gt;mod_fastcgi&lt;/a&gt; and &lt;a href="http://blog.lighttpd.net/articles/2006/07/22/mod_proxy_core-got-x-sendfile-support"&gt;mod_proxy_core&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, as long as your server is correctly configured, you file should be zipping along at record speeds.  If you need this functionality in more than one action or more than one app it&amp;#8217;s not terribly DRY&amp;#8230;  and you should probably write some functional tests for this&amp;#8230; ugh.  Someone really ought to write a plugin.&lt;/p&gt;

&lt;h2&gt;The XSendfile plugin&lt;/h2&gt;

&lt;p class="note"&gt;The advanced or impatient may want to jump straight to the &lt;a href="/rdoc/x_send_file/"&gt;rdoc&lt;/a&gt; or &lt;a href="/svn/plugins/x_send_file"&gt;source&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I wrapped up all this goodness in a plugin.  I&amp;#8217;ve had this running on a production server (Apache2 + Mongrel) for a couple of weeks with no issues.  For the good of humanity, it comes complete with rdoc and tests.&lt;/p&gt;

&lt;h3&gt;Installation&lt;/h3&gt;

&lt;p&gt;You can install the plugin using Rails&amp;#8217; built-in plugin command.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ruby script/plugin install http://john.guen.in/svn/plugins/x_send_file/
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Usage&lt;/h3&gt;

&lt;p&gt;The interface is as close as possible to Rails&amp;#8217; &lt;code&gt;send_file&lt;/code&gt; command.  If your server requires it, you can override the HTTP header used for X-Sendfile with the new &lt;code&gt;:header&lt;/code&gt; option (the default is &lt;code&gt;X-Sendfile&lt;/code&gt;).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;x_send_file('/path/to/file')
x_send_file('/path/to/image.jpg', :type =&amp;gt; 'image/jpeg', :disposition =&amp;gt; 'inline')
x_send_file('/path/to/file/', :header =&amp;gt; 'X-LIGHTTPD-SEND-FILE')
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you want &lt;code&gt;x_send_file&lt;/code&gt; jump in and take over any time &lt;code&gt;send_file&lt;/code&gt; is used,
add this to your environment.rb:&lt;/p&gt;

&lt;p class="note"&gt;That ! stands for &amp;#8220;danger!&amp;#8221;  Use this method responsibly.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;XSendFile::Plugin.replace_send_file!
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;More information&lt;/h2&gt;

&lt;p&gt;If you&amp;#8217;re ready to dig further, check out these resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="/rdoc/x_send_file/"&gt;rdoc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &lt;a href="/svn/plugins/x_send_file"&gt;source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;RoR wiki&amp;#8217;s &lt;a href="http://wiki.rubyonrails.org/rails/pages/HowtoSendFilesFast"&gt;How To Send Files Fast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Apache&amp;#8217;s &lt;a href="http://celebnamer.celebworld.ws/stuff/mod_xsendfile/"&gt;mod_xsendfile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Lighttpd&amp;#8217;s &lt;a href="http://blog.lighttpd.net/articles/2006/07/02/x-sendfile"&gt;mod_fastcgi&lt;/a&gt; and &lt;a href="http://blog.lighttpd.net/articles/2006/07/22/mod_proxy_core-got-x-sendfile-support"&gt;mod_proxy_core&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category domain="http://john.guen.in/past/tags/plugin">plugin</category>
      <category domain="http://john.guen.in/past/tags/rails">rails</category>
      <category domain="http://john.guen.in/past/tags/xsendfile">xsendfile</category>
    </item>
    <item>
      <title>So your subversion server is full...</title>
      <link>http://john.guen.in/past/2007/4/9/so_your_subversion_server_is/</link>
      <pubDate>Sun, 08 Apr 2007 22:47:00 GMT</pubDate>
      <guid>http://john.guen.in/past/2007/4/9/so_your_subversion_server_is/</guid>
      <description>&lt;p&gt;Once you have your fancy new server up &amp;amp; running, you have to prep your svn repository:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;svnadmin create /path/to/new/repos
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once that&amp;#8217;s done, you just need to send the data over from your old repository.  Run this command on your old server:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;svnadmin dump /path/to/old/repos | ssh user@newserver "svnadmin load /path/to/new/repos"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Hey, you&amp;#8217;re done!  Isn&amp;#8217;t the understated elegance of Unix grand?&lt;/p&gt;</description>
      <category domain="http://john.guen.in/past/tags/subversion">subversion</category>
      <category domain="http://john.guen.in/past/tags/unix">unix</category>
    </item>
    <item>
      <title>Hello World</title>
      <link>http://john.guen.in/past/2007/4/9/hello_world/</link>
      <pubDate>Sun, 08 Apr 2007 22:13:00 GMT</pubDate>
      <guid>http://john.guen.in/past/2007/4/9/hello_world/</guid>
      <description>&lt;div&gt;&lt;img src="/images/posts/daphne.jpg" alt="My cat Daphne" class="small" /&gt;&lt;/div&gt;

&lt;p&gt;I plan on using this blog to record my musings about Ruby on Rails, humane web interfaces, and other interesting topics regarding the webotubosphere.  Hopefully, I&amp;#8217;ll even write a tutorial or two.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ll do my best to stay on topic and avoid writing about my cats or how my taste in music is better than yours.  Aside from that giant, ego-stroking masthead with my name, I&amp;#8217;ll try to keep it in the first person whenever practical.&lt;/p&gt;

&lt;p&gt;This blog is powered by &lt;a href="http://www.simplelog.net/"&gt;Simple Log&lt;/a&gt; with a little help from &lt;a href="http://www.google.com/search?q=haml"&gt;Haml &amp;amp; Sass&lt;/a&gt;.  It&amp;#8217;s about 80% done.  I&amp;#8217;m going to run with it and work out that last annoying 20% (print style sheet, search, actually look at it in IE 6&amp;#8230;) as those issues present themselves.&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;ve got something to share, feel free to hit the &amp;#8220;contact&amp;#8221; link at the bottom of the page at any time.  Better yet, add a comment and let everyone join in the fun.&lt;/p&gt;

&lt;p&gt;Happy coding.&lt;/p&gt;</description>
      <category domain="http://john.guen.in/past/tags/meta">meta</category>
    </item>
  </channel>
</rss>
