diff options
author | Sverker Eriksson <[email protected]> | 2017-08-30 21:00:35 +0200 |
---|---|---|
committer | Sverker Eriksson <[email protected]> | 2017-08-30 21:00:35 +0200 |
commit | 44a83c8860bbd00878c720a7b9d940b4630bab8a (patch) | |
tree | 101b3c52ec505a94f56c8f70e078ecb8a2e8c6cd /lib/inets/test | |
parent | 7c67bbddb53c364086f66260701bc54a61c9659c (diff) | |
parent | 040bdce67f88d833bfb59adae130a4ffb4c180f0 (diff) | |
download | otp-44a83c8860bbd00878c720a7b9d940b4630bab8a.tar.gz otp-44a83c8860bbd00878c720a7b9d940b4630bab8a.tar.bz2 otp-44a83c8860bbd00878c720a7b9d940b4630bab8a.zip |
Merge tag 'OTP-20.0' into sverker/20/binary_to_atom-utf8-crash/ERL-474/OTP-14590
Diffstat (limited to 'lib/inets/test')
-rw-r--r-- | lib/inets/test/ftp_SUITE.erl | 126 | ||||
-rw-r--r-- | lib/inets/test/ftp_format_SUITE.erl | 13 | ||||
-rw-r--r-- | lib/inets/test/http_format_SUITE.erl | 2 | ||||
-rw-r--r-- | lib/inets/test/httpc_SUITE.erl | 149 | ||||
-rw-r--r-- | lib/inets/test/httpd_1_1.erl | 6 | ||||
-rw-r--r-- | lib/inets/test/httpd_SUITE.erl | 85 | ||||
-rw-r--r-- | lib/inets/test/httpd_basic_SUITE.erl | 15 | ||||
-rw-r--r-- | lib/inets/test/httpd_test_data/server_root/conf/httpd.conf | 4 | ||||
-rw-r--r-- | lib/inets/test/inets_SUITE.erl | 14 | ||||
-rw-r--r-- | lib/inets/test/inets_socketwrap_SUITE.erl | 2 | ||||
-rw-r--r-- | lib/inets/test/inets_sup_SUITE.erl | 38 | ||||
-rw-r--r-- | lib/inets/test/old_httpd_SUITE_data/server_root/conf/httpd.conf | 4 | ||||
-rw-r--r-- | lib/inets/test/uri_SUITE.erl | 106 |
13 files changed, 476 insertions, 88 deletions
diff --git a/lib/inets/test/ftp_SUITE.erl b/lib/inets/test/ftp_SUITE.erl index e2dec0c42a..3dfec01ba2 100644 --- a/lib/inets/test/ftp_SUITE.erl +++ b/lib/inets/test/ftp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. +%% Copyright Ericsson AB 2004-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -93,8 +93,11 @@ ftp_tests()-> append_chunk, recv, recv_3, - recv_bin, + recv_bin, + recv_bin_twice, recv_chunk, + recv_chunk_twice, + recv_chunk_three_times, type, quote, error_elogin, @@ -191,9 +194,22 @@ end_per_suite(Config) -> ok. %%-------------------------------------------------------------------- -init_per_group(_Group, Config) -> Config. - -end_per_group(_Group, Config) -> Config. +init_per_group(Group, Config) when Group == ftps_active, + Group == ftps_passive -> + catch crypto:stop(), + try crypto:start() of + ok -> + Config + catch + _:_ -> + {skip, "Crypto did not start"} + end; + +init_per_group(_Group, Config) -> + Config. + +end_per_group(_Group, Config) -> + Config. %%-------------------------------------------------------------------- init_per_testcase(Case, Config0) -> @@ -533,15 +549,19 @@ append_chunk(Config0) -> recv() -> [{doc, "Receive a file using recv/2"}]. recv(Config0) -> - File = "f_dst.txt", + File1 = "f_dst1.txt", + File2 = "f_dst2.txt", SrcDir = "a_dir", - Contents = <<"ftp_SUITE test ...">>, - Config = set_state([reset, {mkfile,[SrcDir,File],Contents}], Config0), + Contents1 = <<"1 ftp_SUITE test ...">>, + Contents2 = <<"2 ftp_SUITE test ...">>, + Config = set_state([reset, {mkfile,[SrcDir,File1],Contents1}, {mkfile,[SrcDir,File2],Contents2}], Config0), Pid = proplists:get_value(ftp, Config), ok = ftp:cd(Pid, id2ftp(SrcDir,Config)), ok = ftp:lcd(Pid, id2ftp("",Config)), - ok = ftp:recv(Pid, File), - chk_file(File, Contents, Config), + ok = ftp:recv(Pid, File1), + chk_file(File1, Contents1, Config), + ok = ftp:recv(Pid, File2), + chk_file(File2, Contents2, Config), {error,epath} = ftp:recv(Pid, "non_existing_file"), ok. @@ -572,6 +592,25 @@ recv_bin(Config0) -> ok. %%------------------------------------------------------------------------- +recv_bin_twice() -> + [{doc, "Receive two files as a binaries."}]. +recv_bin_twice(Config0) -> + File1 = "f_dst1.txt", + File2 = "f_dst2.txt", + Contents1 = <<"1 ftp_SUITE test ...">>, + Contents2 = <<"2 ftp_SUITE test ...">>, + Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}], Config0), + ct:log("First transfer",[]), + Pid = proplists:get_value(ftp, Config), + {ok,Received1} = ftp:recv_bin(Pid, id2ftp(File1,Config)), + find_diff(Received1, Contents1), + ct:log("Second transfer",[]), + {ok,Received2} = ftp:recv_bin(Pid, id2ftp(File2,Config)), + find_diff(Received2, Contents2), + ct:log("Transfers ready!",[]), + {error,epath} = ftp:recv_bin(Pid, id2ftp("non_existing_file",Config)), + ok. +%%------------------------------------------------------------------------- recv_chunk() -> [{doc, "Receive a file using chunk-wise."}]. recv_chunk(Config0) -> @@ -584,13 +623,74 @@ recv_chunk(Config0) -> {ok, ReceivedContents, _Ncunks} = recv_chunk(Pid, <<>>), find_diff(ReceivedContents, Contents). +recv_chunk_twice() -> + [{doc, "Receive two files using chunk-wise."}]. +recv_chunk_twice(Config0) -> + File1 = "big_file1.txt", + File2 = "big_file2.txt", + Contents1 = list_to_binary( lists:duplicate(1000, lists:seq(0,255)) ), + Contents2 = crypto:strong_rand_bytes(1200), + Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}], Config0), + Pid = proplists:get_value(ftp, Config), + {{error, "ftp:recv_chunk_start/2 not called"},_} = recv_chunk(Pid, <<>>), + ok = ftp:recv_chunk_start(Pid, id2ftp(File1,Config)), + {ok, ReceivedContents1, _Ncunks1} = recv_chunk(Pid, <<>>), + ok = ftp:recv_chunk_start(Pid, id2ftp(File2,Config)), + {ok, ReceivedContents2, _Ncunks2} = recv_chunk(Pid, <<>>), + find_diff(ReceivedContents1, Contents1), + find_diff(ReceivedContents2, Contents2). + +recv_chunk_three_times() -> + [{doc, "Receive two files using chunk-wise."}, + {timetrap,{seconds,120}}]. +recv_chunk_three_times(Config0) -> + File1 = "big_file1.txt", + File2 = "big_file2.txt", + File3 = "big_file3.txt", + Contents1 = list_to_binary( lists:duplicate(1000, lists:seq(0,255)) ), + Contents2 = crypto:strong_rand_bytes(1200), + Contents3 = list_to_binary( lists:duplicate(1000, lists:seq(255,0,-1)) ), + + Config = set_state([reset, {mkfile,File1,Contents1}, {mkfile,File2,Contents2}, {mkfile,File3,Contents3}], Config0), + Pid = proplists:get_value(ftp, Config), + {{error, "ftp:recv_chunk_start/2 not called"},_} = recv_chunk(Pid, <<>>), + + ok = ftp:recv_chunk_start(Pid, id2ftp(File1,Config)), + {ok, ReceivedContents1, Nchunks1} = recv_chunk(Pid, <<>>), + + ok = ftp:recv_chunk_start(Pid, id2ftp(File2,Config)), + {ok, ReceivedContents2, _Nchunks2} = recv_chunk(Pid, <<>>), + + ok = ftp:recv_chunk_start(Pid, id2ftp(File3,Config)), + {ok, ReceivedContents3, _Nchunks3} = recv_chunk(Pid, <<>>, 10000, 0, Nchunks1), + + find_diff(ReceivedContents1, Contents1), + find_diff(ReceivedContents2, Contents2), + find_diff(ReceivedContents3, Contents3). + + + recv_chunk(Pid, Acc) -> - recv_chunk(Pid, Acc, 0). + recv_chunk(Pid, Acc, 0, 0, undefined). + + + +%% ExpectNchunks :: integer() | undefined +recv_chunk(Pid, Acc, DelayMilliSec, N, ExpectNchunks) when N+1 < ExpectNchunks -> + %% for all I in integer(), I < undefined + recv_chunk1(Pid, Acc, DelayMilliSec, N, ExpectNchunks); + +recv_chunk(Pid, Acc, DelayMilliSec, N, ExpectNchunks) -> + %% N >= ExpectNchunks-1 + timer:sleep(DelayMilliSec), + recv_chunk1(Pid, Acc, DelayMilliSec, N, ExpectNchunks). + -recv_chunk(Pid, Acc, N) -> +recv_chunk1(Pid, Acc, DelayMilliSec, N, ExpectNchunks) -> + ct:log("Call ftp:recv_chunk",[]), case ftp:recv_chunk(Pid) of ok -> {ok, Acc, N}; - {ok, Bin} -> recv_chunk(Pid, <<Acc/binary, Bin/binary>>, N+1); + {ok, Bin} -> recv_chunk(Pid, <<Acc/binary, Bin/binary>>, DelayMilliSec, N+1, ExpectNchunks); Error -> {Error, N} end. diff --git a/lib/inets/test/ftp_format_SUITE.erl b/lib/inets/test/ftp_format_SUITE.erl index a33b31f46f..95d594a44b 100644 --- a/lib/inets/test/ftp_format_SUITE.erl +++ b/lib/inets/test/ftp_format_SUITE.erl @@ -38,8 +38,8 @@ all() -> groups() -> [{ftp_response, [], [ftp_150, ftp_200, ftp_220, ftp_226, ftp_257, ftp_331, - ftp_425, ftp_other_status_codes, ftp_multiple_lines, - ftp_multipel_ctrl_messages]}]. + ftp_425, ftp_other_status_codes, ftp_multiple_lines_status_in_msg, + ftp_multiple_lines, ftp_multipel_ctrl_messages]}]. init_per_suite(Config) -> Config. @@ -141,6 +141,15 @@ ftp_425(Config) when is_list(Config) -> {trans_neg_compl, _} = ftp_response:interpret(Msg), ok. +ftp_multiple_lines_status_in_msg() -> + [{doc, "check that multiple lines gets parsed correct, even if we have " + " the status code within the msg being sent"}]. +ftp_multiple_lines_status_in_msg(Config) when is_list(Config) -> + ML = "230-User usr-230 is logged in\r\n" ++ + "230 OK. Current directory is /\r\n", + {ok, ML, <<>>} = ftp_response:parse_lines(list_to_binary(ML), [], start), + ok. + ftp_multiple_lines() -> [{doc, "Especially check multiple lines devided in significant places"}]. ftp_multiple_lines(Config) when is_list(Config) -> diff --git a/lib/inets/test/http_format_SUITE.erl b/lib/inets/test/http_format_SUITE.erl index a2b463e98c..4e10a97f58 100644 --- a/lib/inets/test/http_format_SUITE.erl +++ b/lib/inets/test/http_format_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2015. All Rights Reserved. +%% Copyright Ericsson AB 2004-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 932567ec55..e6dcd2285f 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2015. All Rights Reserved. +%% Copyright Ericsson AB 2004-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -88,7 +88,8 @@ real_requests()-> stream_through_mfa, streaming_error, inet_opts, - invalid_headers + invalid_headers, + invalid_body ]. only_simulated() -> @@ -107,6 +108,7 @@ only_simulated() -> tolerate_missing_CR, userinfo, bad_response, + timeout_redirect, internal_server_error, invalid_http, invalid_chunk_size, @@ -125,7 +127,9 @@ only_simulated() -> redirect_see_other, redirect_temporary_redirect, port_in_host_header, - relaxed + redirect_port_in_host_header, + relaxed, + multipart_chunks ]. misc() -> @@ -160,21 +164,17 @@ init_per_group(misc = Group, Config) -> ok = httpc:set_options([{ipfamily, Inet}]), Config; + init_per_group(Group, Config0) when Group =:= sim_https; Group =:= https-> - ct:timetrap({seconds, 30}), - start_apps(Group), - StartSsl = try ssl:start() + catch crypto:stop(), + try crypto:start() of + ok -> + ct:timetrap({seconds, 30}), + start_apps(Group), + do_init_per_group(Group, Config0) catch - Error:Reason -> - {skip, lists:flatten(io_lib:format("Failed to start apps for https Error=~p Reason=~p", [Error, Reason]))} - end, - case StartSsl of - {error, {already_started, _}} -> - do_init_per_group(Group, Config0); - ok -> - do_init_per_group(Group, Config0); - _ -> - StartSsl + _:_ -> + {skip, "Crypto did not start"} end; init_per_group(Group, Config0) -> @@ -500,10 +500,11 @@ redirect_multiple_choises(Config) when is_list(Config) -> httpc:request(get, {URL300, []}, [{autoredirect, false}], []). %%------------------------------------------------------------------------- redirect_moved_permanently() -> - [{doc, "If the 301 status code is received in response to a request other " - "than GET or HEAD, the user agent MUST NOT automatically redirect the request " - "unless it can be confirmed by the user, since this might change " - "the conditions under which the request was issued."}]. + [{doc, "The server SHOULD generate a Location header field in the response " + "containing a preferred URI reference for the new permanent URI. The user " + "agent MAY use the Location field value for automatic redirection. The server's " + "response payload usually contains a short hypertext note with a " + "hyperlink to the new URI(s)."}]. redirect_moved_permanently(Config) when is_list(Config) -> URL301 = url(group_name(Config), "/301.html", Config), @@ -514,15 +515,16 @@ redirect_moved_permanently(Config) when is_list(Config) -> {ok, {{_,200,_}, [_ | _], []}} = httpc:request(head, {URL301, []}, [], []), - {ok, {{_,301,_}, [_ | _], [_|_]}} + {ok, {{_,200,_}, [_ | _], [_|_]}} = httpc:request(post, {URL301, [],"text/plain", "foobar"}, [], []). %%------------------------------------------------------------------------- redirect_found() -> - [{doc," If the 302 status code is received in response to a request other " - "than GET or HEAD, the user agent MUST NOT automatically redirect the " - "request unless it can be confirmed by the user, since this might change " - "the conditions under which the request was issued."}]. + [{doc, "The server SHOULD generate a Location header field in the response " + "containing a URI reference for the different URI. The user agent MAY " + "use the Location field value for automatic redirection. The server's " + "response payload usually contains a short hypertext note with a " + "hyperlink to the different URI(s)."}]. redirect_found(Config) when is_list(Config) -> URL302 = url(group_name(Config), "/302.html", Config), @@ -533,14 +535,14 @@ redirect_found(Config) when is_list(Config) -> {ok, {{_,200,_}, [_ | _], []}} = httpc:request(head, {URL302, []}, [], []), - {ok, {{_,302,_}, [_ | _], [_|_]}} + {ok, {{_,200,_}, [_ | _], [_|_]}} = httpc:request(post, {URL302, [],"text/plain", "foobar"}, [], []). %%------------------------------------------------------------------------- redirect_see_other() -> [{doc, "The different URI SHOULD be given by the Location field in the response. " "Unless the request method was HEAD, the entity of the response SHOULD contain a short " - "hypertext note with a hyperlink to the new URI(s). "}]. + "hypertext note with a hyperlink to the new URI(s)."}]. redirect_see_other(Config) when is_list(Config) -> URL303 = url(group_name(Config), "/303.html", Config), @@ -556,10 +558,11 @@ redirect_see_other(Config) when is_list(Config) -> [], []). %%------------------------------------------------------------------------- redirect_temporary_redirect() -> - [{doc," If the 307 status code is received in response to a request other " - "than GET or HEAD, the user agent MUST NOT automatically redirect the request " - "unless it can be confirmed by the user, since this might change " - "the conditions under which the request was issued."}]. + [{doc, "The server SHOULD generate a Location header field in the response " + "containing a URI reference for the different URI. The user agent MAY " + "use the Location field value for automatic redirection. The server's " + "response payload usually contains a short hypertext note with a " + "hyperlink to the different URI(s)."}]. redirect_temporary_redirect(Config) when is_list(Config) -> URL307 = url(group_name(Config), "/307.html", Config), @@ -570,7 +573,7 @@ redirect_temporary_redirect(Config) when is_list(Config) -> {ok, {{_,200,_}, [_ | _], []}} = httpc:request(head, {URL307, []}, [], []), - {ok, {{_,307,_}, [_ | _], [_|_]}} + {ok, {{_,200,_}, [_ | _], [_|_]}} = httpc:request(post, {URL307, [],"text/plain", "foobar"}, [], []). @@ -783,6 +786,14 @@ bad_response(Config) when is_list(Config) -> ct:print("Wrong Statusline: ~p~n", [Reason]). %%------------------------------------------------------------------------- +timeout_redirect() -> + [{doc, "Test that timeout works for redirects, check ERL-420."}]. +timeout_redirect(Config) when is_list(Config) -> + URL = url(group_name(Config), "/redirect_to_missing_crlf.html", Config), + {error, timeout} = httpc:request(get, {URL, []}, [{timeout, 400}], []). + +%%------------------------------------------------------------------------- + internal_server_error(doc) -> ["Test 50X codes"]; internal_server_error(Config) when is_list(Config) -> @@ -997,10 +1008,25 @@ invalid_headers(Config) -> Request = {url(group_name(Config), "/dummy.html", Config), [{"cookie", undefined}]}, {error, _} = httpc:request(get, Request, [], []). +%%------------------------------------------------------------------------- + +invalid_body(Config) -> + URL = url(group_name(Config), "/dummy.html", Config), + try + httpc:request(post, {URL, [], <<"text/plain">>, "foobar"}, + [], []), + ct:fail(accepted_invalid_input) + catch + error:function_clause -> + ok + end. + +%%------------------------------------------------------------------------- remote_socket_close(Config) when is_list(Config) -> URL = url(group_name(Config), "/just_close.html", Config), {error, socket_closed_remotely} = httpc:request(URL). + %%------------------------------------------------------------------------- remote_socket_close_async(Config) when is_list(Config) -> @@ -1099,8 +1125,21 @@ port_in_host_header(Config) when is_list(Config) -> Request = {url(group_name(Config), "/ensure_host_header_with_port.html", Config), []}, {ok, {{_, 200, _}, _, Body}} = httpc:request(get, Request, [], []), inets_test_lib:check_body(Body). +%%------------------------------------------------------------------------- +redirect_port_in_host_header(Config) when is_list(Config) -> + + Request = {url(group_name(Config), "/redirect_ensure_host_header_with_port.html", Config), []}, + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, Request, [], []), + inets_test_lib:check_body(Body). %%------------------------------------------------------------------------- +multipart_chunks(Config) when is_list(Config) -> + Request = {url(group_name(Config), "/multipart_chunks.html", Config), []}, + {ok, Ref} = httpc:request(get, Request, [], [{sync, false}, {stream, self}]), + ok = receive_stream_n(Ref, 10), + httpc:cancel_request(Ref). + +%%------------------------------------------------------------------------- timeout_memory_leak() -> [{doc, "Check OTP-8739"}]. timeout_memory_leak(Config) when is_list(Config) -> @@ -1395,7 +1434,7 @@ dummy_server(Caller, SocketType, Inet, Extra) -> end. dummy_server_init(Caller, ip_comm, Inet, _) -> - BaseOpts = [binary, {packet, 0}, {reuseaddr,true}, {active, false}], + BaseOpts = [binary, {packet, 0}, {reuseaddr,true}, {keepalive, true}, {active, false}], {ok, ListenSocket} = gen_tcp:listen(0, [Inet | BaseOpts]), {ok, Port} = inet:port(ListenSocket), Caller ! {port, Port}, @@ -1677,6 +1716,12 @@ handle_uri(_,"/ensure_host_header_with_port.html",_,Headers,_,_) -> "HTTP/1.1 500 Internal Server Error\r\n" ++ "Content-Length:" ++ Len ++ "\r\n\r\n" ++ B end; +handle_uri(_,"/redirect_ensure_host_header_with_port.html",Port,_,Socket,_) -> + NewUri = url_start(Socket) ++ + integer_to_list(Port) ++ "/ensure_host_header_with_port.html", + "HTTP/1.1 302 Found \r\n" ++ + "Location:" ++ NewUri ++ "\r\n" ++ + "Content-Length:0\r\n\r\n"; handle_uri(_,"/300.html",Port,_,Socket,_) -> NewUri = url_start(Socket) ++ @@ -1879,6 +1924,16 @@ handle_uri(_,"/missing_crlf.html",_,_,_,_) -> "Content-Length:32\r\n" ++ "<HTML><BODY>foobar</BODY></HTML>"; +handle_uri(_,"/redirect_to_missing_crlf.html",Port,_,Socket,_) -> + NewUri = url_start(Socket) ++ + integer_to_list(Port) ++ "/missing_crlf.html", + Body = "<HTML><BODY><a href=" ++ NewUri ++ + ">New place</a></BODY></HTML>", + "HTTP/1.1 303 See Other \r\n" ++ + "Location:" ++ NewUri ++ "\r\n" ++ + "Content-Length:" ++ integer_to_list(length(Body)) + ++ "\r\n\r\n" ++ Body; + handle_uri(_,"/wrong_statusline.html",_,_,_,_) -> "ok 200 HTTP/1.1\r\n\r\n" ++ "Content-Length:32\r\n\r\n" ++ @@ -1965,6 +2020,16 @@ handle_uri(_,"/missing_CR.html",_,_,_,_) -> "Content-Length:32\r\n\n" ++ "<HTML><BODY>foobar</BODY></HTML>"; +handle_uri(_,"/multipart_chunks.html",_,_,Socket,_) -> + Head = "HTTP/1.1 200 ok\r\n" ++ + "Transfer-Encoding:chunked\r\n" ++ + "Date: " ++ httpd_util:rfc1123_date() ++ "\r\n" + "Connection: Keep-Alive\r\n" ++ + "Content-Type: multipart/x-mixed-replace; boundary=chunk_boundary\r\n" ++ + "\r\n", + send(Socket, Head), + send_multipart_chunks(Socket), + http_chunk:encode_last(); handle_uri("HEAD",_,_,_,_,_) -> "HTTP/1.1 200 ok\r\n" ++ "Content-Length:0\r\n\r\n"; @@ -2261,3 +2326,21 @@ otp_8739_dummy_server_main(_Parent, ListenSocket) -> Error -> exit(Error) end. + +send_multipart_chunks(Socket) -> + send(Socket, http_chunk:encode("--chunk_boundary\r\n")), + send(Socket, http_chunk:encode("Content-Type: text/plain\r\nContent-Length: 4\r\n\r\n")), + send(Socket, http_chunk:encode("test\r\n")), + ct:sleep(500), + send_multipart_chunks(Socket). + +receive_stream_n(_, 0) -> + ok; +receive_stream_n(Ref, N) -> + receive + {http, {Ref, stream_start, _}} -> + receive_stream_n(Ref, N); + {http, {Ref,stream, Data}} -> + ct:pal("Data: ~p", [Data]), + receive_stream_n(Ref, N-1) + end. diff --git a/lib/inets/test/httpd_1_1.erl b/lib/inets/test/httpd_1_1.erl index 3755ed117b..ce9f7acc4d 100644 --- a/lib/inets/test/httpd_1_1.erl +++ b/lib/inets/test/httpd_1_1.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2016. All Rights Reserved. +%% Copyright Ericsson AB 2005-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -405,11 +405,11 @@ getRangeSize(Head)-> {multiPart, BoundaryString}; _X1 -> case re:run(Head, ?CONTENT_RANGE "bytes=.*\r\n", [{capture, first}]) of - {match, [{Start, Lenght}]} -> + {match, [{Start, Length}]} -> %% Get the range data remove the fieldname and the %% end of line. RangeInfo = string:substr(Head, Start + 1 + 20, - Lenght - (20 +2)), + Length - (20 +2)), rangeSize(string:strip(RangeInfo)); _X2 -> error diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index 3194b5ad3d..055b847319 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2015. All Rights Reserved. +%% Copyright Ericsson AB 2013-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -119,8 +119,10 @@ groups() -> ]}, {htaccess, [], [htaccess_1_1, htaccess_1_0, htaccess_0_9]}, {security, [], [security_1_1, security_1_0]}, %% Skip 0.9 as causes timing issus in test code - {http_1_1, [], [host, chunked, expect, cgi, cgi_chunked_encoding_test, - trace, range, if_modified_since, mod_esi_chunk_timeout] ++ http_head() ++ http_get() ++ load()}, + {http_1_1, [], + [host, chunked, expect, cgi, cgi_chunked_encoding_test, + trace, range, if_modified_since, mod_esi_chunk_timeout, + esi_put] ++ http_head() ++ http_get() ++ load()}, {http_1_0, [], [host, cgi, trace] ++ http_head() ++ http_get() ++ load()}, {http_0_9, [], http_head() ++ http_get() ++ load()} ]. @@ -195,7 +197,14 @@ init_per_group(Group, Config0) when Group == https_basic; Group == https_security; Group == https_reload -> - init_ssl(Group, Config0); + catch crypto:stop(), + try crypto:start() of + ok -> + init_ssl(Group, Config0) + catch + _:_ -> + {skip, "Crypto did not start"} + end; init_per_group(Group, Config0) when Group == http_basic; Group == http_limit; Group == http_custom; @@ -230,7 +239,14 @@ init_per_group(https_htaccess = Group, Config) -> Path = proplists:get_value(doc_root, Config), catch remove_htaccess(Path), create_htaccess_data(Path, proplists:get_value(address, Config)), - init_ssl(Group, Config); + catch crypto:stop(), + try crypto:start() of + ok -> + init_ssl(Group, Config) + catch + _:_ -> + {skip, "Crypto did not start"} + end; init_per_group(auth_api, Config) -> [{auth_prefix, ""} | Config]; init_per_group(auth_api_dets, Config) -> @@ -283,20 +299,50 @@ init_per_testcase(Case, Config) when Case == host; Case == trace -> http_1_1 -> httpd_1_1 end, - [{version_cb, Cb} | proplists:delete(version_cb, Config)]; + dbg( + Case, + [{version_cb, Cb} | proplists:delete(version_cb, Config)], + init); init_per_testcase(range, Config) -> ct:timetrap({seconds, 20}), DocRoot = proplists:get_value(doc_root, Config), create_range_data(DocRoot), - Config; + dbg(range, Config, init); -init_per_testcase(_, Config) -> +init_per_testcase(Case, Config) -> ct:timetrap({seconds, 20}), - Config. - -end_per_testcase(_Case, _Config) -> - ok. + dbg(Case, Config, init). + +end_per_testcase(Case, Config) -> + dbg(Case, Config, 'end'). + + +dbg(Case, Config, Status) -> + Cases = [esi_put], + case lists:member(Case, Cases) of + true -> + case Status of + init -> + dbg:tracer(), + dbg:p(all, c), + dbg:tpl(httpd_example, cx), + dbg:tpl(mod_esi, generate_webpage, cx), + io:format("dbg: started~n"), + Config; + 'end' -> + io:format("dbg: stopped~n"), + dbg:stop_clear(), + ok + end; + false -> + case Status of + init -> + Config; + 'end' -> + ok + end + end. %%------------------------------------------------------------------------- %% Test cases starts here. @@ -489,6 +535,9 @@ do_auth_api(AuthPrefix, Config) -> "two", "group1"), add_group_member(Node, ServerRoot, Port, AuthPrefix, "secret", "Aladdin", "group2"), + {ok, Members} = list_group_members(Node, ServerRoot, Port, AuthPrefix, "secret", "group1"), + true = lists:member("one", Members), + true = lists:member("two", Members), ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/", "one", "onePassword", Version, Host), Config, [{statuscode, 200}]), @@ -765,6 +814,14 @@ esi(Config) when is_list(Config) -> ok = http_status("GET /cgi-bin/erl/httpd_example:peer ", Config, [{statuscode, 200}, {header, "peer-cert-exist", peer(Config)}]). + +%%------------------------------------------------------------------------- +esi_put() -> + [{doc, "Test mod_esi PUT"}]. + +esi_put(Config) when is_list(Config) -> + ok = http_status("PUT /cgi-bin/erl/httpd_example/put/123342234123 ", + Config, [{statuscode, 200}]). %%------------------------------------------------------------------------- mod_esi_chunk_timeout(Config) when is_list(Config) -> @@ -2115,6 +2172,10 @@ add_group_member(Node, Root, Port, AuthPrefix, Dir, User, Group) -> Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]), rpc:call(Node, mod_auth, add_group_member, [Group, User, Addr, Port, Directory]). +list_group_members(Node, Root, Port, AuthPrefix, Dir, Group) -> + Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]), + rpc:call(Node, mod_auth, list_group_members, [Group, [{port, Port}, {dir, Directory}]]). + getaddr() -> {ok,HostName} = inet:gethostname(), {ok,{A1,A2,A3,A4}} = inet:getaddr(HostName,inet), diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl index f413248092..931cd076cc 100644 --- a/lib/inets/test/httpd_basic_SUITE.erl +++ b/lib/inets/test/httpd_basic_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2016. All Rights Reserved. +%% Copyright Ericsson AB 2007-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -42,7 +42,8 @@ all() -> escaped_url_in_error_body, script_timeout, slowdose, - keep_alive_timeout + keep_alive_timeout, + invalid_rfc1123_date ]. groups() -> @@ -383,6 +384,16 @@ slowdose(Config) when is_list(Config) -> end. %%------------------------------------------------------------------------- + +invalid_rfc1123_date() -> + [{doc, "Test that a non-DST date is handled correcly"}]. +invalid_rfc1123_date(Config) when is_list(Config) -> + Rfc1123FormattedDate = "Sun, 26 Mar 2017 01:00:00 GMT", + NonDSTDateTime = {{2017, 03, 26},{1, 0, 0}}, + Rfc1123FormattedDate =:= httpd_util:rfc1123_date(NonDSTDateTime). + + +%%------------------------------------------------------------------------- %% Internal functions %%------------------------------------------------------------------------- diff --git a/lib/inets/test/httpd_test_data/server_root/conf/httpd.conf b/lib/inets/test/httpd_test_data/server_root/conf/httpd.conf index 3f9fde03b5..3add93cd73 100644 --- a/lib/inets/test/httpd_test_data/server_root/conf/httpd.conf +++ b/lib/inets/test/httpd_test_data/server_root/conf/httpd.conf @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2016. All Rights Reserved. +# Copyright Ericsson AB 1997-2017. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -128,7 +128,7 @@ SecurityDiskLogSize 200000 10 MaxClients 50 -# KeepAlive set the flag for persistent connections. For peristent connections +# KeepAlive set the flag for persistent connections. For persistent connections # set KeepAlive to on. To use One request per connection set the flag to off # Note: The value has changed since previous version of INETS. KeepAlive on diff --git a/lib/inets/test/inets_SUITE.erl b/lib/inets/test/inets_SUITE.erl index 5eaf3a28a0..38b8229389 100644 --- a/lib/inets/test/inets_SUITE.erl +++ b/lib/inets/test/inets_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2015. All Rights Reserved. +%% Copyright Ericsson AB 1997-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -212,11 +212,19 @@ start_httpd(Config) when is_list(Config) -> Pids0 = [ServicePid || {_, ServicePid} <- inets:services()], true = lists:member(Pid0, Pids0), [_|_] = inets:services_info(), - inets:stop(httpd, Pid0), ct:sleep(500), + Pids1 = [ServicePid || {_, ServicePid} <- inets:services()], + false = lists:member(Pid0, Pids1), + {ok, Pid0b} = + inets:start(httpd, [{port, 0}, {ipfamily, inet6fb4} | HttpdConf]), + Pids0b = [ServicePid || {_, ServicePid} <- inets:services()], + true = lists:member(Pid0b, Pids0b), + [_|_] = inets:services_info(), + inets:stop(httpd, Pid0b), + ct:sleep(500), Pids1 = [ServicePid || {_, ServicePid} <- inets:services()], - false = lists:member(Pid0, Pids1), + false = lists:member(Pid0b, Pids1), {ok, Pid1} = inets:start(httpd, [{port, 0}, {ipfamily, inet} | HttpdConf], stand_alone), diff --git a/lib/inets/test/inets_socketwrap_SUITE.erl b/lib/inets/test/inets_socketwrap_SUITE.erl index 18df995215..7ea7e08ed1 100644 --- a/lib/inets/test/inets_socketwrap_SUITE.erl +++ b/lib/inets/test/inets_socketwrap_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2015. All Rights Reserved. +%% Copyright Ericsson AB 1997-2016. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/lib/inets/test/inets_sup_SUITE.erl b/lib/inets/test/inets_sup_SUITE.erl index 5b8b1463c8..1e664337e6 100644 --- a/lib/inets/test/inets_sup_SUITE.erl +++ b/lib/inets/test/inets_sup_SUITE.erl @@ -33,7 +33,7 @@ suite() -> all() -> [default_tree, ftpc_worker, tftpd_worker, - httpd_subtree, httpd_subtree_profile, + httpd_config, httpd_subtree, httpd_subtree_profile, httpc_subtree]. groups() -> @@ -52,9 +52,32 @@ end_per_suite(_) -> inets:stop(), ok. -init_per_testcase(httpd_subtree, Config) -> +init_per_testcase(httpd_config = TC, Config) -> + PrivDir = proplists:get_value(priv_dir, Config), + Dir = filename:join(PrivDir, TC), + ok = file:make_dir(Dir), + + FallbackConfig = [{port, 0}, + {server_name,"www.test"}, + {modules, [mod_get]}, + {server_root, Dir}, + {document_root, Dir}, + {bind_address, any}, + {ipfamily, inet6fb4}], + try + inets:stop(), + inets:start(), + inets:start(httpd, FallbackConfig), + Config + catch + _:Reason -> + inets:stop(), + exit({failed_starting_inets, Reason}) + end; + +init_per_testcase(httpd_subtree = TC, Config) -> PrivDir = proplists:get_value(priv_dir, Config), - Dir = filename:join(PrivDir, "root"), + Dir = filename:join(PrivDir, TC), ok = file:make_dir(Dir), SimpleConfig = [{port, 0}, @@ -75,9 +98,9 @@ init_per_testcase(httpd_subtree, Config) -> exit({failed_starting_inets, Reason}) end; -init_per_testcase(httpd_subtree_profile, Config) -> +init_per_testcase(httpd_subtree_profile = TC, Config) -> PrivDir = proplists:get_value(priv_dir, Config), - Dir = filename:join(PrivDir, "root"), + Dir = filename:join(PrivDir, TC), ok = file:make_dir(Dir), SimpleConfig = [{port, 0}, @@ -193,6 +216,11 @@ tftpd_worker(Config) when is_list(Config) -> [] = supervisor:which_children(tftp_sup), ok. +httpd_config() -> + [{doc, "Makes sure the httpd config works for inet6fb4."}]. +httpd_config(Config) when is_list(Config) -> + do_httpd_subtree(Config, default). + httpd_subtree() -> [{doc, "Makes sure the httpd sub tree is correct."}]. httpd_subtree(Config) when is_list(Config) -> diff --git a/lib/inets/test/old_httpd_SUITE_data/server_root/conf/httpd.conf b/lib/inets/test/old_httpd_SUITE_data/server_root/conf/httpd.conf index 3f9fde03b5..3add93cd73 100644 --- a/lib/inets/test/old_httpd_SUITE_data/server_root/conf/httpd.conf +++ b/lib/inets/test/old_httpd_SUITE_data/server_root/conf/httpd.conf @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2016. All Rights Reserved. +# Copyright Ericsson AB 1997-2017. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -128,7 +128,7 @@ SecurityDiskLogSize 200000 10 MaxClients 50 -# KeepAlive set the flag for persistent connections. For peristent connections +# KeepAlive set the flag for persistent connections. For persistent connections # set KeepAlive to on. To use One request per connection set the flag to off # Note: The value has changed since previous version of INETS. KeepAlive on diff --git a/lib/inets/test/uri_SUITE.erl b/lib/inets/test/uri_SUITE.erl index b26c645821..3e7799141c 100644 --- a/lib/inets/test/uri_SUITE.erl +++ b/lib/inets/test/uri_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. +%% Copyright Ericsson AB 2004-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ -module(uri_SUITE). +-include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). -include("inets_test_lib.hrl"). @@ -50,7 +51,8 @@ all() -> fragments, escaped, hexed_query, - scheme_validation + scheme_validation, + encode_decode ]. %%-------------------------------------------------------------------- @@ -73,7 +75,10 @@ end_per_testcase(_Case, _Config) -> ipv4(Config) when is_list(Config) -> {ok, {http,[],"127.0.0.1",80,"/foobar.html",[]}} = - http_uri:parse("http://127.0.0.1/foobar.html"). + http_uri:parse("http://127.0.0.1/foobar.html"), + + {ok, {http,<<>>,<<"127.0.0.1">>,80,<<"/foobar.html">>,<<>>}} = + http_uri:parse(<<"http://127.0.0.1/foobar.html">>). ipv6(Config) when is_list(Config) -> {ok, {http,[],"2010:836B:4179::836B:4179",80,"/foobar.html",[]}} = @@ -89,24 +94,52 @@ ipv6(Config) when is_list(Config) -> [{foo, false}]), {error, {malformed_url, _, "http://2010:836B:4179::836B:4179/foobar.html"}} = - http_uri:parse("http://2010:836B:4179::836B:4179/foobar.html"). + http_uri:parse("http://2010:836B:4179::836B:4179/foobar.html"), + + {ok, {http,<<>>,<<"2010:836B:4179::836B:4179">>,80,<<"/foobar.html">>,<<>>}} = + http_uri:parse(<<"http://[2010:836B:4179::836B:4179]/foobar.html">>), + {ok, {http,<<>>,<<"[2010:836B:4179::836B:4179]">>,80,<<"/foobar.html">>,<<>>}} = + http_uri:parse(<<"http://[2010:836B:4179::836B:4179]/foobar.html">>, + [{ipv6_host_with_brackets, true}]), + {ok, {http,<<>>,<<"2010:836B:4179::836B:4179">>,80,<<"/foobar.html">>,<<>>}} = + http_uri:parse(<<"http://[2010:836B:4179::836B:4179]/foobar.html">>, + [{ipv6_host_with_brackets, false}]), + {ok, {http,<<>>,<<"2010:836B:4179::836B:4179">>,80,<<"/foobar.html">>,<<>>}} = + http_uri:parse(<<"http://[2010:836B:4179::836B:4179]/foobar.html">>, + [{foo, false}]), + {error, + {malformed_url, _, <<"http://2010:836B:4179::836B:4179/foobar.html">>}} = + http_uri:parse(<<"http://2010:836B:4179::836B:4179/foobar.html">>). host(Config) when is_list(Config) -> {ok, {http,[],"localhost",8888,"/foobar.html",[]}} = - http_uri:parse("http://localhost:8888/foobar.html"). + http_uri:parse("http://localhost:8888/foobar.html"), + + {ok, {http,<<>>,<<"localhost">>,8888,<<"/foobar.html">>,<<>>}} = + http_uri:parse(<<"http://localhost:8888/foobar.html">>). userinfo(Config) when is_list(Config) -> {ok, {http,"nisse:foobar","localhost",8888,"/foobar.html",[]}} = - http_uri:parse("http://nisse:foobar@localhost:8888/foobar.html"). + http_uri:parse("http://nisse:foobar@localhost:8888/foobar.html"), + + {ok, {http,<<"nisse:foobar">>,<<"localhost">>,8888,<<"/foobar.html">>,<<>>}} = + http_uri:parse(<<"http://nisse:foobar@localhost:8888/foobar.html">>). scheme(Config) when is_list(Config) -> {error, no_scheme} = http_uri:parse("localhost/foobar.html"), {error, {malformed_url, _, _}} = - http_uri:parse("localhost:8888/foobar.html"). + http_uri:parse("localhost:8888/foobar.html"), + + {error, no_scheme} = http_uri:parse(<<"localhost/foobar.html">>), + {error, {malformed_url, _, _}} = + http_uri:parse(<<"localhost:8888/foobar.html">>). queries(Config) when is_list(Config) -> {ok, {http,[],"localhost",8888,"/foobar.html","?foo=bar&foobar=42"}} = - http_uri:parse("http://localhost:8888/foobar.html?foo=bar&foobar=42"). + http_uri:parse("http://localhost:8888/foobar.html?foo=bar&foobar=42"), + + {ok, {http,<<>>,<<"localhost">>,8888,<<"/foobar.html">>,<<"?foo=bar&foobar=42">>}} = + http_uri:parse(<<"http://localhost:8888/foobar.html?foo=bar&foobar=42">>). fragments(Config) when is_list(Config) -> {ok, {http,[],"localhost",80,"/",""}} = @@ -142,6 +175,41 @@ fragments(Config) when is_list(Config) -> http_uri:parse("http://localhost?query#", [{fragment,true}]), {ok, {http,[],"localhost",80,"/path","?query","#"}} = http_uri:parse("http://localhost/path?query#", [{fragment,true}]), + + + {ok, {http,<<>>,<<"localhost">>,80,<<"/">>,<<"">>}} = + http_uri:parse(<<"http://localhost#fragment">>), + {ok, {http,<<>>,<<"localhost">>,80,<<"/path">>,<<"">>}} = + http_uri:parse(<<"http://localhost/path#fragment">>), + {ok, {http,<<>>,<<"localhost">>,80,<<"/">>,<<"?query">>}} = + http_uri:parse(<<"http://localhost?query#fragment">>), + {ok, {http,<<>>,<<"localhost">>,80,<<"/path">>,<<"?query">>}} = + http_uri:parse(<<"http://localhost/path?query#fragment">>), + {ok, {http,<<>>,<<"localhost">>,80,<<"/">>,<<"">>,<<"#fragment">>}} = + http_uri:parse(<<"http://localhost#fragment">>, [{fragment,true}]), + {ok, {http,<<>>,<<"localhost">>,80,<<"/path">>,<<"">>,<<"#fragment">>}} = + http_uri:parse(<<"http://localhost/path#fragment">>, [{fragment,true}]), + {ok, {http,<<>>,<<"localhost">>,80,<<"/">>,<<"?query">>,<<"#fragment">>}} = + http_uri:parse(<<"http://localhost?query#fragment">>, [{fragment,true}]), + {ok, {http,<<>>,<<"localhost">>,80,<<"/path">>,<<"?query">>,<<"#fragment">>}} = + http_uri:parse(<<"http://localhost/path?query#fragment">>, + [{fragment,true}]), + {ok, {http,<<>>,<<"localhost">>,80,<<"/">>,<<"">>,<<"">>}} = + http_uri:parse(<<"http://localhost">>, [{fragment,true}]), + {ok, {http,<<>>,<<"localhost">>,80,<<"/path">>,<<"">>,<<"">>}} = + http_uri:parse(<<"http://localhost/path">>, [{fragment,true}]), + {ok, {http,<<>>,<<"localhost">>,80,<<"/">>,<<"?query">>,<<"">>}} = + http_uri:parse(<<"http://localhost?query">>, [{fragment,true}]), + {ok, {http,<<>>,<<"localhost">>,80,<<"/path">>,<<"?query">>,<<"">>}} = + http_uri:parse(<<"http://localhost/path?query">>, [{fragment,true}]), + {ok, {http,<<>>,<<"localhost">>,80,<<"/">>,<<"">>,<<"#">>}} = + http_uri:parse(<<"http://localhost#">>, [{fragment,true}]), + {ok, {http,<<>>,<<"localhost">>,80,<<"/path">>,<<"">>,<<"#">>}} = + http_uri:parse(<<"http://localhost/path#">>, [{fragment,true}]), + {ok, {http,<<>>,<<"localhost">>,80,<<"/">>,<<"?query">>,<<"#">>}} = + http_uri:parse(<<"http://localhost?query#">>, [{fragment,true}]), + {ok, {http,<<>>,<<"localhost">>,80,<<"/path">>,<<"?query">>,<<"#">>}} = + http_uri:parse(<<"http://localhost/path?query#">>, [{fragment,true}]), ok. escaped(Config) when is_list(Config) -> @@ -152,7 +220,16 @@ escaped(Config) when is_list(Config) -> {ok, {http,[],"www.somedomain.com",80,"/%25abc",[]}} = http_uri:parse("http://www.somedomain.com/%25abc"), {ok, {http,[],"www.somedomain.com",80,"/%25abc", "?foo=bar"}} = - http_uri:parse("http://www.somedomain.com/%25abc?foo=bar"). + http_uri:parse("http://www.somedomain.com/%25abc?foo=bar"), + + {ok, {http,<<>>,<<"www.somedomain.com">>,80,<<"/%2Eabc">>,<<>>}} = + http_uri:parse(<<"http://www.somedomain.com/%2Eabc">>), + {ok, {http,<<>>,<<"www.somedomain.com">>,80,<<"/%252Eabc">>,<<>>}} = + http_uri:parse(<<"http://www.somedomain.com/%252Eabc">>), + {ok, {http,<<>>,<<"www.somedomain.com">>,80,<<"/%25abc">>,<<>>}} = + http_uri:parse(<<"http://www.somedomain.com/%25abc">>), + {ok, {http,<<>>,<<"www.somedomain.com">>,80,<<"/%25abc">>, <<"?foo=bar">>}} = + http_uri:parse(<<"http://www.somedomain.com/%25abc?foo=bar">>). hexed_query(doc) -> [{doc, "Solves OTP-6191"}]; @@ -196,6 +273,17 @@ scheme_validation(Config) when is_list(Config) -> http_uri:parse("https://localhost#fragment", [{scheme_validation_fun, none}]). +encode_decode(Config) when is_list(Config) -> + ?assertEqual("foo%20bar", http_uri:encode("foo bar")), + ?assertEqual(<<"foo%20bar">>, http_uri:encode(<<"foo bar">>)), + + ?assertEqual("foo bar", http_uri:decode("foo+bar")), + ?assertEqual(<<"foo bar">>, http_uri:decode(<<"foo+bar">>)), + ?assertEqual("foo bar", http_uri:decode("foo%20bar")), + ?assertEqual(<<"foo bar">>, http_uri:decode(<<"foo%20bar">>)), + ?assertEqual("foo\r\n", http_uri:decode("foo%0D%0A")), + ?assertEqual(<<"foo\r\n">>, http_uri:decode(<<"foo%0D%0A">>)). + %%-------------------------------------------------------------------- %% Internal Functions ------------------------------------------------ |