Closed bitberry-dev closed 2 years ago
@bitberry-dev awesome catch! Any chance you'd be able to send a PR to fix this? 🙃
@whatyouhide Yep, I can send a quick fix like below - just ensure connection closed
defp send_connection_error!(conn, error_code, debug_data) do
frame =
goaway(stream_id: 0, last_stream_id: 2, error_code: error_code, debug_data: debug_data)
try do
conn = send!(conn, Frame.encode(frame))
after
_ = conn.transport.close(conn.socket)
end
conn = put_in(conn.state, :closed)
throw({:mint, conn, wrap_error({error_code, debug_data})})
end
But this is a weak solution and I would not want to implement it, judging by the bug - the code needs to be refactored. And other methods that use send_connection_error!
should be checked. I can also do this in my free time, the only thing I need is a mint core developer with whom I could consult on certain architectural decisions. Do you have slack?
@bitberry-dev yes, you can reach out to me on the Elixir Slack (@whatyouhide
there too I believe). 🙃
So, I looked at the code and was a little surprised by the widespread use of throw. Initially, I wanted to try to abandon throw altogether and control execution more explicitly, this would help to avoid a whole class of errors such as described in the issue, but this will require a deep dive into these 2k+ lines of code and take a lot of time, and, most importantly, it is not clear whether this is necessary at all (obviously, this style of code was used intentionally) :)
In the end, I just wrote a couple of tests and made a simple fix. Added a pull request, take a look 😉
Hello, guys!
I was testing my application to work in extremely edge cases and noticed that mint does not close sockets correctly under certain circumstances, this leads to a leak.
Mint does not close a socket when two circumstances coincide:
I wrote simple test to demonstrate this
Test results:
I quickly found the error by looking at the source code:
close/1
called we are here https://github.com/elixir-mint/mint/blob/7aaf0377343f63dca87d8007fd404253a44598b5/lib/mint/http2.ex#L387send_connection_error!/3
https://github.com/elixir-mint/mint/blob/7aaf0377343f63dca87d8007fd404253a44598b5/lib/mint/http2.ex#L2027send!/2
https://github.com/elixir-mint/mint/blob/7aaf0377343f63dca87d8007fd404253a44598b5/lib/mint/http2.ex#L2094And there are problem,
transport.send(socket, bytes)
returnsTransportError
then you just throw this error and because of it we ignore this command_ = conn.transport.close(conn.socket)
atsend_connection_error!/3
and the socket is not closed correctlyI hope I made my point clear. Looking at the code, I see that you wanted to handle such extreme edge cases, but something went wrong 😂