1%% This Source Code Form is subject to the terms of the Mozilla Public 2%% License, v. 2.0. If a copy of the MPL was not distributed with this 3%% file, You can obtain one at https://mozilla.org/MPL/2.0/. 4%% 5%% Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. 6%% 7 8-module(wildcard). 9 10-export([match/2]). 11 12-spec match(Subject :: binary(), Pattern :: binary()) -> boolean(). 13match(Subject, Pattern) -> 14 case parse_pattern(Pattern) of 15 [First | Rest] -> 16 FirstSize = byte_size(First), 17 case Subject of 18 % If a pattern does not start with a wildcard, 19 % do exact matching in the beginning of the subject 20 <<First:FirstSize/binary, _/binary>> -> 21 scan(Subject, Rest, FirstSize, byte_size(Subject)); 22 _ -> false 23 end; 24 invalid -> false 25 end. 26 27-spec scan(Subject :: binary(), Pattern :: [binary()], 28 Pos :: integer(), Length :: integer()) -> boolean(). 29% Pattern ends with a wildcard 30scan(_Subject, [<<>>], _Pos, _Length) -> true; 31% Pattern is complete. Subject scan is complete 32scan(_Subject, [], Length, Length) -> true; 33% No more pattern but subject scan is not complete 34scan(_Subject, [], Pos, Length) when Pos =/= Length -> false; 35% Subject scan is complete but there are more pattern elements 36scan(_Subject, _NonEmpty, Length, Length) -> false; 37% Skip duplicate wildcards 38scan(Subject, [<<>> | Rest], Pos, Length) -> 39 scan(Subject, Rest, Pos, Length); 40% Every other Part is after a wildcard 41scan(Subject, [Part | Rest], Pos, Length) -> 42 PartSize = byte_size(Part), 43 case binary:match(Subject, Part, [{scope, {Pos, Length - Pos}}]) of 44 nomatch -> false; 45 {PartPos, PartSize} -> 46 NewPos = PartPos + PartSize, 47 scan(Subject, Rest, NewPos, Length) 48 end. 49 50-spec parse_pattern(binary()) -> [binary()] | invalid. 51parse_pattern(Pattern) -> 52 Parts = binary:split(Pattern, <<"*">>, [global]), 53 try lists:map(fun(Part) -> cow_qs:urldecode(Part) end, Parts) 54 catch Type:Error -> 55 rabbit_log:warning("Invalid pattern ~p : ~p", 56 [Pattern, {Type, Error}]), 57 invalid 58 end. 59