aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2017-11-02 08:22:34 +0100
committerErlang/OTP <[email protected]>2017-11-02 08:22:34 +0100
commitd8f7b40f0d8ea8ede5bf1538a1bdc4928e9989f1 (patch)
tree7e9b456cba610151fcffe934023094dfe28dec9a
parenta98379d0519c28f9bc9b673ed2c09fb1ad52456e (diff)
parent25112441ccfb14040a977042d6333e42df7d234f (diff)
downloadotp-d8f7b40f0d8ea8ede5bf1538a1bdc4928e9989f1.tar.gz
otp-d8f7b40f0d8ea8ede5bf1538a1bdc4928e9989f1.tar.bz2
otp-d8f7b40f0d8ea8ede5bf1538a1bdc4928e9989f1.zip
Merge branch 'ingela/inets/maint/httpd-location-chunk-and-close/OTP-14716/OTP-14656/OTP-14696' into maint-20
* ingela/inets/maint/httpd-location-chunk-and-close/OTP-14716/OTP-14656/OTP-14696: inets: Prepare for release inets: httpd - Fix broken handling of POST requests inets: Make sure httpd:stop_service is synchronous inets: httpd - do not hardcode 302 status for location
-rw-r--r--lib/inets/src/http_server/httpd.erl9
-rw-r--r--lib/inets/src/http_server/httpd_esi.erl25
-rw-r--r--lib/inets/src/http_server/httpd_example.erl5
-rw-r--r--lib/inets/src/http_server/httpd_request.erl4
-rw-r--r--lib/inets/src/http_server/httpd_request_handler.erl11
-rw-r--r--lib/inets/src/http_server/mod_esi.erl88
-rw-r--r--lib/inets/test/http_format_SUITE.erl2
-rw-r--r--lib/inets/test/httpd_SUITE.erl17
-rw-r--r--lib/inets/test/httpd_mod.erl7
-rw-r--r--lib/inets/test/inets_SUITE.erl2
-rw-r--r--lib/inets/vsn.mk2
11 files changed, 95 insertions, 77 deletions
diff --git a/lib/inets/src/http_server/httpd.erl b/lib/inets/src/http_server/httpd.erl
index 0b632d24e3..540e68e749 100644
--- a/lib/inets/src/http_server/httpd.erl
+++ b/lib/inets/src/http_server/httpd.erl
@@ -99,7 +99,14 @@ start_service(Conf) ->
stop_service({Address, Port}) ->
stop_service({Address, Port, ?DEFAULT_PROFILE});
stop_service({Address, Port, Profile}) ->
- httpd_sup:stop_child(Address, Port, Profile);
+ Name = httpd_util:make_name("httpd_instance_sup", Address, Port, Profile),
+ Pid = whereis(Name),
+ MonitorRef = erlang:monitor(process, Pid),
+ Result = httpd_sup:stop_child(Address, Port, Profile),
+ receive
+ {'DOWN', MonitorRef, _, _, _} ->
+ Result
+ end;
stop_service(Pid) when is_pid(Pid) ->
case service_info(Pid) of
{ok, Info} ->
diff --git a/lib/inets/src/http_server/httpd_esi.erl b/lib/inets/src/http_server/httpd_esi.erl
index 9406b47802..fd50934d00 100644
--- a/lib/inets/src/http_server/httpd_esi.erl
+++ b/lib/inets/src/http_server/httpd_esi.erl
@@ -66,7 +66,7 @@ handle_headers("") ->
{ok, [], 200};
handle_headers(Headers) ->
NewHeaders = string:tokens(Headers, ?CRLF),
- handle_headers(NewHeaders, [], 200).
+ handle_headers(NewHeaders, [], 200, true).
%%%========================================================================
%%% Internal functions
@@ -80,21 +80,17 @@ parse_headers([?CR, ?LF, ?CR, ?LF | Rest], Acc) ->
parse_headers([Char | Rest], Acc) ->
parse_headers(Rest, [Char | Acc]).
-handle_headers([], NewHeaders, StatusCode) ->
+handle_headers([], NewHeaders, StatusCode, _) ->
{ok, NewHeaders, StatusCode};
-handle_headers([Header | Headers], NewHeaders, StatusCode) ->
+handle_headers([Header | Headers], NewHeaders, StatusCode, NoESIStatus) ->
{FieldName, FieldValue} = httpd_response:split_header(Header, []),
case FieldName of
"location" ->
- case http_request:is_absolut_uri(FieldValue) of
- true ->
- handle_headers(Headers,
- [{FieldName, FieldValue} | NewHeaders],
- 302);
- false ->
- {proceed, FieldValue}
- end;
+ handle_headers(Headers,
+ [{FieldName, FieldValue} | NewHeaders],
+ 302, NoESIStatus);
+
"status" ->
NewStatusCode =
case httpd_util:split(FieldValue," ",2) of
@@ -103,8 +99,9 @@ handle_headers([Header | Headers], NewHeaders, StatusCode) ->
_ ->
200
end,
- handle_headers(Headers, NewHeaders, NewStatusCode);
+ handle_headers(Headers, NewHeaders, NewStatusCode, false);
_ ->
handle_headers(Headers,
- [{FieldName, FieldValue}| NewHeaders], StatusCode)
- end.
+ [{FieldName, FieldValue}| NewHeaders], StatusCode,
+ NoESIStatus)
+ end.
diff --git a/lib/inets/src/http_server/httpd_example.erl b/lib/inets/src/http_server/httpd_example.erl
index 45b6deba97..adbbf64685 100644
--- a/lib/inets/src/http_server/httpd_example.erl
+++ b/lib/inets/src/http_server/httpd_example.erl
@@ -20,7 +20,7 @@
%%
-module(httpd_example).
-export([print/1]).
--export([get/2, put/2, post/2, yahoo/2, test1/2, get_bin/2, peer/2]).
+-export([get/2, put/2, post/2, yahoo/2, test1/2, get_bin/2, peer/2,new_status_and_location/2]).
-export([newformat/3, post_chunked/3]).
%% These are used by the inets test-suite
@@ -90,6 +90,9 @@ post(Env,Input) ->
yahoo(_Env,_Input) ->
"Location: http://www.yahoo.com\r\n\r\n".
+new_status_and_location(_Env,_Input) ->
+ "status:201\r\n Location: http://www.yahoo.com\r\n\r\n".
+
default(Env,Input) ->
[header(),
top("Default Example"),
diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl
index 0eaf073255..007d272323 100644
--- a/lib/inets/src/http_server/httpd_request.erl
+++ b/lib/inets/src/http_server/httpd_request.erl
@@ -306,10 +306,10 @@ add_chunk([<<>>, Body, Length, MaxChunk]) ->
add_chunk([More, Body, Length, MaxChunk]) ->
body_chunk(<<Body/binary, More/binary>>, Length, MaxChunk).
-body_chunk(<<>> = Body, Length, MaxChunk) ->
- {ok, {continue, ?MODULE, add_chunk, [Body, Length, MaxChunk]}};
body_chunk(Body, Length, nolimit) ->
whole_body(Body, Length);
+body_chunk(<<>> = Body, Length, MaxChunk) ->
+ {ok, {continue, ?MODULE, add_chunk, [Body, Length, MaxChunk]}};
body_chunk(Body, Length, MaxChunk) when Length > MaxChunk ->
case size(Body) >= MaxChunk of
diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl
index bd4fdd3832..d918f10424 100644
--- a/lib/inets/src/http_server/httpd_request_handler.erl
+++ b/lib/inets/src/http_server/httpd_request_handler.erl
@@ -516,6 +516,15 @@ handle_body(#state{headers = Headers, body = Body,
case ((Length =< MaxBodySize) or (MaxBodySize == nolimit)) of
true ->
case httpd_request:body_chunk_first(Body, Length, MaxChunk) of
+ %% This is the case that the we need more data to complete
+ %% the body but chunking to the mod_esi user is not enabled.
+ {Module, add_chunk = Function, Args} ->
+ http_transport:setopts(ModData#mod.socket_type,
+ ModData#mod.socket,
+ [{active, once}]),
+ {noreply, State#state{mfa =
+ {Module, Function, Args}}};
+ %% Chunking to mod_esi user is enabled
{ok, {continue, Module, Function, Args}} ->
http_transport:setopts(ModData#mod.socket_type,
ModData#mod.socket,
@@ -525,6 +534,8 @@ handle_body(#state{headers = Headers, body = Body,
{ok, {{continue, Chunk}, Module, Function, Args}} ->
handle_internal_chunk(State#state{chunk = chunk_start(MaxChunk),
body = Chunk}, Module, Function, Args);
+ %% Whole body delivered, if chunking mechanism is enabled the whole
+ %% body fits in one chunk.
{ok, NewBody} ->
handle_response(State#state{chunk = chunk_finish(ChunkState,
CbState, MaxChunk),
diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl
index 3a589ca5f0..3206d957d9 100644
--- a/lib/inets/src/http_server/mod_esi.erl
+++ b/lib/inets/src/http_server/mod_esi.erl
@@ -339,26 +339,21 @@ erl_scheme_webpage_whole(Mod, Func, Env, Input, ModData) ->
{Headers, Body} =
httpd_esi:parse_headers(lists:flatten(Response)),
Length = httpd_util:flatlength(Body),
- case httpd_esi:handle_headers(Headers) of
- {proceed, AbsPath} ->
- {proceed, [{real_name, httpd_util:split_path(AbsPath)}
- | ModData#mod.data]};
- {ok, NewHeaders, StatusCode} ->
- send_headers(ModData, StatusCode,
- [{"content-length",
- integer_to_list(Length)}| NewHeaders]),
- case ModData#mod.method of
- "HEAD" ->
- {proceed, [{response, {already_sent, 200, 0}} |
- ModData#mod.data]};
- _ ->
- httpd_response:send_body(ModData,
- StatusCode, Body),
- {proceed, [{response, {already_sent, 200,
- Length}} |
- ModData#mod.data]}
- end
- end
+ {ok, NewHeaders, StatusCode} = httpd_esi:handle_headers(Headers),
+ send_headers(ModData, StatusCode,
+ [{"content-length",
+ integer_to_list(Length)}| NewHeaders]),
+ case ModData#mod.method of
+ "HEAD" ->
+ {proceed, [{response, {already_sent, 200, 0}} |
+ ModData#mod.data]};
+ _ ->
+ httpd_response:send_body(ModData,
+ StatusCode, Body),
+ {proceed, [{response, {already_sent, 200,
+ Length}} |
+ ModData#mod.data]}
+ end
end.
%% New API that allows the dynamic wepage to be sent back to the client
@@ -398,29 +393,23 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) ->
{continue, _} = Continue ->
Continue;
{Headers, Body} ->
- case httpd_esi:handle_headers(Headers) of
- {proceed, AbsPath} ->
- {proceed, [{real_name, httpd_util:split_path(AbsPath)}
- | ModData#mod.data]};
- {ok, NewHeaders, StatusCode} ->
- IsDisableChunkedSend =
- httpd_response:is_disable_chunked_send(Db),
- case (ModData#mod.http_version =/= "HTTP/1.1") or
- (IsDisableChunkedSend) of
- true ->
- send_headers(ModData, StatusCode,
- [{"connection", "close"} |
- NewHeaders]);
- false ->
- send_headers(ModData, StatusCode,
- [{"transfer-encoding",
- "chunked"} | NewHeaders])
- end,
- handle_body(Pid, ModData, Body, Timeout, length(Body),
- IsDisableChunkedSend)
- end;
- timeout ->
- send_headers(ModData, 504, [{"connection", "close"}]),
+ {ok, NewHeaders, StatusCode} = httpd_esi:handle_headers(Headers),
+ IsDisableChunkedSend = httpd_response:is_disable_chunked_send(Db),
+ case (ModData#mod.http_version =/= "HTTP/1.1") or
+ (IsDisableChunkedSend) of
+ true ->
+ send_headers(ModData, StatusCode,
+ [{"connection", "close"} |
+ NewHeaders]);
+ false ->
+ send_headers(ModData, StatusCode,
+ [{"transfer-encoding",
+ "chunked"} | NewHeaders])
+ end,
+ handle_body(Pid, ModData, Body, Timeout, length(Body),
+ IsDisableChunkedSend);
+ timeout ->
+ send_headers(ModData, 504, [{"connection", "close"}]),
httpd_socket:close(ModData#mod.socket_type, ModData#mod.socket),
{proceed,[{response, {already_sent, 200, 0}} | ModData#mod.data]}
end.
@@ -560,15 +549,10 @@ eval(#mod{method = Method} = ModData, ESIBody, Modules)
{ok, Response} ->
{Headers, _} =
httpd_esi:parse_headers(lists:flatten(Response)),
- case httpd_esi:handle_headers(Headers) of
- {ok, _, StatusCode} ->
- {proceed,[{response, {StatusCode, Response}} |
- ModData#mod.data]};
- {proceed, AbsPath} ->
- {proceed, [{real_name, AbsPath} |
- ModData#mod.data]}
- end
- end;
+ {ok, _, StatusCode} =httpd_esi:handle_headers(Headers),
+ {proceed,[{response, {StatusCode, Response}} |
+ ModData#mod.data]}
+ end;
false ->
{proceed,[{status,
{403, ModData#mod.request_uri,
diff --git a/lib/inets/test/http_format_SUITE.erl b/lib/inets/test/http_format_SUITE.erl
index 4e10a97f58..9a13ed3d17 100644
--- a/lib/inets/test/http_format_SUITE.erl
+++ b/lib/inets/test/http_format_SUITE.erl
@@ -535,7 +535,7 @@ esi_parse_headers(Config) when is_list(Config) ->
{"location","http://foo.bar.se"}], 302} =
httpd_esi:handle_headers(Headers2),
- {proceed,"/foo/bar.html"} =
+ {ok,[{"location","/foo/bar.html"}], 302} =
httpd_esi:handle_headers("location:/foo/bar.html\r\n").
%%--------------------------------------------------------------------
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index 6c8728470b..0c649d9abf 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -129,7 +129,7 @@ groups() ->
{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()},
+ esi_put, esi_post] ++ http_head() ++ http_get() ++ load()},
{http_1_0, [], [host, cgi, trace] ++ http_head() ++ http_get() ++ load()},
{http_0_9, [], http_head() ++ http_get() ++ load()}
].
@@ -932,7 +932,20 @@ esi_put() ->
esi_put(Config) when is_list(Config) ->
ok = http_status("PUT /cgi-bin/erl/httpd_example/put/123342234123 ",
Config, [{statuscode, 200}]).
-
+%%-------------------------------------------------------------------------
+esi_post() ->
+ [{doc, "Test mod_esi POST"}].
+
+esi_post(Config) when is_list(Config) ->
+ Chunk = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
+ Data = lists:duplicate(10000, Chunk),
+ Length = lists:flatlength(Data),
+ ok = http_status("POST /cgi-bin/erl/httpd_example/post ",
+ {"Content-Length:" ++ integer_to_list(Length) ++ "\r\n",
+ Data},
+ [{http_version, "HTTP/1.1"} |Config],
+ [{statuscode, 200}]).
+
%%-------------------------------------------------------------------------
mod_esi_chunk_timeout(Config) when is_list(Config) ->
ok = httpd_1_1:mod_esi_chunk_timeout(proplists:get_value(type, Config),
diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl
index d9118aa1a4..2035b50248 100644
--- a/lib/inets/test/httpd_mod.erl
+++ b/lib/inets/test/httpd_mod.erl
@@ -779,9 +779,14 @@ esi(Type, Port, Host, Node) ->
[{statuscode, 200},
{no_header, "cache-control"},
{version, "HTTP/1.0"}]),
+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
+ "GET /cgi-bin/erl/httpd_example:new_status_and_location"
+ " HTTP/1.1\r\n\r\n",
+ [{statuscode, 201},
+ {header, "Location"},
+ {version, "HTTP/1.1"}]),
ok.
-
%%--------------------------------------------------------------------
get(Type, Port, Host, Node) ->
ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
diff --git a/lib/inets/test/inets_SUITE.erl b/lib/inets/test/inets_SUITE.erl
index 38b8229389..1abd96a228 100644
--- a/lib/inets/test/inets_SUITE.erl
+++ b/lib/inets/test/inets_SUITE.erl
@@ -213,7 +213,6 @@ start_httpd(Config) when is_list(Config) ->
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} =
@@ -222,7 +221,6 @@ start_httpd(Config) when is_list(Config) ->
true = lists:member(Pid0b, Pids0b),
[_|_] = inets:services_info(),
inets:stop(httpd, Pid0b),
- ct:sleep(500),
Pids1 = [ServicePid || {_, ServicePid} <- inets:services()],
false = lists:member(Pid0b, Pids1),
{ok, Pid1} =
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 34b6902747..108d259823 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 6.4.2
+INETS_VSN = 6.4.3
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"