diff --git a/src/hackney_url.erl b/src/hackney_url.erl index f6a8f481..4675e05f 100644 --- a/src/hackney_url.erl +++ b/src/hackney_url.erl @@ -50,8 +50,7 @@ parse_url(URL, S) -> case binary:split(URL, <<"/">>) of [Addr] -> Path = <<"/">>, - parse_addr(Addr, S#hackney_url{raw_path = Path, - path = Path }); + parse_addr1(Addr, S#hackney_url{raw_path = Path, path = Path }); [Addr, Path] -> RawPath = <<"/", Path/binary>>, {Path1, Query, Fragment} = parse_path(RawPath), @@ -82,7 +81,7 @@ normalize(#hackney_url{}=Url, Fun) when is_function(Fun, 1) -> port = Port, netloc = Netloc0, path = Path} = Url, - + {Host, Netloc} = case inet_parse:address(Host0) of {ok, {_, _, _, _}} -> {Host0, Netloc0}; @@ -91,7 +90,7 @@ normalize(#hackney_url{}=Url, Fun) when is_function(Fun, 1) -> _ -> Host1 = unicode:characters_to_list( urldecode(unicode:characters_to_binary(Host0))), - + %% encode domain if needed Host2 = idna:to_ascii(Host1), Netloc1 = case {Scheme, Port} of @@ -121,13 +120,13 @@ unparse_url(#hackney_url{}=Url) -> fragment = Fragment, user = User, password = Password} = Url, - + Scheme1 = case Scheme of http -> <<"http://">>; https -> <<"https://">>; http_unix -> <<"http+unix://">> end, - + Netloc1 = case User of <<>> -> Netloc; @@ -136,27 +135,39 @@ unparse_url(#hackney_url{}=Url) -> _ -> << User/binary, "@", Netloc/binary >> end, - + Qs1 = case Qs of <<>> -> <<>>; _ -> << "?", Qs/binary >> end, - + Fragment1 = case Fragment of <<>> -> <<>>; _ -> << "#", Fragment/binary >> end, - + Path1 = case Path of nil -> <<>>; undefined -> <<>>; <<>> -> <<"/">>; _ -> Path end, - + << Scheme1/binary, Netloc1/binary, Path1/binary, Qs1/binary, Fragment1/binary >>. %% @private +parse_addr1(Addr, S) -> + case binary:split(Addr, <<"?">>) of + [_Addr] -> + {Addr1, Fragment} = parse_fragment(Addr), + parse_addr(Addr1, S#hackney_url{fragment = Fragment}); + [Addr1, Query] -> + {Query1, Fragment} = parse_fragment(Query), + #hackney_url{raw_path = RawPath0 } = S, + RawPath1 = << RawPath0/binary, "?", Query1/binary >>, + parse_addr(Addr1, S#hackney_url{raw_path=RawPath1, qs=Query1, fragment=Fragment}) + end. + parse_addr(Addr, S) -> case binary:split(Addr, <<"@">>) of [Addr] -> @@ -172,7 +183,7 @@ parse_addr(Addr, S) -> user = User, password = <<>> }) end - + end. parse_netloc(<<"[", Rest/binary>>, #hackney_url{transport=Transport}=S) -> @@ -355,13 +366,13 @@ make_url(Url, PathParts, Query) when is_binary(Query) -> %% create path PathParts1 = [fix_path(P) || P <- PathParts, P /= "", P /= "/" orelse P /= <<"/">>], Path = hackney_bstr:join([<<>> | PathParts1], <<"/">>), - + %% initialise the query Query1 = case Query of <<>> -> <<>>; _ -> << "?", Query/binary >> end, - + %% make the final uri iolist_to_binary([fix_path(Url), Path, Query1]). diff --git a/test/hackney_url_tests.erl b/test/hackney_url_tests.erl index 94526c45..b0fdc125 100644 --- a/test/hackney_url_tests.erl +++ b/test/hackney_url_tests.erl @@ -181,6 +181,19 @@ parse_url_test_() -> port = 80, user = <<"">>, password = <<"">>} + }, + {<<"http://www.example.com?q=123">>, + #hackney_url{transport =hackney_tcp, + scheme = http, + netloc = <<"www.example.com">>, + raw_path = <<"/?q=123">>, + path = <<"/">>, + qs = <<"q=123">>, + fragment = <<"">>, + host = "www.example.com", + port = 80, + user = <<"">>, + password = <<"">>} } ], [{V, fun() -> R = hackney_url:parse_url(V) end} || {V, R} <- Tests].