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/Makefile27
-rw-r--r--lib/inets/src/http_client/http.erl35
-rw-r--r--lib/inets/src/http_client/http_uri.erl116
-rw-r--r--lib/inets/src/http_client/httpc.erl86
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl274
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl20
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl25
-rw-r--r--lib/inets/src/http_client/httpc_request.erl15
-rw-r--r--lib/inets/src/http_client/httpc_response.erl4
9 files changed, 270 insertions, 332 deletions
diff --git a/lib/inets/src/http_client/Makefile b/lib/inets/src/http_client/Makefile
index 628c91421f..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
@@ -61,20 +60,17 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
# ----------------------------------------------------
-# INETS FLAGS
-# ----------------------------------------------------
-INETS_FLAGS = -D'SERVER_SOFTWARE="$(APPLICATION)/$(VSN)"'
-
-
-# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
-INETS_ERL_FLAGS += -I ../http_lib -I ../inets_app -pa ../../ebin
-ERL_COMPILE_FLAGS += $(INETS_ERL_FLAGS) \
- $(INETS_FLAGS) \
- +'{parse_transform,sys_pre_attributes}' \
- +'{attribute,insert,app_vsn,$(APP_VSN)}'
+include ../inets_app/inets.mk
+
+ERL_COMPILE_FLAGS += \
+ $(INETS_FLAGS) \
+ $(INETS_ERL_COMPILE_FLAGS) \
+ -I../../include \
+ -I../inets_app \
+ -I../http_lib
# ----------------------------------------------------
@@ -94,9 +90,10 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/http_client
+ $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src/http_client
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
$(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
release_docs_spec:
diff --git a/lib/inets/src/http_client/http.erl b/lib/inets/src/http_client/http.erl
index 7e1e90b50e..bbe2fec267 100644
--- a/lib/inets/src/http_client/http.erl
+++ b/lib/inets/src/http_client/http.erl
@@ -18,21 +18,38 @@
%%
%%
-%% Description:
-%%% This version of the HTTP/1.1 client supports:
-%%% - RFC 2616 HTTP 1.1 client part
-%%% - RFC 2818 HTTP Over TLS
+%%% Description: OLD API MODULE - USE httpc INSTEAD
-module(http).
-%% API
--export([request/1, request/2, request/4, request/5,
+-deprecated({request, 1, next_major_release}).
+-deprecated({request, 2, next_major_release}).
+-deprecated({request, 4, next_major_release}).
+-deprecated({request, 5, next_major_release}).
+-deprecated({cancel_request, 1, next_major_release}).
+-deprecated({cancel_request, 2, next_major_release}).
+-deprecated({set_option, 2, next_major_release}).
+-deprecated({set_option, 3, next_major_release}).
+-deprecated({set_options, 1, next_major_release}).
+-deprecated({set_options, 2, next_major_release}).
+-deprecated({verify_cookies, 2, next_major_release}).
+-deprecated({verify_cookies, 3, next_major_release}).
+-deprecated({cookie_header, 1, next_major_release}).
+-deprecated({cookie_header, 2, next_major_release}).
+-deprecated({stream_next, 1, next_major_release}).
+-deprecated({default_profile, 0, next_major_release}).
+
+%% Deprecated
+-export([
+ request/1, request/2, request/4, request/5,
cancel_request/1, cancel_request/2,
set_option/2, set_option/3,
set_options/1, set_options/2,
- verify_cookies/2, verify_cookies/3, cookie_header/1,
- cookie_header/2, stream_next/1,
- default_profile/0]).
+ verify_cookies/2, verify_cookies/3,
+ cookie_header/1, cookie_header/2,
+ stream_next/1,
+ default_profile/0
+ ]).
%%%=========================================================================
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 6deeab6948..ae754fab94 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -48,7 +48,7 @@
stop_service/1,
services/0, service_info/1]).
--include("http_internal.hrl").
+-include_lib("inets/src/http_lib/http_internal.hrl").
-include("httpc_internal.hrl").
-define(DEFAULT_PROFILE, default).
@@ -104,8 +104,14 @@ request(Url, Profile) ->
%% HTTPOptions - [HttpOption]
%% HTTPOption - {timeout, Time} | {connect_timeout, Time} |
%% {ssl, SSLOptions} | {proxy_auth, {User, Password}}
-%% Ssloptions = [SSLOption]
-%% SSLOption = {verify, code()} | {depth, depth()} | {certfile, path()} |
+%% Ssloptions = ssl_options() |
+%% {ssl, ssl_options()} |
+%% {ossl, ssl_options()} |
+%% {essl, ssl_options()}
+%% ssl_options() = [ssl_option()]
+%% ssl_option() = {verify, code()} |
+%% {depth, depth()} |
+%% {certfile, path()} |
%% {keyfile, path()} | {password, string()} | {cacertfile, path()} |
%% {ciphers, string()}
%% Options - [Option]
@@ -436,18 +442,23 @@ 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,
+ stream = Stream,
headers_as_is = headers_as_is(Headers, Options),
socket_opts = SocketOpts,
started = Started},
@@ -465,6 +476,10 @@ handle_request(Method, Url,
Error
end.
+url_encode(URI, true) ->
+ http_uri:encode(URI);
+url_encode(URI, false) ->
+ URI.
handle_answer(RequestId, false, _) ->
{ok, RequestId};
@@ -572,14 +587,16 @@ 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, Value};
+ {ok, {?HTTP_DEFAULT_SSL_KIND, Value}};
+ ({ssl, SslOptions}) when is_list(SslOptions) ->
+ {ok, {?HTTP_DEFAULT_SSL_KIND, SslOptions}};
+ ({ossl, SslOptions}) when is_list(SslOptions) ->
+ {ok, {ossl, SslOptions}};
+ ({essl, SslOptions}) when is_list(SslOptions) ->
+ {ok, {essl, SslOptions}};
(_) ->
error
end,
@@ -589,12 +606,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};
@@ -603,25 +616,30 @@ 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},
- {autoredirect, {value, true}, #http_options.autoredirect, AutoRedirectPost},
- {ssl, {value, []}, #http_options.ssl, SslPost},
- {proxy_auth, {value, undefined}, #http_options.proxy_auth, ProxyAuthPost},
- {relaxed, {value, false}, #http_options.relaxed, RelaxedPost},
- %% this field has to be *after* the timeout field (as that field is used for the default value)
- {connect_timeout, {field, #http_options.timeout}, #http_options.connect_timeout, ConnTimeoutPost}
+ {version, {value, "HTTP/1.1"}, #http_options.version, VersionPost},
+ {timeout, {value, ?HTTP_REQUEST_TIMEOUT}, #http_options.timeout, TimeoutPost},
+ {autoredirect, {value, true}, #http_options.autoredirect, AutoRedirectPost},
+ {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 db5ff3036a..cb6f3e2841 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -22,8 +22,8 @@
-behaviour(gen_server).
+-include_lib("inets/src/http_lib/http_internal.hrl").
-include("httpc_internal.hrl").
--include("http_internal.hrl").
%%--------------------------------------------------------------------
@@ -177,8 +177,8 @@ stream(BodyPart, Request = #request{stream = Self}, Code)
stream(BodyPart, Request = #request{stream = Self}, 404)
when (Self =:= self) orelse (Self =:= {self, once}) ->
?hcrt("stream - self with 404", [{stream, Self}]),
- httpc_response:send(Request#request.from,
- {Request#request.id, stream, BodyPart}),
+ httpc_response:send(Request#request.from,
+ {Request#request.id, stream, BodyPart}),
{<<>>, Request};
%% Stream to file
@@ -286,8 +286,7 @@ handle_call({connect_and_send, #request{address = Address0,
handle_call(#request{address = Addr} = Request, _,
#state{status = Status,
- session = #tcp_session{socket = Socket,
- type = pipeline} = Session,
+ session = #session{type = pipeline} = Session,
timers = Timers,
options = #options{proxy = Proxy} = _Options,
profile_name = ProfileName} = State)
@@ -301,7 +300,7 @@ handle_call(#request{address = Addr} = Request, _,
Address = handle_proxy(Addr, Proxy),
- case httpc_request:send(Address, Request, Socket) of
+ case httpc_request:send(Address, Session, Request) of
ok ->
?hcrd("request sent", []),
@@ -320,10 +319,10 @@ handle_call(#request{address = Addr} = Request, _,
NewTimers = NewState#state.timers,
NewPipeline = queue:in(Request, State#state.pipeline),
NewSession =
- Session#tcp_session{queue_length =
- %% Queue + current
- queue:len(NewPipeline) + 1,
- client_close = ClientClose},
+ Session#session{queue_length =
+ %% Queue + current
+ queue:len(NewPipeline) + 1,
+ client_close = ClientClose},
httpc_manager:insert_session(NewSession, ProfileName),
?hcrd("session updated", []),
{reply, ok, State#state{pipeline = NewPipeline,
@@ -336,8 +335,8 @@ handle_call(#request{address = Addr} = Request, _,
cancel_timer(Timers#timers.queue_timer,
timeout_queue),
NewSession =
- Session#tcp_session{queue_length = 1,
- client_close = ClientClose},
+ Session#session{queue_length = 1,
+ client_close = ClientClose},
httpc_manager:insert_session(NewSession, ProfileName),
Relaxed =
(Request#request.settings)#http_options.relaxed,
@@ -357,8 +356,7 @@ handle_call(#request{address = Addr} = Request, _,
handle_call(#request{address = Addr} = Request, _,
#state{status = Status,
- session = #tcp_session{socket = Socket,
- type = keep_alive} = Session,
+ session = #session{type = keep_alive} = Session,
timers = Timers,
options = #options{proxy = Proxy} = _Options,
profile_name = ProfileName} = State)
@@ -370,7 +368,7 @@ handle_call(#request{address = Addr} = Request, _,
{status, Status}]),
Address = handle_proxy(Addr, Proxy),
- case httpc_request:send(Address, Request, Socket) of
+ case httpc_request:send(Address, Session, Request) of
ok ->
?hcrd("request sent", []),
@@ -389,10 +387,10 @@ handle_call(#request{address = Addr} = Request, _,
NewTimers = NewState#state.timers,
NewKeepAlive = queue:in(Request, State#state.keep_alive),
NewSession =
- Session#tcp_session{queue_length =
- %% Queue + current
- queue:len(NewKeepAlive) + 1,
- client_close = ClientClose},
+ Session#session{queue_length =
+ %% Queue + current
+ queue:len(NewKeepAlive) + 1,
+ client_close = ClientClose},
httpc_manager:insert_session(NewSession, ProfileName),
?hcrd("session updated", []),
{reply, ok, State#state{keep_alive = NewKeepAlive,
@@ -405,8 +403,8 @@ handle_call(#request{address = Addr} = Request, _,
cancel_timer(Timers#timers.queue_timer,
timeout_queue),
NewSession =
- Session#tcp_session{queue_length = 1,
- client_close = ClientClose},
+ Session#session{queue_length = 1,
+ client_close = ClientClose},
httpc_manager:insert_session(NewSession, ProfileName),
Relaxed =
(Request#request.settings)#http_options.relaxed,
@@ -589,13 +587,13 @@ handle_info({ssl_closed, _}, State = #state{request = undefined}) ->
%%% Error cases
handle_info({tcp_closed, _}, #state{session = Session0} = State) ->
- Socket = Session0#tcp_session.socket,
- Session = Session0#tcp_session{socket = {remote_close, Socket}},
+ Socket = Session0#session.socket,
+ Session = Session0#session{socket = {remote_close, Socket}},
%% {stop, session_remotly_closed, State};
{stop, normal, State#state{session = Session}};
handle_info({ssl_closed, _}, #state{session = Session0} = State) ->
- Socket = Session0#tcp_session.socket,
- Session = Session0#tcp_session{socket = {remote_close, Socket}},
+ Socket = Session0#session.socket,
+ Session = Session0#session{socket = {remote_close, Socket}},
%% {stop, session_remotly_closed, State};
{stop, normal, State#state{session = Session}};
handle_info({tcp_error, _, _} = Reason, State) ->
@@ -704,52 +702,56 @@ terminate(normal, #state{session = undefined}) ->
%% Init error sending, no session information has been setup but
%% there is a socket that needs closing.
terminate(normal,
- #state{request = Request,
- session = #tcp_session{id = undefined,
- socket = Socket}}) ->
- http_transport:close(socket_type(Request), Socket);
+ #state{session = #session{id = undefined} = Session}) ->
+ close_socket(Session);
%% Socket closed remotely
terminate(normal,
- #state{session = #tcp_session{socket = {remote_close, Socket},
- id = Id},
+ #state{session = #session{socket = {remote_close, Socket},
+ socket_type = SocketType,
+ id = Id},
profile_name = ProfileName,
- request = Request,
- timers = Timers,
- pipeline = Pipeline}) ->
+ request = Request,
+ timers = Timers,
+ 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(socket_type(Request), Socket);
+ http_transport:close(SocketType, Socket);
-terminate(_, #state{session = #tcp_session{id = Id,
- socket = Socket,
- scheme = Scheme},
+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),
maybe_retry_queue(KeepAlive, State),
cancel_timer(Timers#timers.queue_timer, timeout_queue),
- http_transport:close(socket_type(Scheme), Socket);
+ http_transport:close(SocketType, Socket);
terminate(Reason, #state{request = undefined}) ->
?hcrt("terminate", [{reason, Reason}]),
@@ -775,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).
%%%--------------------------------------------------------------------
@@ -857,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],
@@ -883,22 +887,23 @@ connect_and_send_first_request(Address,
ConnTimeout = Settings#http_options.connect_timeout,
case connect(SocketType, Address, Options, ConnTimeout) of
{ok, Socket} ->
+ Session = #session{id = {OrigAddress, self()},
+ scheme = Scheme,
+ socket = Socket,
+ socket_type = SocketType},
?hcrd("connected - now send first request", [{socket, Socket}]),
- case httpc_request:send(Address, Request, Socket) of
+ case httpc_request:send(Address, Session, Request) of
ok ->
?hcrd("first request sent", []),
ClientClose =
httpc_request:is_client_closing(Headers),
SessionType = httpc_manager:session_type(Options),
- Session =
- #tcp_session{id = {OrigAddress, self()},
- scheme = Scheme,
- socket = Socket,
- client_close = ClientClose,
- type = SessionType},
+ Session2 =
+ Session#session{client_close = ClientClose,
+ type = SessionType},
TmpState =
State#state{request = Request,
- session = Session,
+ session = Session2,
mfa = init_mfa(Request, State),
status_line = init_status_line(Request),
headers = undefined,
@@ -952,21 +957,20 @@ handler_info(#state{request = Request,
?hcrt("handler info", [{request_info, RequestInfo}]),
%% Info about the current session/socket
- SessionType = Session#tcp_session.type,
- QueueLen = case Session#tcp_session.type of
+ SessionType = Session#session.type,
+ QueueLen = case SessionType of
pipeline ->
queue:len(Pipeline);
keep_alive ->
queue:len(KeepAlive)
end,
- Socket = Session#tcp_session.socket,
- Scheme = Session#tcp_session.scheme,
- SocketType = socket_type(Scheme),
+ Scheme = Session#session.scheme,
+ Socket = Session#session.socket,
+ SocketType = Session#session.socket_type,
?hcrt("handler info", [{session_type, SessionType},
{queue_length, QueueLen},
{scheme, Scheme},
- {socket_type, SocketType},
{socket, Socket}]),
SocketOpts = http_transport:getopts(SocketType, Socket),
@@ -1123,9 +1127,7 @@ handle_response(#state{request = Request,
?hcrd("handle response - continue", []),
%% Send request body
{_, RequestBody} = Request#request.content,
- http_transport:send(socket_type(Session#tcp_session.scheme),
- Session#tcp_session.socket,
- RequestBody),
+ send_raw(Session, RequestBody),
%% Wait for next response
activate_once(Session),
Relaxed = (Request#request.settings)#http_options.relaxed,
@@ -1222,7 +1224,7 @@ handle_pipeline(#state{status = pipeline,
%% If a pipeline that has been idle for some time is not
%% closed by the server, the client may want to close it.
NewState = activate_queue_timeout(TimeOut, State),
- NewSession = Session#tcp_session{queue_length = 0},
+ NewSession = Session#session{queue_length = 0},
httpc_manager:insert_session(NewSession, ProfileName),
%% Note mfa will be initilized when a new request
%% arrives.
@@ -1244,9 +1246,9 @@ handle_pipeline(#state{status = pipeline,
false ->
?hcrv("next request", [{request, NextRequest}]),
NewSession =
- Session#tcp_session{queue_length =
- %% Queue + current
- queue:len(Pipeline) + 1},
+ Session#session{queue_length =
+ %% Queue + current
+ queue:len(Pipeline) + 1},
httpc_manager:insert_session(NewSession, ProfileName),
Relaxed =
(NextRequest#request.settings)#http_options.relaxed,
@@ -1295,16 +1297,16 @@ handle_keep_alive_queue(
%% If a keep_alive session has been idle for some time is not
%% closed by the server, the client may want to close it.
NewState = activate_queue_timeout(TimeOut, State),
- NewSession = Session#tcp_session{queue_length = 0},
+ NewSession = Session#session{queue_length = 0},
httpc_manager:insert_session(NewSession, ProfileName),
%% Note mfa will be initilized when a new request
%% arrives.
{noreply,
- NewState#state{request = undefined,
- mfa = undefined,
+ NewState#state{request = undefined,
+ mfa = undefined,
status_line = undefined,
- headers = undefined,
- body = undefined
+ headers = undefined,
+ body = undefined
}
};
{{value, NextRequest}, KeepAlive} ->
@@ -1347,10 +1349,12 @@ case_insensitive_header(Str) when is_list(Str) ->
case_insensitive_header(Str) ->
Str.
-activate_once(#tcp_session{scheme = Scheme, socket = Socket}) ->
- SocketType = socket_type(Scheme),
+activate_once(#session{socket = Socket, socket_type = SocketType}) ->
http_transport:setopts(SocketType, Socket, [{active, once}]).
+close_socket(#session{socket = Socket, socket_type = SocketType}) ->
+ http_transport:close(SocketType, Socket).
+
activate_request_timeout(
#state{request = #request{timer = undefined} = Request} = State) ->
Timeout = (Request#request.settings)#http_options.timeout,
@@ -1383,7 +1387,7 @@ activate_queue_timeout(Time, State) ->
State#state{timers = #timers{queue_timer = Ref}}.
-is_pipeline_enabled_client(#tcp_session{type = pipeline}) ->
+is_pipeline_enabled_client(#session{type = pipeline}) ->
true;
is_pipeline_enabled_client(_) ->
false.
@@ -1396,7 +1400,7 @@ is_keep_alive_enabled_server("HTTP/1.0",
is_keep_alive_enabled_server(_,_) ->
false.
-is_keep_alive_connection(Headers, #tcp_session{client_close = ClientClose}) ->
+is_keep_alive_connection(Headers, #session{client_close = ClientClose}) ->
(not ((ClientClose) orelse httpc_response:is_server_closing(Headers))).
try_to_enable_pipeline_or_keep_alive(
@@ -1421,7 +1425,7 @@ try_to_enable_pipeline_or_keep_alive(
httpc_manager:insert_session(Session, ProfileName),
%% Make sure type is keep_alive in session
%% as it in this case might be pipeline
- NewSession = Session#tcp_session{type = keep_alive},
+ NewSession = Session#session{type = keep_alive},
State#state{status = keep_alive,
session = NewSession}
end;
@@ -1443,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) ->
@@ -1556,11 +1566,11 @@ init_status_line(#request{settings = Settings}) ->
socket_type(#request{scheme = http}) ->
ip_comm;
socket_type(#request{scheme = https, settings = Settings}) ->
- {ssl, Settings#http_options.ssl};
-socket_type(http) ->
- ip_comm;
-socket_type(https) ->
- {ssl, []}. %% Dummy value ok for ex setopts that does not use this value
+ Settings#http_options.ssl.
+%% socket_type(http) ->
+%% ip_comm;
+%% socket_type(https) ->
+%% {ssl1, []}. %% Dummy value ok for ex setopts that does not use this value
start_stream({_Version, _Code, _ReasonPhrase}, _Headers,
#request{stream = none} = Request) ->
@@ -1629,18 +1639,15 @@ end_stream(SL, R) ->
next_body_chunk(#state{request = #request{stream = {self, once}},
- once = once, session = Session} = State) ->
- http_transport:setopts(socket_type(Session#tcp_session.scheme),
- Session#tcp_session.socket,
- [{active, once}]),
+ once = once,
+ session = Session} = State) ->
+ activate_once(Session),
State#state{once = inactive};
next_body_chunk(#state{request = #request{stream = {self, once}},
once = inactive} = State) ->
State; %% Wait for user to call stream_next
next_body_chunk(#state{session = Session} = State) ->
- http_transport:setopts(socket_type(Session#tcp_session.scheme),
- Session#tcp_session.socket,
- [{active, once}]),
+ activate_once(Session),
State.
handle_verbose(verbose) ->
@@ -1717,6 +1724,11 @@ handle_verbose(_) ->
%% ok.
+send_raw(#session{socket = Socket, socket_type = SocketType}, Body) ->
+ http_transport:send(SocketType, Socket, Body).
+
+
+
call(Msg, Pid) ->
Timeout = infinity,
call(Msg, Pid, Timeout).
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index 4d76c4beb3..1d8a5b6a92 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -18,7 +18,11 @@
%%
%%
--include("inets_internal.hrl").
+-ifndef(httpc_internal_hrl).
+-define(httpc_internal_hrl, true).
+
+-include_lib("inets/src/inets_app/inets_internal.hrl").
+
-define(SERVICE, httpc).
-define(hcri(Label, Data), ?report_important(Label, ?SERVICE, Data)).
-define(hcrv(Label, Data), ?report_verbose(Label, ?SERVICE, Data)).
@@ -56,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
+
}
).
@@ -104,13 +112,14 @@
}
).
--record(tcp_session,
+-record(session,
{
id, % {{Host, Port}, HandlerPid}
client_close, % true | false
scheme, % http (HTTP/TCP) | https (HTTP/SSL/TCP)
socket, % Open socket, used by connection
- queue_length = 1, % Current length of pipeline or keep alive queue
+ socket_type, % socket-type, used by connection
+ queue_length = 1, % Current length of pipeline or keep-alive queue
type % pipeline | keep_alive (wait for response before sending new request)
}).
@@ -138,3 +147,6 @@
%% path, % string()
%% q % query: string()
%% }).
+
+
+-endif. % -ifdef(httpc_internal_hrl).
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index 4738517210..591cb78c29 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -21,8 +21,8 @@
-behaviour(gen_server).
+-include_lib("inets/src/http_lib/http_internal.hrl").
-include("httpc_internal.hrl").
--include("http_internal.hrl").
%% Internal Application API
-export([
@@ -324,7 +324,7 @@ do_init(ProfileName, CookiesDir) ->
?hcrt("create session db", []),
SessionDbName = session_db_name(ProfileName),
ets:new(SessionDbName,
- [public, set, named_table, {keypos, #tcp_session.id}]),
+ [public, set, named_table, {keypos, #session.id}]),
%% Create handler db
?hcrt("create handler/request db", []),
@@ -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.
@@ -882,12 +883,12 @@ select_session(Method, HostPort, Scheme, SessionType,
%% client_close, scheme and type specified.
%% The fields id (part of: HandlerPid) and queue_length
%% specified.
- Pattern = #tcp_session{id = {HostPort, '$1'},
- client_close = false,
- scheme = Scheme,
- socket = '_',
- queue_length = '$2',
- type = SessionType},
+ Pattern = #session{id = {HostPort, '$1'},
+ client_close = false,
+ scheme = Scheme,
+ queue_length = '$2',
+ type = SessionType,
+ _ = '_'},
%% {'_', {HostPort, '$1'}, false, Scheme, '_', '$2', SessionTyp},
Candidates = ets:match(SessionDb, Pattern),
?hcrd("select session", [{host_port, HostPort},
diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl
index 55e0af4b42..d4df97ad40 100644
--- a/lib/inets/src/http_client/httpc_request.erl
+++ b/lib/inets/src/http_client/httpc_request.erl
@@ -19,12 +19,13 @@
-module(httpc_request).
--include("http_internal.hrl").
+-include_lib("inets/src/http_lib/http_internal.hrl").
-include("httpc_internal.hrl").
%%% Internal API
-export([send/3, is_idempotent/1, is_client_closing/1]).
+
%%%=========================================================================
%%% Internal application API
%%%=========================================================================
@@ -39,10 +40,9 @@
%%
%% Description: Composes and sends a HTTP-request.
%%-------------------------------------------------------------------------
-send(SendAddr, #request{scheme = Scheme, socket_opts = SocketOpts} = Request,
- Socket)
+send(SendAddr, #session{socket = Socket, socket_type = SocketType},
+ #request{socket_opts = SocketOpts} = Request)
when is_list(SocketOpts) ->
- SocketType = socket_type(Scheme),
case http_transport:setopts(SocketType, Socket, SocketOpts) of
ok ->
send(SendAddr, Socket, SocketType,
@@ -50,8 +50,7 @@ send(SendAddr, #request{scheme = Scheme, socket_opts = SocketOpts} = Request,
{error, Reason} ->
{error, {setopts_failed, Reason}}
end;
-send(SendAddr, #request{scheme = Scheme} = Request, Socket) ->
- SocketType = socket_type(Scheme),
+send(SendAddr, #session{socket = Socket, socket_type = SocketType}, Request) ->
send(SendAddr, Socket, SocketType, Request).
send(SendAddr, Socket, SocketType,
@@ -209,10 +208,6 @@ headers(_, "HTTP/0.9") ->
headers(Headers, _) ->
Headers.
-socket_type(http) ->
- ip_comm;
-socket_type(https) ->
- {ssl, []}.
http_headers([], Headers) ->
lists:flatten(Headers);
diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl
index df7d40a33e..207b96271c 100644
--- a/lib/inets/src/http_client/httpc_response.erl
+++ b/lib/inets/src/http_client/httpc_response.erl
@@ -19,10 +19,12 @@
-module(httpc_response).
--include("http_internal.hrl").
+-include_lib("inets/src/http_lib/http_internal.hrl").
-include("httpc_internal.hrl").
%% API
+%% Avoid warning for local function error/2 clashing with autoimported BIF.
+-compile({no_auto_import,[error/2]}).
-export([parse/1, result/2, send/2, error/2, is_server_closing/1,
stream_start/3]).