Skip to content

Commit 801c0d4

Browse files
Merge pull request #15049 from rabbitmq/mergify/bp/v4.2.x/pr-15048
Output descriptive error if AMQP message has no body (backport #15048)
2 parents a6567fb + bb38375 commit 801c0d4

File tree

6 files changed

+52
-5
lines changed

6 files changed

+52
-5
lines changed

deps/amqp10_common/src/amqp10_binary_parser.erl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ mapify([Key, Value | Rest]) ->
191191
%% We re-use the match context avoiding creation of sub binaries.
192192
-spec parse_many(binary(), opts()) ->
193193
[amqp10_binary_generator:amqp10_type() |
194-
{{pos, non_neg_integer()}, amqp10_binary_generator:amqp10_type() | body}].
194+
{{pos, non_neg_integer()},
195+
amqp10_binary_generator:amqp10_type() | {body, pos_integer()}}].
195196
parse_many(Binary, Opts) ->
196197
OptionServerMode = lists:member(server_mode, Opts),
197198
pm(Binary, OptionServerMode, 0).

deps/rabbit/src/mc_amqp.erl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ msg_body_encoded([{{pos, Pos}, #'v1_0.application_properties'{content = APC}} |
636636
application_properties = APC,
637637
bare_and_footer_application_properties_pos = Pos - BarePos
638638
});
639-
%% Base case: we assert the last part contains the mandatory body:
639+
%% Base case: The last part must contain the mandatory body:
640640
msg_body_encoded([{{pos, Pos}, {body, Code}}], Payload, Msg)
641641
when is_binary(Payload) ->
642642
%% AMQP sender omitted properties and application-properties sections.
@@ -648,7 +648,9 @@ msg_body_encoded([{{pos, Pos}, {body, Code}}], Payload, Msg)
648648
msg_body_encoded([{{pos, Pos}, {body, Code}}], BarePos, Msg)
649649
when is_integer(BarePos) ->
650650
Msg#msg_body_encoded{bare_and_footer_body_pos = Pos - BarePos,
651-
body_code = Code}.
651+
body_code = Code};
652+
msg_body_encoded([], _, #msg_body_encoded{body_code = uninit}) ->
653+
throw(missing_amqp_message_body).
652654

653655
%% We extract the binary part of the payload exactly once when the bare message starts.
654656
binary_part_bare_and_footer(Payload, Start) ->

deps/rabbit/src/rabbit_amqp_session.erl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2524,7 +2524,11 @@ incoming_link_transfer(
25242524
validate_message_size(PayloadSize, MaxMessageSize),
25252525
rabbit_msg_size_metrics:observe(?PROTOCOL, PayloadSize),
25262526
messages_received(Settled),
2527-
Mc0 = mc:init(mc_amqp, PayloadBin, #{}),
2527+
Mc0 = try mc:init(mc_amqp, PayloadBin, #{})
2528+
catch missing_amqp_message_body ->
2529+
link_error(?V_1_0_AMQP_ERROR_DECODE_ERROR,
2530+
"message has no body", [])
2531+
end,
25282532
case lookup_target(LinkExchange, LinkRKey, Mc0, Vhost, User, PermCache0) of
25292533
{ok, X, RoutingKeys, Mc1, PermCache} ->
25302534
check_user_id(Mc1, User),

deps/rabbit/test/amqp_dotnet_SUITE.erl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ groups() ->
4242
auth_failure,
4343
access_failure_not_allowed,
4444
access_failure_send,
45-
streams
45+
streams,
46+
message_without_body
4647
]
4748
}].
4849

@@ -215,6 +216,9 @@ streams(Config) ->
215216
declare_queue(Config, ?FUNCTION_NAME, "stream"),
216217
run(?FUNCTION_NAME, Config).
217218

219+
message_without_body(Config) ->
220+
run(?FUNCTION_NAME, Config).
221+
218222
%% -------------------------------------------------------------------
219223
%% Helpers
220224
%% -------------------------------------------------------------------

deps/rabbit/test/amqp_dotnet_SUITE_data/fsharp-tests/Program.fs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,37 @@ module Test =
574574
printfn "Exception %A" ex
575575
()
576576

577+
// Test sending a message without a body section.
578+
// Although supported by this lib and Azure Service Bus, we expect RabbitMQ
579+
// to return a descriptive error since a body is mandatory according to the AMQP spec.
580+
let messageWithoutBody uri =
581+
use ac = connectAnon uri
582+
let sender = SenderLink(ac.Session, "sender", "/exchange/amq.fanout")
583+
584+
use detachEvent = new AutoResetEvent(false)
585+
let mutable linkError : Error = null
586+
587+
sender.add_Closed(new ClosedCallback(fun _ err ->
588+
linkError <- err
589+
detachEvent.Set() |> ignore))
590+
591+
// Create a message with Properties but no body section
592+
let message = new Message(Properties = new Properties())
593+
594+
try
595+
sender.Send(message, TimeSpan.FromSeconds 5.)
596+
failwith "Expected exception not received"
597+
with
598+
| :? Amqp.AmqpException as ex ->
599+
printfn "Got expected exception: %A" ex
600+
601+
assertTrue (detachEvent.WaitOne(9000))
602+
assertNotNull linkError
603+
assertEqual (Symbol "amqp:decode-error") linkError.Condition
604+
assertNotNull linkError.Description
605+
assertTrue (linkError.Description.Contains("message has no body"))
606+
assertTrue (not ac.Session.IsClosed)
607+
577608
let (|AsLower|) (s: string) =
578609
match s with
579610
| null -> null
@@ -645,6 +676,9 @@ let main argv =
645676
| [AsLower "no_routes_is_released"; uri] ->
646677
no_routes_is_released uri
647678
0
679+
| [AsLower "message_without_body"; uri] ->
680+
messageWithoutBody uri
681+
0
648682
| _ ->
649683
printfn "test %A not found. usage: <test> <uri>" argv
650684
1

release-notes/4.0.1.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ Starting with RabbitMQ 4.0, RabbitMQ strictly validates that
136136
[non-reserved annotation keys](https://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-messaging-v1.0-os.html#type-annotations).
137137
As a result, clients can only send symbolic keys that begin with `x-`.
138138

139+
Starting with RabbitMQ 4.0, RabbitMQ also strictly validates that an AMQP message contains the mandatory body.
140+
139141
### MQTT
140142

141143
RabbitMQ 3.13 [rabbitmq.conf](https://www.rabbitmq.com/docs/configure#config-file) settings `mqtt.default_user`, `mqtt.default_password`,

0 commit comments

Comments
 (0)