aboutsummaryrefslogtreecommitdiffstats
path: root/lib/inets/src/http_client/httpc_request.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/inets/src/http_client/httpc_request.erl')
-rw-r--r--lib/inets/src/http_client/httpc_request.erl209
1 files changed, 209 insertions, 0 deletions
diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl
new file mode 100644
index 0000000000..3d66638d66
--- /dev/null
+++ b/lib/inets/src/http_client/httpc_request.erl
@@ -0,0 +1,209 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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(httpc_request).
+
+-include("http_internal.hrl").
+-include("httpc_internal.hrl").
+
+%%% Internal API
+-export([send/3, is_idempotent/1, is_client_closing/1]).
+
+%%%=========================================================================
+%%% Internal application API
+%%%=========================================================================
+%%-------------------------------------------------------------------------
+%% send(MaybeProxy, Request) ->
+%% MaybeProxy - {Host, Port}
+%% Host = string()
+%% Port = integer()
+%% Request - #request{}
+%% Socket - socket()
+%% CookieSupport - enabled | disabled | verify
+%%
+%% Description: Composes and sends a HTTP-request.
+%%-------------------------------------------------------------------------
+send(SendAddr, #request{method = Method, scheme = Scheme,
+ path = Path, pquery = Query, headers = Headers,
+ content = Content, address = Address,
+ abs_uri = AbsUri, headers_as_is = HeadersAsIs,
+ settings = HttpOptions,
+ userinfo = UserInfo},
+ Socket) ->
+
+ TmpHeaders = handle_user_info(UserInfo, Headers),
+
+ {TmpHeaders2, Body} =
+ post_data(Method, TmpHeaders, Content, HeadersAsIs),
+
+ {NewHeaders, Uri} = case Address of
+ SendAddr ->
+ {TmpHeaders2, Path ++ Query};
+ _Proxy ->
+ TmpHeaders3 =
+ handle_proxy(HttpOptions, TmpHeaders2),
+ {TmpHeaders3, AbsUri}
+ end,
+
+ FinalHeaders = case NewHeaders of
+ HeaderList when is_list(HeaderList) ->
+ http_headers(HeaderList, []);
+ _ ->
+ http_request:http_headers(NewHeaders)
+ end,
+ Version = HttpOptions#http_options.version,
+
+ Message = [method(Method), " ", Uri, " ",
+ version(Version), ?CRLF, headers(FinalHeaders, Version), ?CRLF, Body],
+
+ http_transport:send(socket_type(Scheme), Socket, lists:append(Message)).
+
+%%-------------------------------------------------------------------------
+%% is_idempotent(Method) ->
+%% Method = atom()
+%%
+%% Description: Checks if Method is considered idempotent.
+%%-------------------------------------------------------------------------
+
+%% In particular, the convention has been established that the GET and
+%% HEAD methods SHOULD NOT have the significance of taking an action
+%% other than retrieval. These methods ought to be considered "safe".
+is_idempotent(head) ->
+ true;
+is_idempotent(get) ->
+ true;
+%% Methods can also have the property of "idempotence" in that (aside
+%% from error or expiration issues) the side-effects of N > 0
+%% identical requests is the same as for a single request.
+is_idempotent(put) ->
+ true;
+is_idempotent(delete) ->
+ true;
+%% Also, the methods OPTIONS and TRACE SHOULD NOT have side effects,
+%% and so are inherently idempotent.
+is_idempotent(trace) ->
+ true;
+is_idempotent(options) ->
+ true;
+is_idempotent(_) ->
+ false.
+
+%%-------------------------------------------------------------------------
+%% is_client_closing(Headers) ->
+%% Headers = #http_request_h{}
+%%
+%% Description: Checks if the client has supplied a "Connection:
+%% close" header.
+%%-------------------------------------------------------------------------
+is_client_closing(Headers) ->
+ case Headers#http_request_h.connection of
+ "close" ->
+ true;
+ _ ->
+ false
+ end.
+
+%%%========================================================================
+%%% Internal functions
+%%%========================================================================
+post_data(Method, Headers, {ContentType, Body}, HeadersAsIs)
+ when Method == post; Method == put ->
+ ContentLength = body_length(Body),
+ NewBody = case Headers#http_request_h.expect of
+ "100-continue" ->
+ "";
+ _ ->
+ Body
+ end,
+
+ NewHeaders = case HeadersAsIs of
+ [] ->
+ Headers#http_request_h{'content-type' =
+ ContentType,
+ 'content-length' =
+ ContentLength};
+ _ ->
+ HeadersAsIs
+ end,
+
+ {NewHeaders, NewBody};
+
+post_data(_, Headers, _, []) ->
+ {Headers, ""};
+post_data(_, _, _, HeadersAsIs = [_|_]) ->
+ {HeadersAsIs, ""}.
+
+body_length(Body) when is_binary(Body) ->
+ integer_to_list(size(Body));
+
+body_length(Body) when is_list(Body) ->
+ integer_to_list(length(Body)).
+
+method(Method) ->
+ http_util:to_upper(atom_to_list(Method)).
+
+version("HTTP/0.9") ->
+ "";
+version(Version) ->
+ Version.
+
+headers(_, "HTTP/0.9") ->
+ "";
+%% HTTP 1.1 headers not present in HTTP 1.0 should be
+%% consider as unknown extension headers that should be
+%% ignored.
+headers(Headers, _) ->
+ Headers.
+
+socket_type(http) ->
+ ip_comm;
+socket_type(https) ->
+ {ssl, []}.
+
+http_headers([], Headers) ->
+ lists:flatten(Headers);
+http_headers([{Key,Value} | Rest], Headers) ->
+ Header = Key ++ ": " ++ Value ++ ?CRLF,
+ http_headers(Rest, [Header | Headers]).
+
+handle_proxy(_, Headers) when is_list(Headers) ->
+ Headers; %% Headers as is option was specified
+handle_proxy(HttpOptions, Headers) ->
+ case HttpOptions#http_options.proxy_auth of
+ undefined ->
+ Headers;
+ {User, Password} ->
+ UserPasswd = base64:encode_to_string(User ++ ":" ++ Password),
+ Headers#http_request_h{'proxy-authorization' =
+ "Basic " ++ UserPasswd}
+ end.
+
+handle_user_info([], Headers) ->
+ Headers;
+handle_user_info(UserInfo, Headers) ->
+ case string:tokens(UserInfo, ":") of
+ [User, Passwd] ->
+ UserPasswd = base64:encode_to_string(User ++ ":" ++ Passwd),
+ Headers#http_request_h{authorization = "Basic " ++ UserPasswd};
+ [User] ->
+ UserPasswd = base64:encode_to_string(User ++ ":"),
+ Headers#http_request_h{authorization = "Basic " ++ UserPasswd};
+ _ ->
+ Headers
+ end.