Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix intermittent chunked response hang #746

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

danielfinke
Copy link

When streaming a chunked response, it is possible to cause a TCP receive hang under particular circumstances. If at one point the parser buffer doesn't have the whole chunk, at a later point the buffer ends up empty <<>>, and subsequently hackney_response:stream_body/1 is called, hackney_response:recv/2 will hang if the expected remaining size exceeds the remainder of the response. That expected size is actually stale, from the earlier point when the parser did not have the whole chunk. This issue slipped in with #710.

This was identified when using https://github.com/benoitc/couchbeam and sending several chunked requests. If the last non-terminating chunk completed the response JSON object, hackney_response:skip_body/1 is called to discard the remaining body, but is told to receive a number of bytes equal to the expected remaining size which will frequently exceed the small terminating chunk and trailers. As a result, the recv operation hangs waiting for bytes that will never arrive.

Now, the transfer state (BufSize/ExpectedSize) are reset after each successful chunk. The speed benefit of #710 is retained (tested with the same approach as in that PR).

  • correct some related typespecs

When streaming a chunked response, it is possible to cause a TCP receive
hang under particular circumstances. If at one point the parser buffer
doesn't have the whole chunk, at a later point the buffer ends up empty
`<<>>`, and subsequently `hackney_response:stream_body/1` is called,
`hackney_response:recv/2` will hang if the expected remaining size
exceeds the remainder of the response. That expected size is actually
stale, from the earlier point when the parser did not have the whole
chunk. This issue slipped in with benoitc#710.

This was identified when using https://github.com/benoitc/couchbeam and
sending several chunked requests. If the last non-terminating chunk
completed the response JSON object, `hackney_response:skip_body/1` is
called to discard the remaining body, but is told to receive a number of
bytes equal to the expected remaining size which will frequently exceed
the small terminating chunk and trailers. As a result, the recv
operation hangs waiting for bytes that will never arrive.

Now, the transfer state (`BufSize`/`ExpectedSize`) are reset after each
successful chunk. The speed benefit of benoitc#710 is retained
(tested with the same approach as in that PR).

- correct some related typespecs
@jamesaimonetti
Copy link

@benoitc this has been working well for us lately. Curious if you have a chance to review?

@benoitc
Copy link
Owner

benoitc commented Oct 1, 2024

on it sorry for the delay.

@benoitc benoitc self-assigned this Oct 1, 2024
@danielfinke
Copy link
Author

@benoitc hey there, anything needed from our end? I double-checked and I see the same EUnit failures on master as on this branch, so I don't believe they are a result of my changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants