aboutsummaryrefslogtreecommitdiffstats
path: root/lib/inets/src/http_client
diff options
context:
space:
mode:
Diffstat (limited to 'lib/inets/src/http_client')
-rw-r--r--lib/inets/src/http_client/Makefile1
-rw-r--r--lib/inets/src/http_client/http_uri.erl116
-rw-r--r--lib/inets/src/http_client/httpc.erl51
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl119
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl6
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl9
6 files changed, 105 insertions, 197 deletions
diff --git a/lib/inets/src/http_client/Makefile b/lib/inets/src/http_client/Makefile
index 575c6efaec..0397b48ab2 100644
--- a/lib/inets/src/http_client/Makefile
+++ b/lib/inets/src/http_client/Makefile
@@ -51,7 +51,6 @@ MODULES = \
httpc_profile_sup \
httpc_response \
httpc_request \
- http_uri \
HRL_FILES = httpc_internal.hrl
diff --git a/lib/inets/src/http_client/http_uri.erl b/lib/inets/src/http_client/http_uri.erl
deleted file mode 100644
index 615a0d8ec4..0000000000
--- a/lib/inets/src/http_client/http_uri.erl
+++ /dev/null
@@ -1,116 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(http_uri).
-
--export([parse/1]).
-
-%%%=========================================================================
-%%% API
-%%%=========================================================================
-parse(AbsURI) ->
- case parse_scheme(AbsURI) of
- {error, Reason} ->
- {error, Reason};
- {Scheme, Rest} ->
- case (catch parse_uri_rest(Scheme, Rest)) of
- {UserInfo, Host, Port, Path, Query} ->
- {Scheme, UserInfo, Host, Port, Path, Query};
- _ ->
- {error, {malformed_url, AbsURI}}
- end
- end.
-
-%%%========================================================================
-%%% Internal functions
-%%%========================================================================
-parse_scheme(AbsURI) ->
- case split_uri(AbsURI, ":", {error, no_scheme}, 1, 1) of
- {error, no_scheme} ->
- {error, no_scheme};
- {StrScheme, Rest} ->
- case list_to_atom(http_util:to_lower(StrScheme)) of
- Scheme when Scheme == http; Scheme == https ->
- {Scheme, Rest};
- Scheme ->
- {error, {not_supported_scheme, Scheme}}
- end
- end.
-
-parse_uri_rest(Scheme, "//" ++ URIPart) ->
-
- {Authority, PathQuery} =
- case split_uri(URIPart, "/", URIPart, 1, 0) of
- Split = {_, _} ->
- Split;
- URIPart ->
- case split_uri(URIPart, "\\?", URIPart, 1, 0) of
- Split = {_, _} ->
- Split;
- URIPart ->
- {URIPart,""}
- end
- end,
-
- {UserInfo, HostPort} = split_uri(Authority, "@", {"", Authority}, 1, 1),
- {Host, Port} = parse_host_port(Scheme, HostPort),
- {Path, Query} = parse_path_query(PathQuery),
- {UserInfo, Host, Port, Path, Query}.
-
-
-parse_path_query(PathQuery) ->
- {Path, Query} = split_uri(PathQuery, "\\?", {PathQuery, ""}, 1, 0),
- {path(Path), Query}.
-
-
-parse_host_port(Scheme,"[" ++ HostPort) -> %ipv6
- DefaultPort = default_port(Scheme),
- {Host, ColonPort} = split_uri(HostPort, "\\]", {HostPort, ""}, 1, 1),
- {_, Port} = split_uri(ColonPort, ":", {"", DefaultPort}, 0, 1),
- {Host, int_port(Port)};
-
-parse_host_port(Scheme, HostPort) ->
- DefaultPort = default_port(Scheme),
- {Host, Port} = split_uri(HostPort, ":", {HostPort, DefaultPort}, 1, 1),
- {Host, int_port(Port)}.
-
-split_uri(UriPart, SplitChar, NoMatchResult, SkipLeft, SkipRight) ->
- case inets_regexp:first_match(UriPart, SplitChar) of
- {match, Match, _} ->
- {string:substr(UriPart, 1, Match - SkipLeft),
- string:substr(UriPart, Match + SkipRight, length(UriPart))};
- nomatch ->
- NoMatchResult
- end.
-
-default_port(http) ->
- 80;
-default_port(https) ->
- 443.
-
-int_port(Port) when is_integer(Port) ->
- Port;
-int_port(Port) when is_list(Port) ->
- list_to_integer(Port).
-
-path("") ->
- "/";
-path(Path) ->
- Path.
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index 8cf82df809..7490bb0e46 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -255,7 +255,7 @@ set_option(Key, Value, Profile) ->
%% Description: Store the cookies from <SetCookieHeaders>
%% in the cookie database
%% for the profile <Profile>. This function shall be used when the option
-%% cookie is set to verify.
+%% cookies is set to verify.
%%-------------------------------------------------------------------------
store_cookies(SetCookieHeaders, Url) ->
store_cookies(SetCookieHeaders, Url, default_profile()).
@@ -454,16 +454,21 @@ handle_request(Method, Url,
HeadersRecord = header_record(NewHeaders, Host2, HTTPOptions),
Receiver = proplists:get_value(receiver, Options),
SocketOpts = proplists:get_value(socket_opts, Options),
+ UrlEncodeBool = HTTPOptions#http_options.url_encode,
+ MaybeEscPath = url_encode(Path, UrlEncodeBool),
+ MaybeEscQuery = url_encode(Query, UrlEncodeBool),
+ AbsUri = url_encode(Url, UrlEncodeBool),
+
Request = #request{from = Receiver,
scheme = Scheme,
address = {Host, Port},
- path = Path,
- pquery = Query,
+ path = MaybeEscPath,
+ pquery = MaybeEscQuery,
method = Method,
headers = HeadersRecord,
content = {ContentType, Body},
settings = HTTPOptions,
- abs_uri = Url,
+ abs_uri = AbsUri,
userinfo = UserInfo,
stream = Stream,
headers_as_is = headers_as_is(Headers0, Options),
@@ -483,6 +488,11 @@ handle_request(Method, Url,
Error
end.
+url_encode(URI, true) ->
+ http_uri:encode(URI);
+url_encode(URI, false) ->
+ URI.
+
chunkify_fun(BodyFun) ->
fun(eof_body_fun) ->
eof;
@@ -606,12 +616,8 @@ http_options_default() ->
(_) ->
error
end,
- AutoRedirectPost = fun(Value) when (Value =:= true) orelse
- (Value =:= false) ->
- {ok, Value};
- (_) ->
- error
- end,
+ AutoRedirectPost = boolfun(),
+
SslPost = fun(Value) when is_list(Value) ->
{ok, {?HTTP_DEFAULT_SSL_KIND, Value}};
({ssl, SslOptions}) when is_list(SslOptions) ->
@@ -629,12 +635,8 @@ http_options_default() ->
(_) ->
error
end,
- RelaxedPost = fun(Value) when (Value =:= true) orelse
- (Value =:= false) ->
- {ok, Value};
- (_) ->
- error
- end,
+ RelaxedPost = boolfun(),
+
ConnTimeoutPost =
fun(Value) when is_integer(Value) andalso (Value >= 0) ->
{ok, Value};
@@ -643,6 +645,8 @@ http_options_default() ->
(_) ->
error
end,
+
+ UrlDecodePost = boolfun(),
[
{version, {value, "HTTP/1.1"}, #http_options.version, VersionPost},
{timeout, {value, ?HTTP_REQUEST_TIMEOUT}, #http_options.timeout, TimeoutPost},
@@ -650,18 +654,21 @@ http_options_default() ->
{ssl, {value, {?HTTP_DEFAULT_SSL_KIND, []}}, #http_options.ssl, SslPost},
{proxy_auth, {value, undefined}, #http_options.proxy_auth, ProxyAuthPost},
{relaxed, {value, false}, #http_options.relaxed, RelaxedPost},
+ {url_encode, {value, false}, #http_options.url_encode, UrlDecodePost},
%% this field has to be *after* the timeout option (as that field is used for the default value)
{connect_timeout, {field, #http_options.timeout}, #http_options.connect_timeout, ConnTimeoutPost}
].
+boolfun() ->
+ fun(Value) when (Value =:= true) orelse
+ (Value =:= false) ->
+ {ok, Value};
+ (_) ->
+ error
+ end.
request_options_defaults() ->
- VerifyBoolean =
- fun(Value) when ((Value =:= true) orelse (Value =:= false)) ->
- ok;
- (_) ->
- error
- end,
+ VerifyBoolean = boolfun(),
VerifySync = VerifyBoolean,
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 8af6613fa2..cb6f3e2841 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -713,33 +713,38 @@ terminate(normal,
profile_name = ProfileName,
request = Request,
timers = Timers,
- pipeline = Pipeline}) ->
+ pipeline = Pipeline,
+ keep_alive = KeepAlive} = State) ->
?hcrt("terminate(normal) - remote close",
[{id, Id}, {profile, ProfileName}]),
%% Clobber session
(catch httpc_manager:delete_session(Id, ProfileName)),
+ maybe_retry_queue(Pipeline, State),
+ maybe_retry_queue(KeepAlive, State),
+
%% Cancel timers
- #timers{request_timers = ReqTmrs, queue_timer = QTmr} = Timers,
- cancel_timer(QTmr, timeout_queue),
- lists:foreach(fun({_, Timer}) -> cancel_timer(Timer, timeout) end,
- ReqTmrs),
+ cancel_timers(Timers),
%% Maybe deliver answers to requests
- deliver_answers([Request | queue:to_list(Pipeline)]),
+ deliver_answer(Request),
%% And, just in case, close our side (**really** overkill)
http_transport:close(SocketType, Socket);
-terminate(_, #state{session = #session{id = Id,
- socket = Socket,
- socket_type = SocketType},
+terminate(Reason, #state{session = #session{id = Id,
+ socket = Socket,
+ socket_type = SocketType},
request = undefined,
profile_name = ProfileName,
timers = Timers,
pipeline = Pipeline,
keep_alive = KeepAlive} = State) ->
+ ?hcrt("terminate",
+ [{id, Id}, {profile, ProfileName}, {reason, Reason}]),
+
+ %% Clobber session
(catch httpc_manager:delete_session(Id, ProfileName)),
maybe_retry_queue(Pipeline, State),
@@ -772,59 +777,55 @@ maybe_send_answer(#request{from = answer_sent}, _Reason, State) ->
maybe_send_answer(Request, Answer, State) ->
answer_request(Request, Answer, State).
-deliver_answers([]) ->
- ?hcrd("deliver answer done", []),
- ok;
-deliver_answers([#request{id = Id, from = From} = Request | Requests])
+deliver_answer(#request{id = Id, from = From} = Request)
when is_pid(From) ->
Response = httpc_response:error(Request, socket_closed_remotely),
?hcrd("deliver answer", [{id, Id}, {from, From}, {response, Response}]),
- httpc_response:send(From, Response),
- deliver_answers(Requests);
-deliver_answers([Request|Requests]) ->
+ httpc_response:send(From, Response);
+deliver_answer(Request) ->
?hcrd("skip deliver answer", [{request, Request}]),
- deliver_answers(Requests).
+ ok.
%%--------------------------------------------------------------------
%% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState}
%% Purpose: Convert process state when code is changed
%%--------------------------------------------------------------------
-code_change(_, #state{request = Request, pipeline = Queue} = State,
- [{from, '5.0.1'}, {to, '5.0.2'}]) ->
- Settings = new_http_options(Request#request.settings),
- NewRequest = Request#request{settings = Settings},
- NewQueue = new_queue(Queue, fun new_http_options/1),
- {ok, State#state{request = NewRequest, pipeline = NewQueue}};
-
-code_change(_, #state{request = Request, pipeline = Queue} = State,
- [{from, '5.0.2'}, {to, '5.0.1'}]) ->
- Settings = old_http_options(Request#request.settings),
- NewRequest = Request#request{settings = Settings},
- NewQueue = new_queue(Queue, fun old_http_options/1),
- {ok, State#state{request = NewRequest, pipeline = NewQueue}};
+%% code_change(_, #state{request = Request, pipeline = Queue} = State,
+%% [{from, '5.0.1'}, {to, '5.0.2'}]) ->
+%% Settings = new_http_options(Request#request.settings),
+%% NewRequest = Request#request{settings = Settings},
+%% NewQueue = new_queue(Queue, fun new_http_options/1),
+%% {ok, State#state{request = NewRequest, pipeline = NewQueue}};
+
+%% code_change(_, #state{request = Request, pipeline = Queue} = State,
+%% [{from, '5.0.2'}, {to, '5.0.1'}]) ->
+%% Settings = old_http_options(Request#request.settings),
+%% NewRequest = Request#request{settings = Settings},
+%% NewQueue = new_queue(Queue, fun old_http_options/1),
+%% {ok, State#state{request = NewRequest, pipeline = NewQueue}};
code_change(_, State, _) ->
{ok, State}.
-new_http_options({http_options, TimeOut, AutoRedirect, SslOpts,
- Auth, Relaxed}) ->
- {http_options, "HTTP/1.1", TimeOut, AutoRedirect, SslOpts,
- Auth, Relaxed}.
-
-old_http_options({http_options, _, TimeOut, AutoRedirect,
- SslOpts, Auth, Relaxed}) ->
- {http_options, TimeOut, AutoRedirect, SslOpts, Auth, Relaxed}.
-
-new_queue(Queue, Fun) ->
- List = queue:to_list(Queue),
- NewList =
- lists:map(fun(Request) ->
- Settings =
- Fun(Request#request.settings),
- Request#request{settings = Settings}
- end, List),
- queue:from_list(NewList).
+%% new_http_options({http_options, TimeOut, AutoRedirect, SslOpts,
+%% Auth, Relaxed}) ->
+%% {http_options, "HTTP/1.1", TimeOut, AutoRedirect, SslOpts,
+%% Auth, Relaxed}.
+
+%% old_http_options({http_options, _, TimeOut, AutoRedirect,
+%% SslOpts, Auth, Relaxed}) ->
+%% {http_options, TimeOut, AutoRedirect, SslOpts, Auth, Relaxed}.
+
+%% new_queue(Queue, Fun) ->
+%% List = queue:to_list(Queue),
+%% NewList =
+%% lists:map(fun(Request) ->
+%% Settings =
+%% Fun(Request#request.settings),
+%% Request#request{settings = Settings}
+%% end, List),
+%% queue:from_list(NewList).
%%%--------------------------------------------------------------------
@@ -854,12 +855,18 @@ connect(SocketType, ToAddress,
inet6fb4 ->
Opts3 = [inet6 | Opts2],
case http_transport:connect(SocketType, ToAddress, Opts3, Timeout) of
- {error, Reason} when ((Reason =:= nxdomain) orelse
- (Reason =:= eafnosupport)) ->
+ {error, _Reason} = Error ->
Opts4 = [inet | Opts2],
- http_transport:connect(SocketType, ToAddress, Opts4, Timeout);
- Other ->
- Other
+ case http_transport:connect(SocketType,
+ ToAddress, Opts4, Timeout) of
+ {error, _} ->
+ %% Reply with the "original" error
+ Error;
+ OK ->
+ OK
+ end;
+ OK ->
+ OK
end;
_ ->
Opts3 = [IpFamily | Opts2],
@@ -1440,6 +1447,12 @@ answer_request(#request{id = RequestId, from = From} = Request, Msg,
timers =
Timers#timers{request_timers =
lists:delete(Timer, RequestTimers)}}.
+
+cancel_timers(#timers{request_timers = ReqTmrs, queue_timer = QTmr}) ->
+ cancel_timer(QTmr, timeout_queue),
+ CancelTimer = fun({_, Timer}) -> cancel_timer(Timer, timeout) end,
+ lists:foreach(CancelTimer, ReqTmrs).
+
cancel_timer(undefined, _) ->
ok;
cancel_timer(Timer, TimeoutMsg) ->
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index 3cdd95a02b..1d8a5b6a92 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -60,7 +60,11 @@
relaxed = false,
%% integer() - ms before a connect times out
- connect_timeout = ?HTTP_REQUEST_CTIMEOUT
+ connect_timeout = ?HTTP_REQUEST_CTIMEOUT,
+
+ %% bool() - Use %-encoding rfc 2396
+ url_encode
+
}
).
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index 1e1bde220b..591cb78c29 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -734,10 +734,11 @@ handle_connect_and_send(_StarterPid, ReqId, HandlerPid, Result,
ok;
[] ->
- error_report(Profile,
- "handler (~p) successfully started "
- "for unknown request ~p => canceling",
- [HandlerPid, ReqId]),
+ ?hcri("handler successfully started "
+ "for unknown request => canceling",
+ [{profile, Profile},
+ {handler, HandlerPid},
+ {request, ReqId}]),
httpc_handler:cancel(ReqId, HandlerPid)
end.