Rainbows! Rack HTTP server user/dev discussion
 help / color / mirror / code / Atom feed
From: Eric Wong <normalperson-rMlxZR9MS24@public.gmane.org>
To: Rainbows! list <rainbows-talk-GrnCvJ7WPxnNLxjTenLetw@public.gmane.org>
Subject: Re: 'Connection reset by peer' when replying before the end of POST data
Date: Tue, 28 Feb 2012 23:39:19 +0000	[thread overview]
Message-ID: <20120228233919.GA10168@dcvr.yhbt.net> (raw)
In-Reply-To: <20120228221546.GC16985@candra>

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

  reply	other threads:[~2012-02-28 23:58 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
     [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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://yhbt.net/rainbows/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120228233919.GA10168@dcvr.yhbt.net \
    --to=normalperson-rmlxzr9ms24@public.gmane.org \
    --cc=rainbows-talk-GrnCvJ7WPxnNLxjTenLetw@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).