diff --git a/deps/rabbit/Makefile b/deps/rabbit/Makefile index bfeb692c0b02..304dcdce0564 100644 --- a/deps/rabbit/Makefile +++ b/deps/rabbit/Makefile @@ -129,7 +129,7 @@ endef LOCAL_DEPS = sasl os_mon inets compiler public_key crypto ssl syntax_tools xmerl BUILD_DEPS = rabbitmq_cli -DEPS = ranch rabbit_common amqp10_common rabbitmq_prelaunch ra sysmon_handler stdout_formatter recon redbug observer_cli osiris syslog systemd seshat horus khepri khepri_mnesia_migration cuttlefish gen_batch_server +DEPS = ranch cowlib rabbit_common amqp10_common rabbitmq_prelaunch ra sysmon_handler stdout_formatter recon redbug observer_cli osiris syslog systemd seshat horus khepri khepri_mnesia_migration cuttlefish gen_batch_server TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers meck proper amqp_client rabbitmq_amqp_client rabbitmq_amqp1_0 # We pin a version of Horus even if we don't use it directly (it is a diff --git a/deps/rabbit/src/rabbit_amqp_management.erl b/deps/rabbit/src/rabbit_amqp_management.erl index 092d59314298..65e9603495d0 100644 --- a/deps/rabbit/src/rabbit_amqp_management.erl +++ b/deps/rabbit/src/rabbit_amqp_management.erl @@ -80,7 +80,7 @@ handle_http_req(<<"GET">>, _User, _ConnPid, PermCaches) -> - QNameBin = rabbit_uri:urldecode(QNameBinQuoted), + QNameBin = cow_uri:urldecode(QNameBinQuoted), QName = queue_resource(Vhost, QNameBin), case rabbit_amqqueue:with( QName, @@ -110,7 +110,7 @@ handle_http_req(HttpMethod = <<"PUT">>, exclusive := Exclusive, arguments := QArgs0 } = decode_queue(ReqPayload), - QNameBin = rabbit_uri:urldecode(QNameBinQuoted), + QNameBin = cow_uri:urldecode(QNameBinQuoted), Owner = case Exclusive of true -> ConnPid; false -> none @@ -190,7 +190,7 @@ handle_http_req(<<"PUT">>, User = #user{username = Username}, _ConnPid, {PermCache0, TopicPermCache}) -> - XNameBin = rabbit_uri:urldecode(XNameBinQuoted), + XNameBin = cow_uri:urldecode(XNameBinQuoted), #{type := XTypeBin, durable := Durable, auto_delete := AutoDelete, @@ -240,7 +240,7 @@ handle_http_req(<<"DELETE">>, User, ConnPid, {PermCache0, TopicPermCache}) -> - QNameBin = rabbit_uri:urldecode(QNameBinQuoted), + QNameBin = cow_uri:urldecode(QNameBinQuoted), QName = queue_resource(Vhost, QNameBin), PermCache = check_resource_access(QName, read, User, PermCache0), try rabbit_amqqueue:with_exclusive_access_or_die( @@ -270,7 +270,7 @@ handle_http_req(<<"DELETE">>, User = #user{username = Username}, ConnPid, {PermCache0, TopicPermCache}) -> - QNameBin = rabbit_uri:urldecode(QNameBinQuoted), + QNameBin = cow_uri:urldecode(QNameBinQuoted), QName = queue_resource(Vhost, QNameBin), ok = prohibit_cr_lf(QNameBin), PermCache = check_resource_access(QName, configure, User, PermCache0), @@ -290,7 +290,7 @@ handle_http_req(<<"DELETE">>, User = #user{username = Username}, _ConnPid, {PermCache0, TopicPermCache}) -> - XNameBin = rabbit_uri:urldecode(XNameBinQuoted), + XNameBin = cow_uri:urldecode(XNameBinQuoted), XName = exchange_resource(Vhost, XNameBin), ok = prohibit_cr_lf(XNameBin), ok = prohibit_default_exchange(XName), @@ -630,9 +630,9 @@ decode_binding_path_segment(Segment) -> end, case re:run(Segment, MP, [{capture, all_but_first, binary}]) of {match, [SrcQ, <>, DstQ, KeyQ, ArgsHash]} -> - Src = rabbit_uri:urldecode(SrcQ), - Dst = rabbit_uri:urldecode(DstQ), - Key = rabbit_uri:urldecode(KeyQ), + Src = cow_uri:urldecode(SrcQ), + Dst = cow_uri:urldecode(DstQ), + Key = cow_uri:urldecode(KeyQ), DstKind = destination_char_to_kind(DstKindChar), {Src, DstKind, Dst, Key, ArgsHash}; nomatch -> diff --git a/deps/rabbit/src/rabbit_amqp_session.erl b/deps/rabbit/src/rabbit_amqp_session.erl index 4ad681707a25..b31093dcceb6 100644 --- a/deps/rabbit/src/rabbit_amqp_session.erl +++ b/deps/rabbit/src/rabbit_amqp_session.erl @@ -2699,7 +2699,7 @@ ensure_source(Source = #'v1_0.source'{address = Address, {utf8, <<"/queues/", QNameBinQuoted/binary>>} -> %% The only possible v2 source address format is: %% /queues/:queue - try rabbit_uri:urldecode(QNameBinQuoted) of + try cow_uri:urldecode(QNameBinQuoted) of QNameBin -> QName = queue_resource(Vhost, QNameBin), ok = exit_if_absent(QName), @@ -2907,11 +2907,11 @@ parse_target_v2_string0(<<"/exchanges/", Rest/binary>>) -> [<<"amq.default">> | _] -> {error, bad_address}; [XNameBinQuoted] -> - XNameBin = rabbit_uri:urldecode(XNameBinQuoted), + XNameBin = cow_uri:urldecode(XNameBinQuoted), {ok, XNameBin, <<>>, undefined}; [XNameBinQuoted, RKeyQuoted] -> - XNameBin = rabbit_uri:urldecode(XNameBinQuoted), - RKey = rabbit_uri:urldecode(RKeyQuoted), + XNameBin = cow_uri:urldecode(XNameBinQuoted), + RKey = cow_uri:urldecode(RKeyQuoted), {ok, XNameBin, RKey, undefined}; _ -> {error, bad_address} @@ -2920,7 +2920,7 @@ parse_target_v2_string0(<<"/queues/">>) -> %% empty queue name is invalid {error, bad_address}; parse_target_v2_string0(<<"/queues/", QNameBinQuoted/binary>>) -> - QNameBin = rabbit_uri:urldecode(QNameBinQuoted), + QNameBin = cow_uri:urldecode(QNameBinQuoted), {ok, ?DEFAULT_EXCHANGE_NAME, QNameBin, QNameBin}; parse_target_v2_string0(_) -> {error, bad_address}. diff --git a/deps/rabbit/src/rabbit_uri.erl b/deps/rabbit/src/rabbit_uri.erl deleted file mode 100644 index f1e2d028753f..000000000000 --- a/deps/rabbit/src/rabbit_uri.erl +++ /dev/null @@ -1,154 +0,0 @@ -%% Copyright (c) 2016-2024, Loïc Hoguin -%% -%% Permission to use, copy, modify, and/or distribute this software for any -%% purpose with or without fee is hereby granted, provided that the above -%% copyright notice and this permission notice appear in all copies. -%% -%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -%% ------------------------------------------------------------------------- %% -%% This file is a partial copy of -%% https://github.com/ninenines/cowlib/blob/optimise-urldecode/src/cow_uri.erl -%% We use this copy because: -%% 1. uri_string:unquote/1 is lax: It doesn't validate that characters that are -%% required to be percent encoded are indeed percent encoded. In RabbitMQ, -%% we want to enforce that proper percent encoding is done by AMQP clients. -%% 2. uri_string:unquote/1 and cow_uri:urldecode/1 in cowlib v2.13.0 are both -%% slow because they allocate a new binary for the common case where no -%% character was percent encoded. -%% When a new cowlib version is released, we should make app rabbit depend on -%% app cowlib calling cow_uri:urldecode/1 and delete this file (rabbit_uri.erl). -%% ------------------------------------------------------------------------- %% - --module(rabbit_uri). - --export([urldecode/1]). - --define(UNHEX(H, L), (?UNHEX(H) bsl 4 bor ?UNHEX(L))). - --define(UNHEX(C), - case C of - $0 -> 0; - $1 -> 1; - $2 -> 2; - $3 -> 3; - $4 -> 4; - $5 -> 5; - $6 -> 6; - $7 -> 7; - $8 -> 8; - $9 -> 9; - $A -> 10; - $B -> 11; - $C -> 12; - $D -> 13; - $E -> 14; - $F -> 15; - $a -> 10; - $b -> 11; - $c -> 12; - $d -> 13; - $e -> 14; - $f -> 15 - end -). - -%% Decode a percent encoded string. (RFC3986 2.1) -%% -%% Inspiration for some of the optimisations done here come -%% from the new `json` module as it was in mid-2024. -%% -%% Possible input includes: -%% -%% * nothing encoded (no % character): -%% We want to return the binary as-is to avoid an allocation. -%% -%% * small number of encoded characters: -%% We can "skip" words of text. -%% -%% * mostly encoded characters (non-ascii languages) -%% We can decode characters in bulk. - --define(IS_PLAIN(C), ( - (C =:= $!) orelse (C =:= $$) orelse (C =:= $&) orelse (C =:= $') orelse - (C =:= $() orelse (C =:= $)) orelse (C =:= $*) orelse (C =:= $+) orelse - (C =:= $,) orelse (C =:= $-) orelse (C =:= $.) orelse (C =:= $0) orelse - (C =:= $1) orelse (C =:= $2) orelse (C =:= $3) orelse (C =:= $4) orelse - (C =:= $5) orelse (C =:= $6) orelse (C =:= $7) orelse (C =:= $8) orelse - (C =:= $9) orelse (C =:= $:) orelse (C =:= $;) orelse (C =:= $=) orelse - (C =:= $@) orelse (C =:= $A) orelse (C =:= $B) orelse (C =:= $C) orelse - (C =:= $D) orelse (C =:= $E) orelse (C =:= $F) orelse (C =:= $G) orelse - (C =:= $H) orelse (C =:= $I) orelse (C =:= $J) orelse (C =:= $K) orelse - (C =:= $L) orelse (C =:= $M) orelse (C =:= $N) orelse (C =:= $O) orelse - (C =:= $P) orelse (C =:= $Q) orelse (C =:= $R) orelse (C =:= $S) orelse - (C =:= $T) orelse (C =:= $U) orelse (C =:= $V) orelse (C =:= $W) orelse - (C =:= $X) orelse (C =:= $Y) orelse (C =:= $Z) orelse (C =:= $_) orelse - (C =:= $a) orelse (C =:= $b) orelse (C =:= $c) orelse (C =:= $d) orelse - (C =:= $e) orelse (C =:= $f) orelse (C =:= $g) orelse (C =:= $h) orelse - (C =:= $i) orelse (C =:= $j) orelse (C =:= $k) orelse (C =:= $l) orelse - (C =:= $m) orelse (C =:= $n) orelse (C =:= $o) orelse (C =:= $p) orelse - (C =:= $q) orelse (C =:= $r) orelse (C =:= $s) orelse (C =:= $t) orelse - (C =:= $u) orelse (C =:= $v) orelse (C =:= $w) orelse (C =:= $x) orelse - (C =:= $y) orelse (C =:= $z) orelse (C =:= $~) -)). - -urldecode(Binary) -> - skip_dec(Binary, Binary, 0). - -%% This functions helps avoid a binary allocation when -%% there is nothing to decode. -skip_dec(Binary, Orig, Len) -> - case Binary of - <> - when ?IS_PLAIN(C1) andalso ?IS_PLAIN(C2) - andalso ?IS_PLAIN(C3) andalso ?IS_PLAIN(C4) -> - skip_dec(Rest, Orig, Len + 4); - _ -> - dec(Binary, [], Orig, 0, Len) - end. - --dialyzer({no_improper_lists, [dec/5]}). -%% This clause helps speed up decoding of highly encoded values. -dec(<<$%, H1, L1, $%, H2, L2, $%, H3, L3, $%, H4, L4, Rest/bits>>, Acc, Orig, Skip, Len) -> - C1 = ?UNHEX(H1, L1), - C2 = ?UNHEX(H2, L2), - C3 = ?UNHEX(H3, L3), - C4 = ?UNHEX(H4, L4), - case Len of - 0 -> - dec(Rest, [Acc|<>], Orig, Skip + 12, 0); - _ -> - Part = binary_part(Orig, Skip, Len), - dec(Rest, [Acc, Part|<>], Orig, Skip + Len + 12, 0) - end; -dec(<<$%, H, L, Rest/bits>>, Acc, Orig, Skip, Len) -> - C = ?UNHEX(H, L), - case Len of - 0 -> - dec(Rest, [Acc|<>], Orig, Skip + 3, 0); - _ -> - Part = binary_part(Orig, Skip, Len), - dec(Rest, [Acc, Part|<>], Orig, Skip + Len + 3, 0) - end; -%% This clause helps speed up decoding of barely encoded values. -dec(<>, Acc, Orig, Skip, Len) - when ?IS_PLAIN(C1) andalso ?IS_PLAIN(C2) - andalso ?IS_PLAIN(C3) andalso ?IS_PLAIN(C4) -> - dec(Rest, Acc, Orig, Skip, Len + 4); -dec(<>, Acc, Orig, Skip, Len) when ?IS_PLAIN(C) -> - dec(Rest, Acc, Orig, Skip, Len + 1); -dec(<<>>, _, Orig, 0, _) -> - Orig; -dec(<<>>, Acc, _, _, 0) -> - iolist_to_binary(Acc); -dec(<<>>, Acc, Orig, Skip, Len) -> - Part = binary_part(Orig, Skip, Len), - iolist_to_binary([Acc|Part]); -dec(_, _, Orig, Skip, Len) -> - error({invalid_byte, binary:at(Orig, Skip + Len)}). diff --git a/deps/rabbitmq_mqtt/src/mc_mqtt.erl b/deps/rabbitmq_mqtt/src/mc_mqtt.erl index ff2ce997da45..5afdcd1c6913 100644 --- a/deps/rabbitmq_mqtt/src/mc_mqtt.erl +++ b/deps/rabbitmq_mqtt/src/mc_mqtt.erl @@ -92,7 +92,7 @@ convert_from(mc_amqp, Sections, Env) -> MqttX:(byte_size(MqttX))/binary, "/", RoutingKeyQuoted/binary>> -> - try rabbit_uri:urldecode(RoutingKeyQuoted) of + try cow_uri:urldecode(RoutingKeyQuoted) of RoutingKey -> MqttTopic = rabbit_mqtt_util:amqp_to_mqtt(RoutingKey), #{'Response-Topic' => MqttTopic}