* 'Connection reset by peer' when replying before the end of POST data @ 2012-02-28 22:15 Lunar 2012-02-28 23:39 ` Eric Wong 0 siblings, 1 reply; 9+ messages in thread From: Lunar @ 2012-02-28 22:15 UTC (permalink / raw) To: rainbows-talk-GrnCvJ7WPxnNLxjTenLetw Hi! Short introduction: I am working on a simple "one-click" file sharing web application specific focus on protecting users' privacy [1]. Thanks to Rainbows! it can work with big uploads without any request buffering which is simply marvelous! :) I am currently trying to implement a limit on the maximum uploaded file size, not unlike what is already done by Rainbows::MaxBody. Unfortunately, it looks like answering a request while the client is in the middle of posting data is not supported that well by Rainbows! Here is a minimal test case: --- 8< --- config.ru --------------------------------------------------- class InterruptTest def call(env) # HTTP 1.1 standard (and curl) needs this /\A100-continue\z/i =~ env['HTTP_EXPECT'] and return [ 100, {}, [] ] error = "Request entity too large!\n" env['rack.input'].read 1000 Rainbows.sleep 1 [ 403, { 'Content-Type' => 'text/plain' }, [ error ] ] end end run InterruptTest.new --- >8 ----------------------------------------------------------------- --- 8< --- rainbows.conf ----------------------------------------------- Rainbows! do use :ThreadSpawn rewindable_input false client_max_body_size nil end --- >8 ----------------------------------------------------------------- I am starting Rainbows! with the following command-line: $ rainbows -E none -p 8081 -c rainbows.conf rackup.ru And then, when asking curl (the `test` file is 7636 bytes long): $ curl -v -F "file=@test;type=text/plain" http://localhost:8081 * About to connect() to localhost port 8081 (#0) * Trying 127.0.0.1... connected * Connected to localhost (127.0.0.1) port 8081 (#0) > POST / HTTP/1.1 > User-Agent: curl/7.21.0 (i486-pc-linux-gnu) libcurl/7.21.0 > OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.15 libssh2/1.2.6 > Host: localhost:8081 > Accept: */* > Content-Length: 7829 > Expect: 100-continue > Content-Type: multipart/form-data; > boundary=----------------------------cd790f73307f > < HTTP/1.1 100 Continue < HTTP/1.1 403 Forbidden < Date: Tue, 28 Feb 2012 21:20:15 GMT < Status: 403 Forbidden < Connection: close < Content-Type: text/plain < Request entity too large! * Recv failure: Connection reset by peer * Closing connection #0 curl: (56) Recv failure: Connection reset by peer This "connection reset by peer" is annoying as it will result in Apache stating "Bad gateway", or Firefox displaying "The connection was reset". I believe Rainbows::MaxBody having the same issue, but I am not sure. Also looking at the code, it looks like Rainbows::MaxBody trust the Content-Length header and do not mesure the actual amount of bytes received if the header is present. I believe Content-Length can be faked by malicious clients, so it might be better to use limit_input! for every connections. In any cases, I would very much like to solve this issue, but I feel a little bit lost on where to start. My assumption was that other webservers were doing it right, otherwise no one would ever see a 413 Request Entity Too Large message in a browser. I see that Nginx has options related to SO_LINGER and that Apache also mention "Lingering Close" when discussing how to close connections. But I don't really know where to poke on Rainbows! to play with these kinds of options. Anyway, this issue looks closeloy like the one described in section 8 of <http://ftp.ics.uci.edu/pub/ietf/http/draft-ietf-http-connection-00.txt>. Thanks again for any help solving this. :) [1] You can have a look at <https://git.codecoop.org/projects/coquelicot>, but there is not that much to see yet. The code using Rainbows! is not yet in a releasable state, but progress is steady, so expect some news later. :) [2] <https://httpd.apache.org/docs/2.2/misc/perf-tuning.html> Cheers, -- Lunar _______________________________________________ Rainbows! mailing list - rainbows-talk-GrnCvJ7WPxnNLxjTenLetw@public.gmane.org http://rubyforge.org/mailman/listinfo/rainbows-talk Do not quote signatures (like this one) or top post when replying ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: 'Connection reset by peer' when replying before the end of POST data 2012-02-28 22:15 'Connection reset by peer' when replying before the end of POST data Lunar @ 2012-02-28 23:39 ` Eric Wong [not found] ` <20120228233919.GA10168-yBiyF41qdooeIZ0/mPfg9Q@public.gmane.org> 0 siblings, 1 reply; 9+ messages in thread From: Eric Wong @ 2012-02-28 23:39 UTC (permalink / raw) To: Rainbows! list Lunar <lunar@anargeek.net> wrote: > Hi! > > Short introduction: I am working on a simple "one-click" file > sharing web application specific focus on protecting users' privacy [1]. > Thanks to Rainbows! it can work with big uploads without any request > buffering which is simply marvelous! :) Good to know, I also handle a lot of uploads (via PUT, though) > I am currently trying to implement a limit on the maximum uploaded file > size, not unlike what is already done by Rainbows::MaxBody. > Unfortunately, it looks like answering a request while the client is in > the middle of posting data is not supported that well by Rainbows! Rainbows! really can't be "nice" to clients that try to abuse it. > Here is a minimal test case: > > --- 8< --- config.ru --------------------------------------------------- > > class InterruptTest > def call(env) > # HTTP 1.1 standard (and curl) needs this If you get a Content-Length, you can return something other than 100 if Content-Length is too much. > /\A100-continue\z/i =~ env['HTTP_EXPECT'] and return [ 100, {}, [] ] > error = "Request entity too large!\n" > env['rack.input'].read 1000 You can also drain the socket to avoid connection resets: input = env['rack.input'] buf = "" # reuse buf to reduce GC pressure while input.read(1024, buf) # ignore buf, keep reading until nil end > Rainbows.sleep 1 > [ 403, { 'Content-Type' => 'text/plain' }, [ error ] ] > end > end > > run InterruptTest.new > > --- >8 ----------------------------------------------------------------- > > --- 8< --- rainbows.conf ----------------------------------------------- > > Rainbows! do > use :ThreadSpawn > rewindable_input false > client_max_body_size nil > end > > --- >8 ----------------------------------------------------------------- > > I am starting Rainbows! with the following command-line: > > $ rainbows -E none -p 8081 -c rainbows.conf rackup.ru > > And then, when asking curl (the `test` file is 7636 bytes long): > > $ curl -v -F "file=@test;type=text/plain" http://localhost:8081 > * About to connect() to localhost port 8081 (#0) > * Trying 127.0.0.1... connected > * Connected to localhost (127.0.0.1) port 8081 (#0) > > POST / HTTP/1.1 > > User-Agent: curl/7.21.0 (i486-pc-linux-gnu) libcurl/7.21.0 > > OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.15 libssh2/1.2.6 > > Host: localhost:8081 > > Accept: */* > > Content-Length: 7829 > > Expect: 100-continue > > Content-Type: multipart/form-data; > > boundary=----------------------------cd790f73307f > > > < HTTP/1.1 100 Continue > < HTTP/1.1 403 Forbidden > < Date: Tue, 28 Feb 2012 21:20:15 GMT > < Status: 403 Forbidden > < Connection: close > < Content-Type: text/plain > < > Request entity too large! > * Recv failure: Connection reset by peer > * Closing connection #0 > curl: (56) Recv failure: Connection reset by peer > > This "connection reset by peer" is annoying as it will result in Apache > stating "Bad gateway", or Firefox displaying "The connection was reset". > I believe Rainbows::MaxBody having the same issue, but I am not sure. Yes MaxBody does have this issue. It's better to save bandwidth than show a nice error message if somebody is trying to attack you. But you can implement the socket draining example above to get the nice error message. > Also looking at the code, it looks like Rainbows::MaxBody trust the > Content-Length header and do not mesure the actual amount of bytes > received if the header is present. I believe Content-Length can be faked > by malicious clients, so it might be better to use limit_input! for > every connections. It only uses Content-Length as a hint. Unicorn::StreamInput (the env["rack.input"] object) won't read _past_ Content-Length so HTTP pipelining can be used with uploads. If it reads too little, then it'll just timeout eventually. > In any cases, I would very much like to solve this issue, but I feel a > little bit lost on where to start. > > My assumption was that other webservers were doing it right, otherwise > no one would ever see a 413 Request Entity Too Large message in a > browser. They probably drain the socket or wait a bit before closing the connection. Rack doesn't give developers much control over how the socket is managed. > I see that Nginx has options related to SO_LINGER and that > Apache also mention "Lingering Close" when discussing how to close > connections. But I don't really know where to poke on Rainbows! to play > with these kinds of options. Anyway, this issue looks closeloy like the > one described in section 8 of > <http://ftp.ics.uci.edu/pub/ietf/http/draft-ietf-http-connection-00.txt>. Also, neither Matz Ruby 1.8 nor 1.9 can do lingering close as IO#close still holds onto the GVL (blocking all clients). I tried to make close(2) release the GVL for 1.9.3, but it doesn't interact well if another thread was operating on that IO object. > Thanks again for any help solving this. :) > > [1] You can have a look at > <https://git.codecoop.org/projects/coquelicot>, but there is not > that much to see yet. The code using Rainbows! is not yet in a > releasable state, but progress is steady, so expect some news > later. :) Cool (especially that you host your own), I don't see an obvious way to clone your repo and look at it, though :x _______________________________________________ Rainbows! mailing list - rainbows-talk@rubyforge.org http://rubyforge.org/mailman/listinfo/rainbows-talk Do not quote signatures (like this one) or top post when replying ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <20120228233919.GA10168-yBiyF41qdooeIZ0/mPfg9Q@public.gmane.org>]
* Re: 'Connection reset by peer' when replying before the end of POST data [not found] ` <20120228233919.GA10168-yBiyF41qdooeIZ0/mPfg9Q@public.gmane.org> @ 2012-02-29 7:22 ` Lunar 2012-02-29 17:23 ` Eric Wong 0 siblings, 1 reply; 9+ messages in thread From: Lunar @ 2012-02-29 7:22 UTC (permalink / raw) To: Rainbows! list Hi Eric, Thanks for your quick answer! Eric Wong wrote: > Lunar <lunar-L8VBg9NU5dbk1uMJSBkQmQ@public.gmane.org> wrote: > > I am currently trying to implement a limit on the maximum uploaded file > > size, not unlike what is already done by Rainbows::MaxBody. > > Unfortunately, it looks like answering a request while the client is in > > the middle of posting data is not supported that well by Rainbows! > [...] > > You can also drain the socket to avoid connection resets: > > input = env['rack.input'] > buf = "" # reuse buf to reduce GC pressure > while input.read(1024, buf) > # ignore buf, keep reading until nil > end I thought about it, but I would rather not do that. Coquelicot is meant as a small, self-contained application that can also be run at home behind broadband connections with small bandwidth or quota. If users set a file limit of 5 MiB, I would rather not drain the whole 700 MiB before denying the request. > > In any cases, I would very much like to solve this issue, but I feel a > > little bit lost on where to start. > > > > My assumption was that other webservers were doing it right, otherwise > > no one would ever see a 413 Request Entity Too Large message in a > > browser. > > They probably drain the socket or wait a bit before closing the > connection. Rack doesn't give developers much control over how the > socket is managed. Quoting the "HTTP Connection Management" document [1] which I mentioned previously: "Servers must therefore close each half of the connection independently." After digging some more at Nginx, it looks like Nginx is doing exactly that. I also looked at Apache and the code responsible for half-closing both side of the connection is very readable. Function is called `ap_lingering_close()` in server/connection.c. It looks like there is no way to call shutdown(2) in Ruby 1.8.7, but from the documentation, Ruby 1.9.3 has IO#close_read and IO#close_write method that will call shutdown(2) for each half of a socket. I don't have Ruby 1.9.3 right now, but I can try to produce a test case later demonstrating the differences between calling `@io.close` and `@io.close_write; @io.close`. In any case, I think it would worth to try to add such call sequences in Rainbows! and see if it helps. If you can't give it a shot yourself, could you point me to the relevant part of the code? [1] <http://ftp.ics.uci.edu/pub/ietf/http/draft-ietf-http-connection-00.txt> > Also, neither Matz Ruby 1.8 nor 1.9 can do lingering close as IO#close > still holds onto the GVL (blocking all clients). > > I tried to make close(2) release the GVL for 1.9.3, but it doesn't > interact well if another thread was operating on that IO object. I am not that versed in Ruby internal, but I fail to see how this could be related to first closing the clients write side of the connection. There should be a window between IO#close_write and IO#close in which in GVL does not matter, does it? > > [1] You can have a look at > > <https://git.codecoop.org/projects/coquelicot>, but there is not > > that much to see yet. The code using Rainbows! is not yet in a > > releasable state, but progress is steady, so expect some news > > later. :) > > Cool (especially that you host your own), I don't see an obvious way to > clone your repo and look at it, though :x I will keep the list in touch when interesting meat is available. In the meantime, you should be able to `git://git.codecoop.org/coquelicot.git` (maybe in a few hours, it looks the public access got lost at some point). Cheers, -- Lunar _______________________________________________ Rainbows! mailing list - rainbows-talk-GrnCvJ7WPxnNLxjTenLetw@public.gmane.org http://rubyforge.org/mailman/listinfo/rainbows-talk Do not quote signatures (like this one) or top post when replying ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: 'Connection reset by peer' when replying before the end of POST data 2012-02-29 7:22 ` Lunar @ 2012-02-29 17:23 ` Eric Wong [not found] ` <20120229172315.GA26630-yBiyF41qdooeIZ0/mPfg9Q@public.gmane.org> 0 siblings, 1 reply; 9+ messages in thread From: Eric Wong @ 2012-02-29 17:23 UTC (permalink / raw) To: Rainbows! list Lunar <lunar@anargeek.net> wrote: > Quoting the "HTTP Connection Management" document [1] which I mentioned > previously: "Servers must therefore close each half of the connection > independently." > > After digging some more at Nginx, it looks like Nginx is doing exactly > that. I also looked at Apache and the code responsible for half-closing > both side of the connection is very readable. Function is called > `ap_lingering_close()` in server/connection.c. It's very expensive to do what Apache does with threads+Rainbows!. It also appears that Apache and nginx continues to completely drain the socket if the client is sending, too (which is your case). I don't know if there's a way around draining the socket entirely to avoid connection resets in the client :< I'm more interested in keeping good clients going and not wasting server resources dealing with clients I don't want in the first place. > It looks like there is no way to call shutdown(2) in Ruby 1.8.7, but > from the documentation, Ruby 1.9.3 has IO#close_read and IO#close_write > method that will call shutdown(2) for each half of a socket. There's a shutdown method in BasicSocket for 1.8 > In any case, I think it would worth to try to add such call sequences in > Rainbows! and see if it helps. If you can't give it a shot yourself, > could you point me to the relevant part of the code? You could emulate lingering close with something like this: (valid for ThreadSpawn/ThreadPool, not EM/Cool.io stuff) diff --git a/lib/rainbows/client.rb b/lib/rainbows/client.rb index b456eca..9d8256a 100644 --- a/lib/rainbows/client.rb +++ b/lib/rainbows/client.rb @@ -6,4 +6,16 @@ class Rainbows::Client < Kgio::Socket include Rainbows::ProcessClient alias write kgio_write + + def close + close_write + buf = "" + begin + kgio_wait_readable(2) + buf = kgio_tryread(512, buf) + rescue + break + end while buf + super + end end I'm not going to apply that to Rainbows!, it's needless overhead/complexity for dealing with clients I want to reject anyways (and you're still draining the client socket). > [1] <http://ftp.ics.uci.edu/pub/ietf/http/draft-ietf-http-connection-00.txt> > > > Also, neither Matz Ruby 1.8 nor 1.9 can do lingering close as IO#close > > still holds onto the GVL (blocking all clients). > > > > I tried to make close(2) release the GVL for 1.9.3, but it doesn't > > interact well if another thread was operating on that IO object. > > I am not that versed in Ruby internal, but I fail to see how this could > be related to first closing the clients write side of the connection. > There should be a window between IO#close_write and IO#close in which in > GVL does not matter, does it? Having the kernel handle lingering close() should be an "easier" version of the above patch (but I think you still need to drain the input as long as your client is sending). _______________________________________________ Rainbows! mailing list - rainbows-talk@rubyforge.org http://rubyforge.org/mailman/listinfo/rainbows-talk Do not quote signatures (like this one) or top post when replying ^ permalink raw reply related [flat|nested] 9+ messages in thread
[parent not found: <20120229172315.GA26630-yBiyF41qdooeIZ0/mPfg9Q@public.gmane.org>]
* Re: 'Connection reset by peer' when replying before the end of POST data [not found] ` <20120229172315.GA26630-yBiyF41qdooeIZ0/mPfg9Q@public.gmane.org> @ 2012-02-29 20:57 ` Lunar 2012-02-29 21:36 ` Eric Wong 0 siblings, 1 reply; 9+ messages in thread From: Lunar @ 2012-02-29 20:57 UTC (permalink / raw) To: Rainbows! list Eric Wong wrote: > Lunar <lunar@anargeek.net> wrote: > > Quoting the "HTTP Connection Management" document [1] which I mentioned > > previously: "Servers must therefore close each half of the connection > > independently." > > > > After digging some more at Nginx, it looks like Nginx is doing exactly > > that. I also looked at Apache and the code responsible for half-closing > > both side of the connection is very readable. Function is called > > `ap_lingering_close()` in server/connection.c. > > It's very expensive to do what Apache does with threads+Rainbows!. It > also appears that Apache and nginx continues to completely drain the > socket if the client is sending, too (which is your case). > > I don't know if there's a way around draining the socket entirely to > avoid connection resets in the client :< With your proposed patch, everything is working as intended. At least, I can confirm Firefox correctly display the error message sent by the server and not the less understandable "Connection reset by peer". I can also confirm that it does not send the complete file: it looks like it stops sending as soon as either it notices the socket is closed on its write part, or when the response arrives. I am satisfied enough not to dive in libxpcom… > You could emulate lingering close with something like this: > (valid for ThreadSpawn/ThreadPool, not EM/Cool.io stuff) > > diff --git a/lib/rainbows/client.rb b/lib/rainbows/client.rb > index b456eca..9d8256a 100644 > --- a/lib/rainbows/client.rb > +++ b/lib/rainbows/client.rb > @@ -6,4 +6,16 @@ class Rainbows::Client < Kgio::Socket > include Rainbows::ProcessClient > > alias write kgio_write > + > + def close > + close_write > + buf = "" > + begin > + kgio_wait_readable(2) > + buf = kgio_tryread(512, buf) > + rescue > + break > + end while buf > + super > + end > end > > I'm not going to apply that to Rainbows!, it's needless > overhead/complexity for dealing with clients I want to reject > anyways (and you're still draining the client socket). That was exactly what I was looking for. It even works fine on Ruby 1.8.7. I can include that code directly in Coquelicot (by reopening Rainbows::Client to add this extra method) so my pet case is solved. I could see it part of Rainbows!, as optional behaviour, off by default if you'd prefer, but I am fine either way. Thanks for your help! I will let you know as soon as enhanced Coquelicot codebase using Rainbows! is clean enough for a wider exposure (and I have been noticed that the public repository is now back). Cheers, -- Lunar _______________________________________________ Rainbows! mailing list - rainbows-talk@rubyforge.org http://rubyforge.org/mailman/listinfo/rainbows-talk Do not quote signatures (like this one) or top post when replying ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: 'Connection reset by peer' when replying before the end of POST data 2012-02-29 20:57 ` Lunar @ 2012-02-29 21:36 ` Eric Wong [not found] ` <20120229213601.GA7116-yBiyF41qdooeIZ0/mPfg9Q@public.gmane.org> 0 siblings, 1 reply; 9+ messages in thread From: Eric Wong @ 2012-02-29 21:36 UTC (permalink / raw) To: Rainbows! list Lunar <lunar@anargeek.net> wrote: > With your proposed patch, everything is working as intended. At least, I > can confirm Firefox correctly display the error message sent by the > server and not the less understandable "Connection reset by peer". I can > also confirm that it does not send the complete file: it looks like it > stops sending as soon as either it notices the socket is closed on its > write part, or when the response arrives. I am satisfied enough not to > dive in libxpcom… Cool, thanks for confirming. It's good that your client knows to back off. My original patch isn't safe for bad clients that send continously. Below is a safer version of my original patch, can you see if it works? diff --git a/lib/rainbows/client.rb b/lib/rainbows/client.rb index b456eca..1dcb6d4 100644 --- a/lib/rainbows/client.rb +++ b/lib/rainbows/client.rb @@ -6,4 +6,16 @@ class Rainbows::Client < Kgio::Socket include Rainbows::ProcessClient alias write kgio_write + + def close + close_write + kgio_wait_readable(2) + buf = "" + case kgio_tryread(512, buf) + when nil, Symbol + break + end while true + ensure + super + end end > I could see it part of Rainbows!, as optional behaviour, off by default > if you'd prefer, but I am fine either way. I'll probably call it "lingering_close" like nginx calls it. Of course this needs to be supported for EM/Cool.io, too. _______________________________________________ Rainbows! mailing list - rainbows-talk@rubyforge.org http://rubyforge.org/mailman/listinfo/rainbows-talk Do not quote signatures (like this one) or top post when replying ^ permalink raw reply related [flat|nested] 9+ messages in thread
[parent not found: <20120229213601.GA7116-yBiyF41qdooeIZ0/mPfg9Q@public.gmane.org>]
* Re: 'Connection reset by peer' when replying before the end of POST data [not found] ` <20120229213601.GA7116-yBiyF41qdooeIZ0/mPfg9Q@public.gmane.org> @ 2012-03-02 16:03 ` Lunar 2012-03-02 16:29 ` Lunar 0 siblings, 1 reply; 9+ messages in thread From: Lunar @ 2012-03-02 16:03 UTC (permalink / raw) To: Rainbows! list Eric Wong wrote: > Lunar <lunar@anargeek.net> wrote: > > With your proposed patch, everything is working as intended. At least, I > > can confirm Firefox correctly display the error message sent by the > > server and not the less understandable "Connection reset by peer". I can > > also confirm that it does not send the complete file: it looks like it > > stops sending as soon as either it notices the socket is closed on its > > write part, or when the response arrives. I am satisfied enough not to > > dive in libxpcom… > > Cool, thanks for confirming. It's good that your client knows to back > off. Actually, they don't, I was a little too quick to answer. I made some more test, sending a 8.1 MB file over a Wi-Fi connection between two systems. For each test, I created a pcap file by recording the HTTP transmission. curl is 7.21.2-4, and I am using: curl -v -F "file=@test-file.xcf;type=application/x-xcf" \ -F "submit=submit" http://webserver/ epiphany is 2.30.6-1, using WebKit and IIRC, libsoup for its HTTP connections. Iceweasel is version 3.5.16-12. w3m is 0.5.2-10. All coming from Debian Squeeze. Here's what's hapenning for nginx (0.7.67-3+squeeze1) when `client_max_body` is set to `1m`: - curl: 413 displayed, 9.5K - w3m: 413 displayed, 8.8M - iceweasel: 413 displayed, 8.8M - epiphany: 413 displayed, 8.8M For Apache (2.2.16-6+squeeze6), using `LimitRequestBody 1048576`: - curl: 413 displayed, 1.8K - w3m: 413 displayed, 8.8M - iceweasel: 413 displayed, 8.9M - epiphany: 413 displayed, 8.8M So it looks usual HTTP web server and clients will drain all the POST input in order to display the error message. *sigh* Then I set up Rainbows! with the following (running latest gems on Ruby 1.8.7): --- 8< --- rainbows.conf ----------------------------------------------- Rainbows! do use :ThreadSpawn rewindable_input false end --- >8 ----------------------------------------------------------------- --- 8< --- rackup.ru --------------------------------------------------- run lambda do |env| while env['rack.input'].read; end; [ 200, { 'Content-Type' => 'text/plain' }, [ 'OK' ] ] end --- >8 ----------------------------------------------------------------- Same tests with this configuration: - curl: OK displayed, 9.5M - w3m: OK displayed, 9.5M - iceweasel: OK displayed, 9.5M - epiphany: OK displayed, 11M If I add `client_max_body_size 1024 * 1024` in rainbows.conf: - curl: 413 displayed, 1.4K - w3m: 413 displayed, 11K - iceweasel: connection reset by peer, 21K - epiphany: connection terminated unexpectedly, 20K > My original patch isn't safe for bad clients that send continously. > Below is a safer version of my original patch, can you see if it > works? > > diff --git a/lib/rainbows/client.rb b/lib/rainbows/client.rb > index b456eca..1dcb6d4 100644 > --- a/lib/rainbows/client.rb > +++ b/lib/rainbows/client.rb > @@ -6,4 +6,16 @@ class Rainbows::Client < Kgio::Socket > include Rainbows::ProcessClient > > alias write kgio_write > + > + def close > + close_write > + kgio_wait_readable(2) > + buf = "" > + case kgio_tryread(512, buf) > + when nil, Symbol > + break > + end while true > + ensure > + super > + end > end Using this patch (actually, defining Rainbows::Client#close in rackup.ru), I get: - curl: 413 displayed, 1.5K - w3m: 413 displayed, 17K - iceweasel: connection reset by peer, 19K - epiphany: connection terminated unexpectedly, 16K I have tried to come up with something closer to what other webservers do, and it looks like it (but I might have overlooked something): def close close_write buf = "" loop do kgio_wait_readable(2) break unless kgio_tryread(512, buf) end ensure super end Using this, I get the following results: - curl: 413 displayed, 1.4K - w3m: 413 displayed, 8.8M - iceweasel: 413 displayed, 8.8M - epiphany: 413 displayed, 8.8M This whole issue leaves me severely disappointed. It looks like I either have to waste much of my users time (by forcing them to upload the whole file) or leave them clueless if the file is too big (by cutting the connection early, resulting in a "reset by peer message"). What a choice… Hope that helps, -- Lunar _______________________________________________ Rainbows! mailing list - rainbows-talk@rubyforge.org http://rubyforge.org/mailman/listinfo/rainbows-talk Do not quote signatures (like this one) or top post when replying ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: 'Connection reset by peer' when replying before the end of POST data 2012-03-02 16:03 ` Lunar @ 2012-03-02 16:29 ` Lunar 2012-03-02 21:05 ` Eric Wong 0 siblings, 1 reply; 9+ messages in thread From: Lunar @ 2012-03-02 16:29 UTC (permalink / raw) To: Rainbows! list Lunar wrote: > Using this, I get the following results: > > - curl: 413 displayed, 1.4K > - w3m: 413 displayed, 8.8M > - iceweasel: 413 displayed, 8.8M > - epiphany: 413 displayed, 8.8M > > > This whole issue leaves me severely disappointed. It looks like I either > have to waste much of my users time (by forcing them to upload the whole > file) or leave them clueless if the file is too big (by cutting the > connection early, resulting in a "reset by peer message"). What a > choice… Just for the record, reverse proxying this last iteration with Nginx (with "proxy_buffering off;") or Apache (with "SetEnv proxy-sendchunks 1") result in 413 displayed and full transmission of the given file with all clients (curl included). -- Lunar _______________________________________________ Rainbows! mailing list - rainbows-talk@rubyforge.org http://rubyforge.org/mailman/listinfo/rainbows-talk Do not quote signatures (like this one) or top post when replying ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: 'Connection reset by peer' when replying before the end of POST data 2012-03-02 16:29 ` Lunar @ 2012-03-02 21:05 ` Eric Wong 0 siblings, 0 replies; 9+ messages in thread From: Eric Wong @ 2012-03-02 21:05 UTC (permalink / raw) To: Rainbows! list Lunar <lunar@anargeek.net> wrote: > > This whole issue leaves me severely disappointed. It looks like I either > > have to waste much of my users time (by forcing them to upload the whole > > file) or leave them clueless if the file is too big (by cutting the > > connection early, resulting in a "reset by peer message"). What a > > choice… > > Just for the record, reverse proxying this last iteration with Nginx > (with "proxy_buffering off;") or Apache (with > "SetEnv proxy-sendchunks 1") result in 413 displayed and full > transmission of the given file with all clients (curl included). Ouch :( I think using 100-continue is the only halfway-viable choice. Too bad it's: 1) subject to race conditions 2) can't help with chunked transfers 3) not widely-supported (any widespread clients besides curl?) Anyways, thanks for all your testing and reports! _______________________________________________ Rainbows! mailing list - rainbows-talk@rubyforge.org http://rubyforge.org/mailman/listinfo/rainbows-talk Do not quote signatures (like this one) or top post when replying ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2012-03-02 21:39 UTC | newest] Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-02-28 22:15 'Connection reset by peer' when replying before the end of POST data Lunar 2012-02-28 23:39 ` Eric Wong [not found] ` <20120228233919.GA10168-yBiyF41qdooeIZ0/mPfg9Q@public.gmane.org> 2012-02-29 7:22 ` Lunar 2012-02-29 17:23 ` Eric Wong [not found] ` <20120229172315.GA26630-yBiyF41qdooeIZ0/mPfg9Q@public.gmane.org> 2012-02-29 20:57 ` Lunar 2012-02-29 21:36 ` Eric Wong [not found] ` <20120229213601.GA7116-yBiyF41qdooeIZ0/mPfg9Q@public.gmane.org> 2012-03-02 16:03 ` Lunar 2012-03-02 16:29 ` Lunar 2012-03-02 21:05 ` Eric Wong
Code repositories for project(s) associated with this public inbox https://yhbt.net/rainbows.git/ This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).