fixed broken pipe issue on quick error response from server

in some cases where the client is sending a request with a lot of bytes
(i.e. file uploads), and the server can't consume it (because
authorization, or wrong endpoint), the server stops processing the
request altogether and sends an error response immediately, in which
case the client should pivot and read the error response. Not doing this
was causing the Errno::EPIPE error. The mitigation is therefore to
rescue the error, and mark the consumption loop to read the response
immediately.
This commit is contained in:
HoneyryderChuck 2021-02-15 10:20:20 +00:00
parent 7082f63e4e
commit 19dc528030

View File

@ -251,6 +251,7 @@ module HTTPX
def consume
catch(:called) do
epiped = false
loop do
parser.consume
@ -321,7 +322,19 @@ module HTTPX
break
end
siz = @io.write(@write_buffer)
begin
siz = @io.write(@write_buffer)
rescue Errno::EPIPE
# this can happen if we still have bytes in the buffer to send to the server, but
# the server wants to respond immediately with some message, or an error. An example is
# when one's uploading a big file to an unintended endpoint, and the server stops the
# consumption, and responds immediately with an authorization of even method not allowed error.
# at this point, we have to let the connection switch to read-mode.
log(level: 2) { "pipe broken, could not flush buffer..." }
epiped = true
read_drained = false
break
end
log(level: 3, color: :cyan) { "IO WRITE: #{siz} bytes..." }
unless siz
ex = EOFError.new("descriptor closed")