Files | Admin

Notes:

Release Name: 0.9.0

Notes:
Rack HTTP server for Unix, fast clients and nothing else

unicorn 0.9.0

We now have support for "Transfer-Encoding: chunked" bodies in
requests.  Not only that, Rack applications reading input bodies
get that data streamed off to the client socket on an as-needed
basis.  This allows the application to do things like upload
progress notification and even tunneling of arbitrary stream
protocols via bidirectional chunked encoding.

See Unicorn::App::Inetd and examples/git.ru (including the
comments) for an example of tunneling the git:// protocol over
HTTP.

This release also gives applications the ability to respond
positively to "Expect: 100-continue" headers before being rerun
without closing the socket connection.  See Unicorn::App::Inetd
for an example of how this is used.

This release is NOT recommended for production use.

Eric Wong (43):
      http_request: no need to reset the request
      http_request: StringIO is binary for empty bodies (1.9)
      http_request: fix typo for 1.9
      Transfer-Encoding: chunked streaming input support
      Unicorn::App::Inetd: reinventing Unix, poorly :)
      README: update with mailing list info
      local.mk.sample: publish_doc gzips all html, js, css
      Put copyright text in new files, include GPL2 text
      examples/cat-chunk-proxy: link to proposed curl(1) patch
      Update TODO
      Avoid duplicating the "Z" constant
      Optimize body-less GET/HEAD requests (again)
      tee_input: Don't expose the @rd object as a return value
      exec_cgi: small cleanups
      README: another note about older Sinatra
      tee_input: avoid defining a @rd.size method
      Make TeeInput easier to use
      test_upload: add tests for chunked encoding
      GNUmakefile: more stringent error checking in tests
      test_upload: fix ECONNRESET with 1.9
      GNUmakefile: allow TRACER= to be specified for tests
      test_rails: workaround long-standing 1.9 bug
      tee_input: avoid rereading fresh data
      "Fix" tests that break with stream_input=false
      inetd: fix broken constant references
      configurator: provide stream_input (true|false) option
      chunked_reader: simpler interface
      http_request: force BUFFER to be Encoding::BINARY
      ACK clients on "Expect: 100-continue" header
      Only send "100 Continue" when no body has been sent
      http_request: tighter Transfer-Encoding: "chunked" check
      Add trailer_parser for parsing trailers
      chunked_reader: Add test for chunk parse failure
      TeeInput: use only one IO for tempfile
      trailer_parser: set keys with "HTTP_" prefix
      TrailerParser integration into ChunkedReader
      Unbind listeners as before stopping workers
      Retry listen() on EADDRINUSE 5 times ever 500ms
      Re-add support for non-portable socket options
      Move "Expect: 100-continue" handling to the app
      tee_input: avoid ignoring initial body blob
      Force streaming input onto apps by default
      unicorn 0.9.0



Changes: commit b67ff587730abfd4e1f78c448ef128315fbf786d Author: Eric Wong <normalperson@yhbt.net> Date: Wed Jul 1 14:15:34 2009 -0700 unicorn 0.9.0 commit 90c0e4666185f29d3484c12ea6d451fcac528376 Author: Eric Wong <normalperson@yhbt.net> Date: Wed Jul 1 15:16:49 2009 -0700 Remove cat-chunk-proxy, curl CVS supports non-blocking stdin Now that upstream curl supports this functionality, there's no reason to duplicate it here as an example. commit 06bf73975864b8e16ef1ee977f8424a0e5517fd6 Author: Eric Wong <normalperson@yhbt.net> Date: Wed Jul 1 13:59:40 2009 -0700 Force streaming input onto apps by default This change gives applications full control to deny clients from uploading unwanted message bodies. This also paves the way for doing things like upload progress notification within applications in a Rack::Lint-compatible manner. Since we don't support HTTP keepalive, so we have more freedom here by being able to close TCP connections and deny clients the ability to write to us (and thus wasting our bandwidth). While I could've left this feature off by default indefinitely for maximum backwards compatibility (for arguably broken applications), Unicorn is not and has never been about supporting the lowest common denominator. commit ec5d374768ced6aba3fed8a9481d2ac3c07cdb98 Author: Eric Wong <normalperson@yhbt.net> Date: Wed Jul 1 13:49:29 2009 -0700 tee_input: avoid ignoring initial body blob This was causing the first part of the body to be missing when an HTTP client failed to delay between sending the header and body in the request. commit ec14a20474575e77a23b713ee8fcda1e71b1d018 Author: Eric Wong <normalperson@yhbt.net> Date: Wed Jul 1 13:32:33 2009 -0700 Move "Expect: 100-continue" handling to the app This gives the app ability to deny clients with 417 instead of blindly making the decision for the underlying application. Of course, apps must be made aware of this. commit 563d03f649ef31d2aec3505cbbed1e015493b8fc Author: Eric Wong <normalperson@yhbt.net> Date: Tue Jun 30 19:16:43 2009 -0700 Re-add support for non-portable socket options Now that we support tunnelling arbitrary protocols over HTTP as well as "100 Continue" responses, TCP_NODELAY actually becomes useful to us. TCP_NODELAY is actually reasonably portable nowadays; even. While we're adding non-portable options, TCP_CORK/TCP_NOPUSH can be enabled, too. Unlike some other servers, these can't be disabled explicitly/intelligently to force a flush, however. However, these may still improve performance with "normal" HTTP applications (Mongrel has always had TCP_CORK enabled in Linux). While we're adding OS-specific features, we might as well support TCP_DEFER_ACCEPT in Linux and FreeBSD the "httpready" accept filter to prevent abuse. These options can all be enabled on a per-listener basis. commit d247b5d95a3ad2de65cc909db21fdfbc6194b4c9 Author: Eric Wong <normalperson@yhbt.net> Date: Tue Jun 30 17:47:55 2009 -0700 Retry listen() on EADDRINUSE 5 times ever 500ms This number of retries and delay taken directly from nginx commit 8c2040127770e40e344a927ddc187bf801073e33 Author: Eric Wong <normalperson@yhbt.net> Date: Tue Jun 30 17:33:15 2009 -0700 Unbind listeners as before stopping workers This allows another process to take our listeners sooner rather than later. commit 20bf660a3efff9229c81b3b3a0feb6844bc27a7c Author: Eric Wong <normalperson@yhbt.net> Date: Tue Jun 30 17:15:56 2009 -0700 TrailerParser integration into ChunkedReader Support for the "Trailer:" header and associated Trailer lines should be reasonably well supported now commit f01c1d4071e8ce30aa6806fd3cd8eec7491bf06c Author: Eric Wong <normalperson@yhbt.net> Date: Tue Jun 30 17:15:34 2009 -0700 trailer_parser: set keys with "HTTP_" prefix commit 8f648549d57df3d1b9796c70d2e11ba6ffb19486 Author: Eric Wong <normalperson@yhbt.net> Date: Tue Jun 30 17:11:31 2009 -0700 TeeInput: use only one IO for tempfile We can actually just use one IO and file descriptor here and simplify the code while we're at it. commit 2d3f12f0ca25ddfdec5b7d92f76489dcc1f26cf7 Author: Eric Wong <normalperson@yhbt.net> Date: Tue Jun 30 14:15:57 2009 -0700 chunked_reader: Add test for chunk parse failure I'd honestly be more comfortable doing this in C (and possibly adapting the code from the libcurl internals since that code has been very well-tested). commit 608e6243a2b15bfc28c3524ed45d5fc7598e8565 Author: Eric Wong <normalperson@yhbt.net> Date: Tue Jun 30 13:47:41 2009 -0700 Add trailer_parser for parsing trailers Eventually this (and ChunkedReader) may be done in C/Ragel along with the existing HttpParser. commit 86cd3fec9a02352d10b53bac02f98267d2b77bdd Author: Eric Wong <normalperson@yhbt.net> Date: Mon Jun 29 22:27:44 2009 -0700 http_request: tighter Transfer-Encoding: "chunked" check Don't allow misbehaving clients to mispell "chunked" commit 7e36e29a69c4adb777e82a91a381bd680967c055 Author: Eric Wong <normalperson@yhbt.net> Date: Mon Jun 29 21:24:59 2009 -0700 Only send "100 Continue" when no body has been sent Under slow/inconsistent network conditions or overly aggressive clients, there is a possibility we could've already started reading the body. In those cases, don't bother responding to the expectation to continue since the client has already started sending a message body. commit 516c4a8686911a3b6c5e1837d183cd6f515e877c Author: Eric Wong <normalperson@yhbt.net> Date: Mon Jun 29 19:21:34 2009 -0700 ACK clients on "Expect: 100-continue" header By responding with a "HTTP/1.1 100 Continue" response to encourage a client to send the rest of the body. This is part of the HTTP/1.1 standard but not often implemented by servers: http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3 This will speed up curl uploads since curl sleeps up to 1 second if no response is received: http://curl.haxx.se/docs/faq.html#My_HTTP_POST_or_PUT_requests_are commit ec3ac2e4291026a3ebf687d7d0c45c34acac111e Author: Eric Wong <normalperson@yhbt.net> Date: Mon Jun 29 18:21:52 2009 -0700 http_request: force BUFFER to be Encoding::BINARY Not sure why this hasn't been an issue yet, but better safe than sorry with data integrity... commit 41f6f65a6cb7152b5181704373d7da62704a62e8 Author: Eric Wong <normalperson@yhbt.net> Date: Mon Jun 29 18:01:41 2009 -0700 chunked_reader: simpler interface This won't be heavily used enough to make preallocation worth the effort. While we're at it, don't enforce policy by forcing the readpartial buffer to be Encoding::BINARY (even though it /should/ be :), it's up to the user of the interface to decide. commit 4f05fb1a3b44f8eab1a9dda26d5b115f33a149cd Author: Eric Wong <normalperson@yhbt.net> Date: Mon Jun 29 05:27:18 2009 -0700 configurator: provide stream_input (true|false) option The default is false because some applications were not written to handle partial reads (even though IO#read allows it, not just IO#readpartial). commit 1e10654f81e74c4d11ab538b16dcc1b7bd36cb7f Author: Eric Wong <normalperson@yhbt.net> Date: Mon Jun 29 11:33:02 2009 -0700 inetd: fix broken constant references This has been totally broken since commit b0013b043a15d77d810d5965157766c1af364db2 "Avoid duplicating the "Z" constant" commit 2c53b32bf651966d3eb39850cc6be019eda51df0 Author: Eric Wong <normalperson@yhbt.net> Date: Mon Jun 29 05:11:13 2009 -0700 "Fix" tests that break with stream_input=false commit 0d3aa1eb6bc7646c9bde78b0fae4e34bc5876421 Author: Eric Wong <normalperson@yhbt.net> Date: Mon Jun 29 04:58:21 2009 -0700 tee_input: avoid rereading fresh data Oops! commit cfed47020a39291504877ce2a3463ed268fed9c8 Author: Eric Wong <normalperson@yhbt.net> Date: Mon Jun 29 03:59:00 2009 -0700 test_rails: workaround long-standing 1.9 bug Now that I've beefed out my Makefile to detect errors, I've noticed this test has been failing under 1.9 for a while now. Currently no released version of Rack(1.0) or Rails(2.3.2.1) supports this. commit 0127374ed2e4028ca8e164c2cfba357b53960a10 Author: Eric Wong <normalperson@yhbt.net> Date: Mon Jun 29 03:06:56 2009 -0700 GNUmakefile: allow TRACER= to be specified for tests This can allow you to run make with: TRACER='strace -f -o $(t).strace -s 100000' to debug a test failure (it should be usable with truss, ltrace, and other similar tools). commit 93f55bb8802866e8f9a2d741ecec6a75973f2c72 Author: Eric Wong <normalperson@yhbt.net> Date: Mon Jun 29 03:03:35 2009 -0700 test_upload: fix ECONNRESET with 1.9 This has been broken since 6945342a1f0a4caaa918f2b0b1efef88824439e0 "Transfer-Encoding: chunked streaming input support" but somehow never caught by me or anyone else. commit d7b3fb8053315c2ecf4d66199b028df5070e1ab8 Author: Eric Wong <normalperson@yhbt.net> Date: Mon Jun 29 02:39:04 2009 -0700 GNUmakefile: more stringent error checking in tests commit 7cbdf6ba4c3463dfc1cac5cb01d4241c02be7fde Author: Eric Wong <normalperson@yhbt.net> Date: Sat Jun 27 16:00:02 2009 -0700 test_upload: add tests for chunked encoding Additionally, provide verifications for sizes after-the-fact to avoid slamming all of our input into the server. commit 14ce889cc12628405b0f6a1842b7e1ad09ca4b7b Author: Eric Wong <normalperson@yhbt.net> Date: Sat Jun 27 15:58:45 2009 -0700 Make TeeInput easier to use The complexity of making the object persistent isn't worth the potential performance gain here. commit 665717d9d339748447e26d3eb0e34c9f6c64ce73 Author: Eric Wong <normalperson@yhbt.net> Date: Fri Jun 26 15:52:39 2009 -0700 tee_input: avoid defining a @rd.size method We don't ever expose the @rd object to the public so Rack-applications won't ever call size() on it. commit 1f0d2e953af07b5bb904953767ee8c66deea669a Author: Eric Wong <normalperson@yhbt.net> Date: Thu Jun 25 20:25:08 2009 -0700 README: another note about older Sinatra Older Sinatra would blindly try to run Mongrel or Thin at_exit. This causes strange behavior to happen when Unicorn workers are exited. commit 8e030bcd34da6296b1bda95f151c2ac4b777f617 Author: Eric Wong <normalperson@yhbt.net> Date: Thu Jun 25 16:38:13 2009 -0700 exec_cgi: small cleanups * avoid '' strings for GC-friendliness * Ensure the '' we do need is binary for 1.9 * Disable passing the raw rack.input object to the child process This is never possible with our new TeeInput wrapper. commit 1574d8ce531d79fc905be2f319fa703fb0710e96 Author: Eric Wong <normalperson@yhbt.net> Date: Thu Jun 25 16:37:01 2009 -0700 tee_input: Don't expose the @rd object as a return value Pay a performance penalty and always proxy reads through our TeeInput object to ensure nobody closes our internal reader. commit 4651cd8b7c10d18bc745b84ebc7a55aad07d6077 Author: Eric Wong <normalperson@yhbt.net> Date: Wed Jun 10 16:00:08 2009 -0700 Optimize body-less GET/HEAD requests (again) No point in making syscalls to deal with empty bodies. Reinstate usage of the NULL_IO object which allows us to avoid allocating new objects. commit b0013b043a15d77d810d5965157766c1af364db2 Author: Eric Wong <normalperson@yhbt.net> Date: Tue Jun 9 16:22:55 2009 -0700 Avoid duplicating the "Z" constant Trying not to repeat ourselves. Unfortunately, Ruby 1.9 forces us to actually care about encodings of arbitrary byte sequences. commit f3e1cd9b7728b85f346d5588268066c9ef9d3cf3 Author: Eric Wong <normalperson@yhbt.net> Date: Sun Jun 7 13:28:25 2009 -0700 Update TODO commit 67c2b02fdb4a863f1a7934b2c907b6d11c236f75 Author: Eric Wong <normalperson@yhbt.net> Date: Sun Jun 7 03:41:20 2009 -0700 examples/cat-chunk-proxy: link to proposed curl(1) patch Then hopefully soon we'll be able to get rid of this script... commit a834b9fe0f3085f979d7f378d3cb72e0a052d85c Author: Eric Wong <normalperson@yhbt.net> Date: Sat Jun 6 13:53:35 2009 -0700 Put copyright text in new files, include GPL2 text Just clarifying the license terms of the new code. Other files should really have this notice in there as well. commit 7fdf4388a637b687c3996a4e5943db4610ba6f6e Author: Eric Wong <normalperson@yhbt.net> Date: Sat Jun 6 13:41:19 2009 -0700 local.mk.sample: publish_doc gzips all html, js, css While we're at it, use the rsyncable flag with gzip here to reduce bandwidth usage on my end. commit c302b3281b71897f6e2854562e6f77447831e61e Author: Eric Wong <normalperson@yhbt.net> Date: Sat Jun 6 13:14:20 2009 -0700 README: update with mailing list info commit a64913eafbee3501a677b1232470838a4ad0fc65 Author: Eric Wong <normalperson@yhbt.net> Date: Fri Jun 5 22:16:47 2009 -0700 Unicorn::App::Inetd: reinventing Unix, poorly :) This includes an example of tunneling the git protocol inside a TE:chunked HTTP request. The example is unfortunately contrived in that it relies on the custom examples/cat-chunk-proxy.rb script in the client. My initial wish was to have a generic tool like curl(1) operate like this: cat > ~/bin/cat-chunk-proxy.sh <<EOF #!/bin/sh exec curl -sfNT- http://$1:$2/ EOF chmod +x ~/bin/cat-chunk-proxy.sh GIT_PROXY_COMMAND=cat-chunk-proxy.sh git clone git://0:8080/foo Unfortunately, curl will attempt a blocking read on stdin before reading the TCP socket; causing the git-clone consumer to starve. This does not appear to be a problem with the new server code for handling chunked requests. commit 6945342a1f0a4caaa918f2b0b1efef88824439e0 Author: Eric Wong <normalperson@yhbt.net> Date: Fri Jun 5 18:03:46 2009 -0700 Transfer-Encoding: chunked streaming input support This adds support for handling POST/PUT request bodies sent with chunked transfer encodings ("Transfer-Encoding: chunked"). Attention has been paid to ensure that a client cannot OOM us by sending an extremely large chunk. This implementation is pure Ruby as the Ragel-based implementation in rfuzz didn't offer a streaming interface. It should be reasonably close to RFC-compliant but please test it in an attempt to break it. The more interesting part is the ability to stream data to the hosted Rack application as it is being transferred to the server. This can be done regardless if the input is chunked or not, enabling the streaming of POST/PUT bodies can allow the hosted Rack application to process input as it receives it. See examples/echo.ru for an example echo server over HTTP. Enabling streaming also allows Rack applications to support upload progress monitoring previously supported by Mongrel handlers. Since Rack specifies that the input needs to be rewindable, this input is written to a temporary file (a la tee(1)) as it is streamed to the application the first time. Subsequent rewinded reads will read from the temporary file instead of the socket. Streaming input to the application is disabled by default since applications may not necessarily read the entire input body before returning. Since this is a completely new feature we've never seen in any Ruby HTTP application server before, we're taking the safe route by leaving it disabled by default. Enabling this can only be done globally by changing the Unicorn HttpRequest::DEFAULTS hash: Unicorn::HttpRequest::DEFAULTS["unicorn.stream_input"] = true Similarly, a Rack application can check if streaming input is enabled by checking the value of the "unicorn.stream_input" key in the environment hashed passed to it. All of this code has only been lightly tested and test coverage is lacking at the moment. [1] - http://tools.ietf.org/html/rfc2616#section-3.6.1 commit a48695449f49e6900819fed472f23408c62b5501 Author: Eric Wong <normalperson@yhbt.net> Date: Fri Jun 5 00:19:05 2009 -0700 http_request: fix typo for 1.9 commit 4716aab9530cabb14448a5123865b9f79b77f40c Author: Eric Wong <normalperson@yhbt.net> Date: Sat May 30 09:15:50 2009 -0700 http_request: StringIO is binary for empty bodies (1.9) commit 34b916e3c237f32d5455869d2823eccb27e9ff24 Author: Eric Wong <normalperson@yhbt.net> Date: Sat May 30 09:10:29 2009 -0700 http_request: no need to reset the request That method no longer exists, but Ruby would never know until it tried to run it. Yes, I miss my compiled languages.