Skip to content

Commit 50726d5

Browse files
committed
fix a crash in the streaming hello monitor, if the server sends more than one response at once
1 parent 5b0bc86 commit 50726d5

File tree

5 files changed

+36
-15
lines changed

5 files changed

+36
-15
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## 0.9.2 (2022-09-07)
9+
* Bugfix
10+
* fix a crash in the streaming hello monitor, if the server sends more than one response at once
11+
812
## 0.9.1 (2022-05-27)
913
* Bugfix
1014
* add backward compatible for Elixir < 1.13 (thanks to ja-jimenez)

lib/mongo/messages.ex

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ defmodule Mongo.Messages do
3939

4040
@header_size 4 * 4
4141

42-
defrecordp :msg_header, [:length, :request_id, :response_to, :op_code]
42+
defrecord :msg_header, [:length, :request_id, :response_to, :op_code]
4343
defrecord :op_query, [:flags, :coll, :num_skip, :num_return, :query, :select]
4444
defrecord :op_reply, [:flags, :cursor_id, :from, :num, :docs]
4545
defrecord :sequence, [:size, :identifier, :docs]
@@ -51,16 +51,20 @@ defmodule Mongo.Messages do
5151
Decodes the header from response of a request sent by the mongodb server
5252
"""
5353
def decode_header(iolist) when is_list(iolist) do
54-
case IO.iodata_length(iolist) >= @header_size do
55-
true -> iolist |> IO.iodata_to_binary() |> decode_header()
56-
false -> :error
54+
case IO.iodata_length(iolist) == @header_size do
55+
true ->
56+
iolist
57+
|> IO.iodata_to_binary()
58+
|> decode_header()
59+
60+
false ->
61+
:error
5762
end
5863
end
5964

60-
def decode_header(<<length::int32, request_id::int32, response_to::int32, op_code::int32, rest::binary>>) do
61-
## todo don't subtract header-size here
65+
def decode_header(<<length::int32, request_id::int32, response_to::int32, op_code::int32>>) do
6266
header = msg_header(length: length - @header_size, request_id: request_id, response_to: response_to, op_code: op_code)
63-
{:ok, header, rest}
67+
{:ok, header}
6468
end
6569

6670
def decode_header(_binary), do: :error

lib/mongo/version.ex

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,15 @@ defmodule Mongo.Version do
3535
# Supports features available from 5.0 and onwards.
3636
wire_version_50: 13,
3737
# Supports features available from 5.1 and onwards.
38-
wire_version_51: 14
38+
wire_version_51: 14,
39+
# Supports features available from 5.2 and onwards.
40+
wire_version_52: 15,
41+
# Supports features available from 5.3 and onwards.
42+
wire_version_53: 16,
43+
# Supports features available from 6.0 and onwards.
44+
wire_version_60: 17,
45+
# Supports features available from 6.1 and onwards.
46+
wire_version_61: 18
3947
]
4048

4149
for {key, value} <- values do

lib/mongo_db_connection/utils.ex

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ defmodule Mongo.MongoDBConnection.Utils do
1212
# currently not used @reply_shard_config_stale 0x4
1313
# currently not used @reply_await_capable 0x8
1414

15+
@header_size 4 * 4
16+
1517
@doc """
1618
Sends a request id and waits for the response with the same id
1719
"""
@@ -97,22 +99,24 @@ defmodule Mongo.MongoDBConnection.Utils do
9799
end
98100

99101
defp recv_data(nil, "", %{connection: {mod, socket}} = state) do
100-
case mod.recv(socket, 0, state.timeout) do
102+
case mod.recv(socket, @header_size, state.timeout) do
101103
{:ok, tail} -> recv_data(nil, tail, state)
102104
{:error, reason} -> recv_error(reason, state)
103105
end
104106
end
105107

106108
defp recv_data(nil, data, %{connection: {mod, socket}} = state) do
107109
case decode_header(data) do
108-
{:ok, header, rest} ->
109-
recv_data(header, rest, state)
110+
{:ok, header} ->
111+
msg_header(length: length) = header
110112

111-
:error ->
112-
case mod.recv(socket, 0, state.timeout) do
113-
{:ok, tail} -> recv_data(nil, [data | tail], state)
113+
case mod.recv(socket, length, state.timeout) do
114+
{:ok, data} -> recv_data(header, data, state)
114115
{:error, reason} -> recv_error(reason, state)
115116
end
117+
118+
:error ->
119+
recv_error(:header_not_found, state)
116120
end
117121
end
118122

@@ -122,6 +126,7 @@ defmodule Mongo.MongoDBConnection.Utils do
122126
{:ok, id, reply}
123127

124128
:error ->
129+
## todo
125130
case mod.recv(socket, 0, state.timeout) do
126131
{:ok, tail} -> recv_data(header, [data | tail], state)
127132
{:error, reason} -> recv_error(reason, state)

test/mongo/transaction_retries_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,6 @@ defmodule Mongo.TransactionRetriesTest do
165165
catcher
166166
|> EventCatcher.succeeded_events()
167167
|> Enum.map(fn event -> event.command_name end)
168-
|> Enum.reject(fn event -> event == :isMaster end)
168+
|> Enum.reject(fn event -> event == :isMaster || event == :more_to_come end)
169169
end
170170
end

0 commit comments

Comments
 (0)