Skip to content

mc_amqpl: remove parsing of <= 3.13 AMQP 1.0 compatibility headers - #17272

Merged
michaelklishin merged 6 commits into
mainfrom
mc-amqpl-legacy-amqp10-passthrough
Sep 2, 2026
Merged

michaelklishin merged 6 commits into
mainfrom
mc-amqpl-legacy-amqp10-passthrough

Conversation

@ansd

@ansd ansd commented Aug 31, 2026

Copy link
Copy Markdown
Member

Follows through on the decision in #16077 (comment) to remove parsing of the AMQP 1.0
compatibility headers in 4.4 rather than harden their validation.

RabbitMQ 3.13 and earlier stored a message received over AMQP 1.0 as an
AMQP 0-9-1 #content{}, keeping the sections that do not map to AMQP 0-9-1 in
four headers:

x-amqp-1.0-properties
x-amqp-1.0-app-properties
x-amqp-1.0-message-annotations
x-amqp-1.0-footer

The module that wrote them was replaced in 4.0, so the only messages that carry
them are ones a 3.13 or earlier node stored and no consumer has read since.
mc_amqpl still looked all four up on every conversion to AMQP 1.0. Such a
message is still delivered, with these headers now converted like any other
x- header, which is what an AMQP 0-9-1 consumer of one has always seen.

Three message annotations have the same history in the other direction:
x-basic-delivery-mode, x-basic-priority and x-basic-expiration.
rabbit_msg_record wrote them when it encoded an AMQP 0-9-1 message as AMQP 1.0
for a stream, and it was deleted before 4.0, so only a stream entry written by a
3.13 or earlier node carries them. x-basic-type stays, because
basic.properties.type has no AMQP 1.0 equivalent.

Two smaller changes to the same conversion code:

  • basic.properties.type is a free-form AMQP 0-9-1 property, but convert_to/3
    took a value of amqp-1.0 to mean the payload holds AMQP 1.0 encoded body
    sections. It now checks that the payload is well formed and that the sections
    it decodes to belong in a message body, and falls back to a single data
    section otherwise.

  • essential_properties/1 matched {ok, TTL} on
    rabbit_basic:parse_expiration/1. rabbit_channel checks expiration before
    building the message, but producers that build a #content{} themselves do
    not go through that check, so an expiration that does not parse is now
    ignored. This changes nothing for AMQP 0-9-1.

ansd added 5 commits August 31, 2026 11:55
`basic.properties.type` is a free-form AMQP 0.9.1 property. `convert_to/3`
took a value of `amqp-1.0` to mean the payload holds AMQP 1.0 encoded body
sections and decoded it on that basis, without checking that the payload is
well formed, or that the sections it decodes to belong in a message body.

Check both, and fall back to a single data section otherwise. A publisher
that means something else by `amqp-1.0` now gets the same conversion as any
other AMQP 0.9.1 publisher.

The type itself is still needed, because `convert_from/3` sets it whenever
an AMQP 1.0 message with an amqp-value or amqp-sequence body, or with a
footer, is converted to AMQP 0.9.1.
RabbitMQ 3.13 and earlier stored a message received over AMQP 1.0 as an
AMQP 0.9.1 `#content{}`, keeping the sections that do not map to AMQP 0.9.1
in four headers:

    x-amqp-1.0-properties
    x-amqp-1.0-app-properties
    x-amqp-1.0-message-annotations
    x-amqp-1.0-footer

The module that wrote them was replaced in 4.0, so the only messages that
carry them are ones a 3.13 or earlier node stored and no consumer has read
since. `mc_amqpl` still looked all four up on every conversion to AMQP 1.0.

Three message annotations have the same history in the other direction:

    x-basic-delivery-mode
    x-basic-priority
    x-basic-expiration

`rabbit_msg_record` wrote these when it encoded an AMQP 0.9.1 message as
AMQP 1.0 for a stream. It was deleted before 4.0, so only a stream written
by a 3.13 or earlier node contains them.

Drop all seven. The headers now convert like any other x- header, which is
what an AMQP 0.9.1 consumer of such a message has always seen, and a
recovered stream entry no longer restores a delivery mode, priority or
expiration that the 4.x annotations do not carry.

`x-basic-type` stays: `convert_to/3` writes it because
`basic.properties.type` has no AMQP 1.0 equivalent.
`mc_amqpl:essential_properties/1` matched `{ok, TTL}` on
`rabbit_basic:parse_expiration/1`, which returns an error for a value that
is not a non-negative integer. It runs for every message `mc_amqpl:init/1`
initialises.

`rabbit_channel` calls `check_expiration_header/1` before building the
message, so for an AMQP 0.9.1 publisher the match always succeeds.
Producers that build a `#content{}` themselves do not go through that check.

Ignore an expiration that does not parse. This changes nothing for AMQP
0.9.1, where the channel still rejects it before the message is built.
@ansd ansd added this to the 4.4.0 milestone Aug 31, 2026
@ansd ansd added the do-not-backport Changes not meant to be backported to release branches label Aug 31, 2026
@mergify

mergify Bot commented Aug 31, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@michaelklishin michaelklishin left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we apply the same idea as in 7111f4d to mc_amqpl:convert_to/3 (lines 341-347)?

Something like this

MsgTTL = case rabbit_basic:parse_expiration(Props) of
             {ok, Ttl} -> Ttl;
             {error, _} -> undefined
         end,

@ansd
ansd requested a review from michaelklishin September 1, 2026 08:32
@michaelklishin
michaelklishin merged commit 4e546e2 into main Sep 2, 2026
188 checks passed
@michaelklishin
michaelklishin deleted the mc-amqpl-legacy-amqp10-passthrough branch September 2, 2026 02:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-backport Changes not meant to be backported to release branches

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants