Date | Commit message (Collapse) |
|
Noticed while hacking on a Zbatery-using application
(cherry picked from commit ac15513bb81a345cd12c67702a81a585b8b0514e)
|
|
"stringio" is part of the Ruby distro and we use it in multiple
places, so avoid re-requiring it.
(cherry picked from commit 0fea004ab093ec4f59d919915a505a136326bd8a)
|
|
Different threads may change $/ during execution, so cache it at
function entry to a local variable for safety. $/ may also be
of a non-binary encoding, so rely on Rack::Utils.bytesize to
portably capture the correct size.
Our string slicing is always safe from 1.9 encoding: both our
socket and backing temporary file are opened in binary mode,
so we'll always be dealing with binary strings in this class
(in accordance to the Rack spec).
(cherry picked from commit 1cd698f8c7938b1f19e9ba091708cb4515187939)
|
|
It makes RDoc look better and cleaner, since we don't
do anything in the Unicorn namespace.
(cherry picked from commit 6f720afd95d8131a2657c643b97cb18c750ed9f8)
|
|
Some folks may require more fine-grained control of buffering
and I/O chunk sizes, so we'll support them (unofficially, for
now).
(cherry picked from commit 9f48be69bfe579dab02b5fe8d6e728ae63fd24fc)
|
|
no need to pass an extra argument
(cherry picked from commit 1a49a8295054a2e931f5288540acb858be8edcc8)
|
|
Rack 1.2 removed the +size+ method requirement, but we'll
still support it since Rack 1.2 doesn't _prohibit_ it, and
Rack 1.[01] applications will continue to exist for a while.
|
|
It's a waste of memory bandwidth to do memcpy() when we know
Unicorn::HttpParser (via rb_str_resize()) will allocate new
memory for the string for us. An empty String is "free",
as we've already paid the Object cost regardless.
|
|
We'll use struct members exclusively from now on instead of
throwing ivars into the mix. This allows us to _unofficially_
support direct access to more members easily. Unofficial
extensions may include the ability to splice(2)/tee(2) for
better performance.
This also makes our object size smaller across all Ruby
implementations as well, too (helps Rainbows! out).
|
|
|
|
We do not hide unforseen exceptions, as that could cause us to
waste precious time attempting to continue processing after
errors.
|
|
First move it to a separate method, this allows subclasses to
reuse our error handler. Additionally, capture HttpParserError
as well since backtraces are worthless when a client sends us
a bad request, too.
|
|
|
|
Leaving the EOFError exception as-is bad because most
applications/frameworks run an application-wide exception
handler to pretty-print and/or log the exception with a huge
backtrace.
Since there's absolutely nothing we can do in the server-side
app to deal with clients prematurely shutting down, having a
backtrace does not make sense. Having a backtrace can even be
harmful since it creates unnecessary noise for application
engineers monitoring or tracking down real bugs.
|
|
It's confusing when a local variable reuses the same name
as a struct member.
|
|
Just let the error bubble all the way up to where Unicorn calls
process_client where it'll be appropriately handled.
Additionally, we'l just check the return value of tee() in
ensure_length and avoid it if it nils on us.
|
|
|
|
Subclass off the core File class so we don't have to
worry about #size being defined. This will mainly
be useful to Rainbows! but allows us to simplify
our TeeInput implementation a little, too.
|
|
Found in Rainbows! testing. Reusing the buffer when finalizing
input for headers could be problematic because it would lead
to the @buf2 instance variable being clobbered; allowing the
trailers to "leak" into the body.
|
|
Under FreeBSD writing to the file in sync mode does not change current
position, so change position to the end of the file. Without this patch
multipart post requests with large data (image uploading) does not work
correctly:
Status: 500 Internal Server Error
bad content body
/usr/local/lib/ruby/gems/1.8/gems/rack-1.0.0/lib/rack/utils.rb:347:in `parse_multipart'
/usr/local/lib/ruby/gems/1.8/gems/rack-1.0.0/lib/rack/utils.rb:319:in `loop'
/usr/local/lib/ruby/gems/1.8/gems/rack-1.0.0/lib/rack/utils.rb:319:in `parse_multipart'
File position behavior under FreeBSD :
ruby -v
ruby 1.8.7 (2009-04-08 patchlevel 160) [i386-freebsd7]
irb(main):001:0> b = File.new("abc", "w+")
=> #<File:abc>
irb(main):002:0> b.sync = true
=> true
irb(main):004:0> b.write("abc")
=> 3
irb(main):005:0> b.pos
=> 0
Acked-by: Eric Wong <normalperson@yhbt.net>
|
|
There are existing applications and libraries that don't check
the return value of env['rack.input'].read(length) (like Rails
:x). Those applications became broken under the IO#readpartial
semantics of TeeInput#read when handling larger request bodies.
We'll preserve the IO#readpartial semantics _only_ when handling
chunked requests (as long as Rack allows it, it's useful for
real-time processing of audio/video streaming uploads,
especially with Rainbows! and mobile clients) but use
read-in-full semantics for TeeInput#read on requests with a
known Content-Length.
|
|
We've started using magic comments to ensure any strings we
create are binary instead. Additionally, ensure we create any
StringIO objects with an explicit string (which default to
binary) to ensure the StringIO object is binary. This is
because StringIO.new (with no arguments) will always use the
process-wide default encoding since it does not know about
magic comments (and couldn't, really...)
|
|
This ensures any string literals that pop up in *our* code will
just be a bag of bytes. This shouldn't affect/fix/break
existing apps in most cases, but most constants will always have
the "correct" encoding (none!) to be consistent with HTTP/socket
expectations. Since this comment affects things only on a
per-source basis, it won't affect existing apps with the
exception of strings we pass to the Rack application.
This will eventually allow us to get rid of that Unicorn::Z
constant, too.
|
|
the docs for the TeeInput class was clobbering the Unicorn
module documentation instead.
|
|
TeeInput being needed is now (once again) an uncommon code path
so there's no point in relying on global constants. While we're
at it, allow StringIO to be used in the presence of small
inputs; too.
|
|
This method is strictly a filter, it does no I/O so "read"
is not an appropriate name to give it.
|
|
This should be more robust, faster and easier to deal
with than the ugly proof-of-concept regexp-based ones.
|
|
With the 1.9.2preview1 release (and presumably 1.9.1 p243), the
Ruby core team has decided that bending over backwards to
support crippled operating/file systems was necessary and that
files must be closed before unlinking.
Regardless, this is more efficient than using Tempfile because:
1) no delegation is necessary, this is a real File object
2) no mkdir is necessary for locking, we can trust O_EXCL
to work properly without unnecessary FS activity
3) no finalizer is needed to unlink the file, we unlink
it as soon as possible after creation.
|
|
This simplifies chunked_reader substantially with a slight
increase in tee_input complexity. This is beneficial because
chunked_reader is more complex to begin with and more likely
to experience correctness issues.
|
|
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.
|
|
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.
|
|
We can actually just use one IO and file descriptor here and
simplify the code while we're at it.
|
|
Oops!
|
|
The complexity of making the object persistent isn't worth the
potential performance gain here.
|
|
We don't ever expose the @rd object to the public so
Rack-applications won't ever call size() on it.
|
|
Pay a performance penalty and always proxy reads through our
TeeInput object to ensure nobody closes our internal reader.
|
|
Trying not to repeat ourselves. Unfortunately, Ruby 1.9 forces
us to actually care about encodings of arbitrary byte sequences.
|
|
Just clarifying the license terms of the new code. Other files
should really have this notice in there as well.
|
|
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
|