You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by va...@apache.org on 2021/06/07 17:26:01 UTC

[couchdb-ibrowse] 05/05: Unquote basic auth username and password (#5)

This is an automated email from the ASF dual-hosted git repository.

vatamane pushed a commit to branch upstream-rebase
in repository https://gitbox.apache.org/repos/asf/couchdb-ibrowse.git

commit 16e73e0a9ad7b5fce1a73d322f7fed8b414dcfb6
Author: Jiahui Li <54...@users.noreply.github.com>
AuthorDate: Wed May 5 08:06:49 2021 -0500

    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.
---
 src/ibrowse_http_client.erl |  4 +++-
 src/ibrowse_lib.erl         | 43 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 44 insertions(+), 3 deletions(-)

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 @@ add_auth_headers(#url{username = User,
                                 [{"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 @@ printable_date(Now) ->
      $:,
      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 @@ parse_url_test() ->
               ?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