Merge pull request #13365 from rabbitmq/cow-uri

Delete rabbit_uri
This commit is contained in:
Michael Klishin 2025-02-18 11:36:06 -05:00 committed by GitHub
commit 819b80bfc9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 16 additions and 170 deletions

View File

@ -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

View File

@ -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, <<DstKindChar>>, 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 ->

View File

@ -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}.

View File

@ -1,154 +0,0 @@
%% Copyright (c) 2016-2024, Loïc Hoguin <essen@ninenines.eu>
%%
%% 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
<<C1, C2, C3, C4, Rest/bits>>
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|<<C1, C2, C3, C4>>], Orig, Skip + 12, 0);
_ ->
Part = binary_part(Orig, Skip, Len),
dec(Rest, [Acc, Part|<<C1, C2, C3, C4>>], 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|<<C>>], Orig, Skip + 3, 0);
_ ->
Part = binary_part(Orig, Skip, Len),
dec(Rest, [Acc, Part|<<C>>], Orig, Skip + Len + 3, 0)
end;
%% This clause helps speed up decoding of barely encoded values.
dec(<<C1, C2, C3, C4, Rest/bits>>, 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(<<C, Rest/bits>>, 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)}).

View File

@ -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}