-
Notifications
You must be signed in to change notification settings - Fork 327
Description
I ran into a bug where http.rb raises HTTP::ConnectionError: error writing to socket: Connection reset by peer
when POSTing ~3mb of xml to a server. The error's #cause
is Errno::ECONNRESET: Connection reset by peer
.
The reason this happened is that I needed to follow a redirect (302 FOUND) directly after a POST request, (I don't have control of this server) so I used the chainable API:
HTTP
.follow(strict: false)
# ...snip
.post(url, data)
Expecting this to issue a simple GET request to the provided URL. (Maybe with the same cookies/headers).
To my surprise, the above code repeats the entire request body, which for whatever reason, the receiving server does not care to wait for before closing the connection. (I have no idea what the code of said server is actually doing).
I've reproduced the issue here. The stacktrace when running this script against the real world server looks like this:
stacktrace
TEST 11: STATUS RECEIVED: 200 OK ✓ SUCCESS
TEST 12: ❌ FAIL: error raised: HTTP::ConnectionError: error writing to socket: Connection reset by peer
STACK: /home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/timeout/null.rb:52:in `write'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/timeout/null.rb:52:in `write'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/request/writer.rb:109:in `write'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/request/writer.rb:65:in `block in send_request'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/request/writer.rb:82:in `block in each_chunk'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/request/body.rb:93:in `write'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/request/body.rb:37:in `copy_stream'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/request/body.rb:37:in `each'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/request/writer.rb:80:in `each_chunk'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/request/writer.rb:65:in `send_request'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/request/writer.rb:38:in `stream'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/request.rb:118:in `stream'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/connection.rb:76:in `send_request'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/client.rb:74:in `perform'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/client.rb:35:in `block in request'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/redirector.rb:63:in `perform'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/client.rb:34:in `request'
/home/odin/.rbenv/versions/2.6.6/gemsets/repro/gems/http-4.4.1/lib/http/chainable.rb:27:in `post'
/home/odin/dev/work/httprb-socket-mem-error-repro/http_requester.rb:30:in `request_validation!'
/home/odin/dev/work/httprb-socket-mem-error-repro/setup.rb:15:in `go!'
/home/odin/dev/work/httprb-socket-mem-error-repro/setup.rb:35:in `block in test!'
/home/odin/dev/work/httprb-socket-mem-error-repro/setup.rb:32:in `times'
/home/odin/dev/work/httprb-socket-mem-error-repro/setup.rb:32:in `test!'
main.rb:24:in `<main>'
CAUSE: Errno::ECONNRESET: Connection reset by peer
The failure is flaky. It seems that sometimes http.rb does manage to write the entire request body into the socket before it closes, probably due to network delays.
I'm not sure this gem is following a standard that says that this behaviour is indeed correct.
At any rate, I found this behaviour surprising and wish I had a simple option for getting around it. Maybe something like this:
HTTP
.follow(strict: false, body: false) # please mr. http don't copy the body into the redirect it might be masssssssive
# ... snip
.post(url, data)
Environment
http.rb version: 4.4.1
ruby version: 2.6.6