Unquote basic auth username and password (#5)
Unquote username and password which were parsed by ibrowse_lib:parse_url/1 before inserting them in the basic auth header.
Previously if the user had characters like @ in their username or password, and they were percent-encoded, they were inserted encoded in the basic auth header which lead to authentication failure.
diff --git a/src/ibrowse_http_client.erl b/src/ibrowse_http_client.erl
index bee6a70..e3bc698 100644
--- a/src/ibrowse_http_client.erl
+++ b/src/ibrowse_http_client.erl
@@ -1066,7 +1066,9 @@
[{"Authorization", ["Basic ", http_auth_basic(U, P)]} | Headers]
end;
_ ->
- [{"Authorization", ["Basic ", http_auth_basic(User, UPw)]} | Headers]
+ User1 = ibrowse_lib:unquote(User),
+ UPw1 = ibrowse_lib:unquote(UPw),
+ [{"Authorization", ["Basic ", http_auth_basic(User1, UPw1)]} | Headers]
end,
add_proxy_auth_headers(State, Headers_1).
diff --git a/src/ibrowse_lib.erl b/src/ibrowse_lib.erl
index 6c1883d..581ebfd 100644
--- a/src/ibrowse_lib.erl
+++ b/src/ibrowse_lib.erl
@@ -30,9 +30,14 @@
get_value/3,
parse_url/1,
printable_date/0,
- printable_date/1
+ unquote/1
]).
+-define(PERCENT, 37). % $\%
+-define(IS_HEX(C), ((C >= $0 andalso C =< $9) orelse
+ (C >= $a andalso C =< $f) orelse
+ (C >= $A andalso C =< $F))).
+
get_trace_status(Host, Port) ->
ibrowse:get_config_value({trace, Host, Port}, false).
@@ -389,6 +394,29 @@
$:,
integer_to_list(MicroSecs div 1000)].
+%% @spec unquote(string() | binary()) -> string()
+%% @doc Unquote a URL encoded string.
+unquote(Binary) when is_binary(Binary) ->
+ unquote(binary_to_list(Binary));
+unquote(String) ->
+ qs_revdecode(lists:reverse(String)).
+
+qs_revdecode(S) ->
+ qs_revdecode(S, []).
+
+qs_revdecode([], Acc) ->
+ Acc;
+qs_revdecode([$+ | Rest], Acc) ->
+ qs_revdecode(Rest, [$\s | Acc]);
+qs_revdecode([Lo, Hi, ?PERCENT | Rest], Acc) when ?IS_HEX(Lo), ?IS_HEX(Hi) ->
+ qs_revdecode(Rest, [(unhexdigit(Lo) bor (unhexdigit(Hi) bsl 4)) | Acc]);
+qs_revdecode([C | Rest], Acc) ->
+ qs_revdecode(Rest, [C | Acc]).
+
+unhexdigit(C) when C >= $0, C =< $9 -> C - $0;
+unhexdigit(C) when C >= $a, C =< $f -> C - $a + 10;
+unhexdigit(C) when C >= $A, C =< $F -> C - $A + 10.
+
do_trace(Fmt, Args) ->
do_trace(get(my_trace_flag), Fmt, Args).
@@ -462,4 +490,15 @@
?assertMatch(Expected_result, parse_url(Url))
end, Urls).
--endif.
+unquote_test() ->
+ ?assertEqual("foo bar",
+ unquote("foo+bar")),
+ ?assertEqual("foo bar",
+ unquote("foo%20bar")),
+ ?assertEqual("foo\r\n",
+ unquote("foo%0D%0A")),
+ ?assertEqual("foo\r\n",
+ unquote(<<"foo%0D%0A">>)),
+ ok.
+
+-endif.
\ No newline at end of file