benoitc / hackney

simple HTTP client in Erlang
Other
1.34k stars 427 forks source link

Send hackney_response before calling handle_error #573

Closed Kuroneer closed 5 years ago

Kuroneer commented 5 years ago

As hackney_manager:handle_error could terminate the request, the request process should send the response to the owner before calling it.

Right now, with async calls there's a race condition when calling hackney_manager:handle_error before having sent the response (from a {error, Term}) back to the owner. Since hackney_manager:handle_error can kill the caller, and it may have not sent the response yet.

$> while true; do echo -e "HTTP/1.1 200 OK\n\n $(date)" | nc -l -p 8081; sleep .1; done
662> hackney:request(get, "localhost:8081", [], <<>>, [{pool, d}, {stream_to, self()}, async]).
(<0.2645.0>) returned from hackney_stream:parse/1 -> {error,bad_request}
(<0.2645.0>) call hackney_manager:handle_error(
(<0.2645.0>) call hackney_manager:close_request(
(<0.2645.0>) call hackney_manager:get_state(
(<0.2645.0>) returned from hackney_manager:get_state/1 -> {client,
(<0.2645.0>) call hackney_manager:close_request( %% <--- <0.2645.0> is still in close_request
(<0.788.0>) call hackney_manager:handle_cast(
(<0.788.0>) call hackney_manager:untrack_owner(
(<0.788.0>) returned from hackney_manager:untrack_owner/3 -> {dict,1,16,16,8,
(<0.788.0>) call hackney_manager:finish_request(
(<0.788.0>) returned from hackney_manager:finish_request/2 -> ok
(<0.788.0>) call hackney_manager:terminate_async_response(<0.2645.0>)
(<0.788.0>) call hackney_manager:terminate_async_response(<0.2645.0>,shutdown) %% <--- <0.2645.0> gets killed
(<0.788.0>) call hackney_manager:monitor_child(<0.2645.0>)
(<0.788.0>) returned from hackney_manager:monitor_child/1 -> true
(<0.788.0>) call hackney_manager:wait_async_response(<0.2645.0>)
(<0.2645.0>) exception_from {hackney_manager,close_request,1} {exit,shutdown}
(<0.2645.0>) exception_from {hackney_manager,close_request,1} {exit,shutdown}
(<0.2645.0>) exception_from {hackney_manager,handle_error,1} {exit,shutdown}
(<0.2645.0>) exception_from {hackney_stream,stream_loop,4} {exit,shutdown}
(<0.2645.0>) exception_from {hackney_stream,async_recv,5} {exit,shutdown}
(<0.2645.0>) exception_from {hackney_stream,stream_loop,4} {exit,shutdown}
(<0.2645.0>) exception_from {hackney_stream,init,4} {exit,shutdown}
(<0.788.0>) returned from hackney_manager:wait_async_response/1 -> ok
(<0.788.0>) returned from hackney_manager:terminate_async_response/2 -> ok
(<0.788.0>) returned from hackney_manager:terminate_async_response/1 -> ok
(<0.788.0>) returned from hackney_manager:handle_cast/2 -> {noreply,
{ok,#Ref<0.708395227.153616385.107477>}
663> flush().
ok
benoitc commented 5 years ago

thanks!