1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21-module(http_transport).
22
23% Internal application API
24-export([
25	 start/1,
26	 connect/3, connect/4,
27	 listen/4, listen/5,
28	 accept/2, accept/3,
29	 close/2,
30         close_tag/1,
31	 send/3,
32	 controlling_process/3,
33	 setopts/3, getopts/2, getopts/3,
34	 getstat/2,
35	 peername/2, sockname/2,
36	 resolve/0
37	]).
38-export([negotiate/3]).
39-export([ipv4_name/1, ipv6_name/1]).
40
41-include_lib("inets/src/inets_app/inets_internal.hrl").
42-include("http_internal.hrl").
43
44
45%%%=========================================================================
46%%%  Internal application API
47%%%=========================================================================
48
49%%-------------------------------------------------------------------------
50%% start(SocketType) -> ok | {error, Reason}
51%%      SocketType = ip_comm | {ssl, _}
52%%
53%% Description: Makes sure ssl is started.
54%%-------------------------------------------------------------------------
55start(ip_comm) ->
56    ok;
57start({ip_comm, _}) ->
58    ok;
59start({ssl, _}) ->
60    do_start_ssl();
61start({essl, _}) ->
62    do_start_ssl().
63
64do_start_ssl() ->
65    try lists:foreach(fun(App) ->
66			      ok = application:ensure_started(App)
67		      end,
68		      [crypto, asn1, public_key, ssl])
69    catch
70	_:Reason ->
71	    {error, Reason}
72    end.
73
74
75%%-------------------------------------------------------------------------
76%% connect(SocketType, Address, Options, Timeout) ->
77%%                                            {ok, Socket} | {error, Reason}
78%%      SocketType = ip_comm | {ssl, SslConfig}
79%%      Address = {Host, Port}
80%%      Options = [option()]
81%%      Socket = socket()
82%%      option() = ipfamily() | {ip, ip_address()} | {port, integer()}
83%%      ipfamily() = inet | inet6
84%%
85%% Description: Connects to the Host and Port specified in HTTPRequest.
86%%-------------------------------------------------------------------------
87
88connect(SocketType, Address, Opts) ->
89    connect(SocketType, Address, Opts, infinity).
90connect(ip_comm, {Host, Port}, Opts0, Timeout) ->
91    Opts = [binary, {packet, 0}, {active, false}, {reuseaddr, true} | Opts0 ],
92    try gen_tcp:connect(Host, Port, Opts, Timeout) of
93	{ok, _} = OK ->
94	    OK;
95	{error, _} = ERROR ->
96	    ERROR
97    catch
98	exit:{badarg, _} ->
99	    {error, {eoptions, Opts}};
100	exit:badarg ->
101	    {error, {eoptions, Opts}}
102    end;
103
104%% Wrapper for backaward compatibillity
105connect({ssl, SslConfig}, Address, Opts, Timeout) ->
106    connect({?HTTP_DEFAULT_SSL_KIND, SslConfig}, Address, Opts, Timeout);
107
108connect({essl, SslConfig}, {Host, Port}, Opts0, Timeout) ->
109    Opts = [binary, {active, false}, {ssl_imp, new} | Opts0] ++ SslConfig,
110    case (catch ssl:connect(Host, Port, Opts, Timeout)) of
111	{'EXIT', Reason} ->
112	    {error, {eoptions, Reason}};
113	{ok, _} = OK ->
114	    OK;
115	{error, _} = ERROR ->
116	    ERROR
117    end.
118
119
120%%-------------------------------------------------------------------------
121%% listen(SocketType, Addr, Port, Fd) -> {ok, Socket} | {error, Reason}
122%%      SocketType = ip_comm | {ssl, SSLConfig}
123%%      Port = integer()
124%%      Socket = socket()
125%%      Fd = undefined | fd()
126%%
127%% Description: Sets up socket to listen on the port Port on the local
128%% host using either gen_tcp or ssl. In the gen_tcp case the port
129%% might allready have been initiated by a wrapper-program and is
130%% given as an Fd that can be retrieved by init:get_argument. The
131%% reason for this to enable a HTTP-server not running as root to use
132%% port 80.
133%%-------------------------------------------------------------------------
134listen(ip_comm, Addr, Port, Fd, IpFamily) ->
135    listen_ip_comm(Addr, Port, [], Fd, IpFamily);
136
137listen({ip_comm, SockOpts}, Addr, Port, Fd, IpFamily) ->
138    listen_ip_comm(Addr, Port, SockOpts, Fd, IpFamily);
139
140listen({essl, SSLConfig}, Addr, Port, Fd, IpFamily) ->
141    listen_ssl(Addr, Port, Fd, SSLConfig, IpFamily, []).
142
143listen(ip_comm, Addr, Port, IpFamily) ->
144    listen_ip_comm(Addr, Port, [], undefined, IpFamily);
145
146%% Wrapper for backaward compatibillity
147listen({ssl, SSLConfig}, Addr, Port, IpFamily) ->
148    listen({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Addr, Port, IpFamily);
149
150listen({essl, SSLConfig}, Addr, Port, IpFamily) ->
151    {SSLConfig2, ExtraOpts} = case proplists:get_value(log_alert, SSLConfig, undefined) of
152		    undefined ->
153			{SSLConfig, []};
154		    LogAlert ->
155			{proplists:delete(log_alert, SSLConfig), [{log_alert, LogAlert}]}
156		end,
157    listen_ssl(Addr, Port, undefined, SSLConfig2, IpFamily, ExtraOpts).
158
159listen_ip_comm(Addr, Port, SockOpts, Fd, IpFamily) ->
160    case (catch do_listen_ip_comm(Addr, Port, SockOpts, Fd, IpFamily)) of
161	{'EXIT', Reason} ->
162	    {error, {exit, Reason}};
163	Else ->
164	    Else
165    end.
166
167do_listen_ip_comm(Addr, Port, SockOpts, Fd, IpFamily) ->
168    Backlog = proplists:get_value(backlog, SockOpts, 128),
169    {NewPort, Opts} = get_socket_info(Addr, Port, Fd,
170				      [{backlog, Backlog}, {reuseaddr, true} | SockOpts]),
171    Opts2 = [IpFamily | Opts],
172    gen_tcp:listen(NewPort, Opts2).
173
174listen_ssl(Addr, Port, Fd, Opts0, IpFamily, ExtraOpts) ->
175    Backlog = proplists:get_value(backlog, Opts0, 128),
176    {NewPort, SockOpt} = get_socket_info(Addr, Port, Fd,
177					 [{backlog, Backlog}, {reuseaddr, true}]),
178    Opts = SockOpt ++ Opts0,
179    Opts2 = [IpFamily | Opts],
180    ssl:listen(NewPort, Opts2 ++ ExtraOpts).
181
182get_socket_info(Addr, Port, Fd, BaseOpts) ->
183    %% The presence of a file descriptor takes precedence
184    case Fd of
185	undefined ->
186	    {Port, sock_opts(Addr, BaseOpts)};
187	Fd ->
188	    {0, sock_opts([{fd, Fd} | BaseOpts])}
189    end.
190
191%%-------------------------------------------------------------------------
192%% accept(SocketType, ListenSocket) -> {ok, Socket} | {error, Reason}
193%% accept(SocketType, ListenSocket, Timeout) -> ok | {error, Reason}
194%%   SocketType = ip_comm | {ssl, SSLConfig}
195%%   ListenSocket = socket()
196%%   Timeout = infinity | integer() >= 0
197%%   Socket = socket()
198%%
199%% Description: Accepts an incoming connection request on a listen socket,
200%% using either gen_tcp or ssl.
201%%-------------------------------------------------------------------------
202accept(SocketType, ListenSocket) ->
203    accept(SocketType, ListenSocket, infinity).
204
205accept(ip_comm, ListenSocket, Timeout) ->
206    gen_tcp:accept(ListenSocket, Timeout);
207accept({ip_comm, _}, ListenSocket, Timeout) ->
208    gen_tcp:accept(ListenSocket, Timeout);
209
210%% Wrapper for backaward compatibillity
211accept({ssl, SSLConfig}, ListenSocket, Timeout) ->
212    accept({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, ListenSocket, Timeout);
213
214accept({essl, _SSLConfig}, ListenSocket, Timeout) ->
215    ssl:transport_accept(ListenSocket, Timeout).
216
217
218%%-------------------------------------------------------------------------
219%% controlling_process(SocketType, Socket, NewOwner) -> ok | {error, Reason}
220%%   SocketType = ip_comm | {ssl, _}
221%%   Socket = socket()
222%%   NewOwner = pid()
223%%
224%% Description: Assigns a new controlling process to Socket.
225%%-------------------------------------------------------------------------
226controlling_process(ip_comm, Socket, NewOwner) ->
227    gen_tcp:controlling_process(Socket, NewOwner);
228controlling_process({ip_comm, _}, Socket, NewOwner) ->
229    gen_tcp:controlling_process(Socket, NewOwner);
230
231%% Wrapper for backaward compatibillity
232controlling_process({ssl, SSLConfig}, Socket, NewOwner) ->
233    controlling_process({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, NewOwner);
234
235controlling_process({essl, _}, Socket, NewOwner) ->
236    ssl:controlling_process(Socket, NewOwner).
237
238
239%%-------------------------------------------------------------------------
240%% setopts(SocketType, Socket, Options) -> ok | {error, Reason}
241%%     SocketType = ip_comm | {ssl, _}
242%%     Socket = socket()
243%%     Options = list()
244%% Description: Sets one or more options for a socket, using either
245%% gen_tcp or ssl.
246%%-------------------------------------------------------------------------
247setopts(ip_comm, Socket, Options) ->
248    inet:setopts(Socket, Options);
249setopts({ip_comm, _}, Socket, Options) ->
250    inet:setopts(Socket, Options);
251
252%% Wrapper for backaward compatibillity
253setopts({ssl, SSLConfig}, Socket, Options) ->
254    setopts({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Options);
255
256setopts({essl, _}, Socket, Options) ->
257    (catch ssl:setopts(Socket, Options)).
258
259
260%%-------------------------------------------------------------------------
261%% getopts(SocketType, Socket [, Opts]) -> ok | {error, Reason}
262%%     SocketType = ip_comm | {ssl, _}
263%%     Socket = socket()
264%%     Opts   = socket_options()
265%% Description: Gets the values for some options.
266%%-------------------------------------------------------------------------
267getopts(SocketType, Socket) ->
268    Opts = [packet, packet_size, recbuf, sndbuf, priority, tos, send_timeout],
269    getopts(SocketType, Socket, Opts).
270
271getopts({ip_comm, _}, Socket, Options) ->
272    getopts(ip_comm, Socket, Options);
273
274getopts(ip_comm, Socket, Options) ->
275    case inet:getopts(Socket, Options) of
276	{ok, SocketOpts} ->
277	    SocketOpts;
278	{error, _} ->
279	    []
280    end;
281
282%% Wrapper for backaward compatibillity
283getopts({ssl, SSLConfig}, Socket, Options) ->
284    getopts({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Options);
285
286getopts({essl, _}, Socket, Options) ->
287    getopts_ssl(Socket, Options).
288
289getopts_ssl(Socket, Options) ->
290    case ssl:getopts(Socket, Options) of
291	{ok, SocketOpts} ->
292	    SocketOpts;
293	{error, _} ->
294	    []
295    end.
296
297
298%%-------------------------------------------------------------------------
299%% getstat(SocketType, Socket) -> socket_stats()
300%%     SocketType = ip_comm | {ssl, _}
301%%     Socket = socket()
302%%     socket_stats() = list()
303%% Description: Gets the socket stats values for the socket
304%%-------------------------------------------------------------------------
305getstat(ip_comm = _SocketType, Socket) ->
306    case inet:getstat(Socket) of
307	{ok, Stats} ->
308	    Stats;
309	{error, _} ->
310	    []
311    end;
312
313%% Wrapper for backaward compatibillity
314getstat({ssl, SSLConfig}, Socket) ->
315    getstat({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket);
316
317getstat({essl, _} = _SocketType, _Socket) ->
318    [].
319
320
321%%-------------------------------------------------------------------------
322%% send(RequestOrSocketType, Socket, Message) -> ok | {error, Reason}
323%%     SocketType = ip_comm | {ssl, _}
324%%     Socket = socket()
325%%     Message = list() | binary()
326%% Description: Sends a packet on a socket, using either gen_tcp or ssl.
327%%-------------------------------------------------------------------------
328send(ip_comm, Socket, Message) ->
329    gen_tcp:send(Socket, Message);
330send({ip_comm, _}, Socket, Message) ->
331    gen_tcp:send(Socket, Message);
332
333%% Wrapper for backaward compatibillity
334send({ssl, SSLConfig}, Socket, Message) ->
335    send({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Message);
336
337send({essl, _}, Socket, Message) ->
338    ssl:send(Socket, Message).
339
340%%-------------------------------------------------------------------------
341%% close(SocketType, Socket) -> ok | {error, Reason}
342%%     SocketType = ip_comm | {ssl, _}
343%%     Socket = socket()
344%%
345%% Description: Closes a socket, using either gen_tcp or ssl.
346%%-------------------------------------------------------------------------
347close(ip_comm, Socket) ->
348    gen_tcp:close(Socket);
349close({ip_comm, []}, Socket) ->
350    gen_tcp:close(Socket);
351
352%% Wrapper for backaward compatibillity
353close({ssl, SSLConfig}, Socket) ->
354    close({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket);
355
356close({essl, _}, Socket) ->
357    ssl:close(Socket).
358
359
360%%-------------------------------------------------------------------------
361%% peername(SocketType, Socket) -> {Port, SockName}
362%%     SocketType = ip_comm | {ssl, _}
363%%     Socket = socket()
364%%     Port = integer()  (-1 if error occured)
365%%     PeerName = string()
366%%
367%% Description: Returns the address and port for the other end of a
368%% connection, usning either gen_tcp or ssl.
369%%-------------------------------------------------------------------------
370peername(ip_comm, Socket) ->
371    do_peername(inet:peername(Socket));
372peername({ip_comm, _}, Socket) ->
373    do_peername(inet:peername(Socket));
374
375%% Wrapper for backaward compatibillity
376peername({ssl, SSLConfig}, Socket) ->
377    peername({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket);
378
379peername({essl, _}, Socket) ->
380    do_peername(ssl:peername(Socket)).
381
382do_peername({ok, {Addr, Port}})
383  when is_tuple(Addr) andalso (size(Addr) =:= 4) ->
384    PeerName = ipv4_name(Addr),
385    {Port, PeerName};
386do_peername({ok, {Addr, Port}})
387  when is_tuple(Addr) andalso (size(Addr) =:= 8) ->
388    PeerName = ipv6_name(Addr),
389    {Port, PeerName};
390do_peername({error, _}) ->
391    {-1, "unknown"}.
392
393
394%%-------------------------------------------------------------------------
395%% sockname(SocketType, Socket) -> {Port, SockName}
396%%     SocketType = ip_comm | {ssl, _}
397%%     Socket = socket()
398%%     Port = integer()  (-1 if error occured)
399%%     SockName = string()
400%%
401%% Description: Returns the address and port for the local (our) end
402%% other end of connection, using either gen_tcp or ssl.
403%%-------------------------------------------------------------------------
404sockname(ip_comm, Socket) ->
405    do_sockname(inet:sockname(Socket));
406sockname({ip_comm, _}, Socket) ->
407    do_sockname(inet:sockname(Socket));
408%% Wrapper for backaward compatibillity
409sockname({ssl, SSLConfig}, Socket) ->
410    sockname({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket);
411
412sockname({essl, _}, Socket) ->
413    do_sockname(ssl:sockname(Socket)).
414
415do_sockname({ok, {Addr, Port}})
416  when is_tuple(Addr) andalso (size(Addr) =:= 4) ->
417    SockName = ipv4_name(Addr),
418    {Port, SockName};
419do_sockname({ok, {Addr, Port}})
420  when is_tuple(Addr) andalso (size(Addr) =:= 8) ->
421    SockName = ipv6_name(Addr),
422    {Port, SockName};
423do_sockname({error, _}) ->
424    {-1, "unknown"}.
425
426
427%%-------------------------------------------------------------------------
428%% resolve() -> HostName
429%%     HostName = string()
430%%
431%% Description: Returns the local hostname.
432%%-------------------------------------------------------------------------
433resolve() ->
434    {ok, Name} = inet:gethostname(),
435    Name.
436
437
438%%-------------------------------------------------------------------------
439%% ipv4_name(Ipv4Addr) -> string()
440%% ipv6_name(Ipv6Addr) -> string()
441%%     Ipv4Addr = ip4_address()
442%%     Ipv6Addr = ip6_address()
443%%
444%% Description: Returns the local hostname.
445%%-------------------------------------------------------------------------
446ipv4_name({A, B, C, D}) ->
447    integer_to_list(A) ++ "." ++
448	integer_to_list(B) ++ "." ++
449	integer_to_list(C) ++ "." ++
450	integer_to_list(D).
451
452ipv6_name({A, B, C, D, E, F, G, H}) ->
453    http_util:integer_to_hexlist(A) ++ ":"++
454	http_util:integer_to_hexlist(B) ++ ":" ++
455	http_util:integer_to_hexlist(C) ++ ":" ++
456	http_util:integer_to_hexlist(D) ++ ":" ++
457	http_util:integer_to_hexlist(E) ++ ":" ++
458	http_util:integer_to_hexlist(F) ++ ":" ++
459	http_util:integer_to_hexlist(G) ++ ":" ++
460	http_util:integer_to_hexlist(H).
461
462
463close_tag(ip_comm) ->
464    tcp_closed;
465close_tag(_) ->
466    ssl_closed.
467
468%%%========================================================================
469%%% Internal functions
470%%%========================================================================
471
472%% -- sock_opts --
473%% Address any comes from directive: BindAddress "*"
474sock_opts(undefined, Opts) ->
475    sock_opts(Opts);
476sock_opts(any = Addr, Opts) ->
477    sock_opts([{ip, Addr} | Opts]);
478sock_opts(Addr, Opts) ->
479    sock_opts([{ip, Addr} | Opts]).
480
481sock_opts(Opts) ->
482    [{packet, 0}, {active, false} | Opts].
483
484
485%% -- negotiate --
486negotiate(ip_comm,_,_) ->
487    ok;
488negotiate({ip_comm, _},_,_) ->
489    ok;
490negotiate({ssl, SSLConfig}, Socket, Timeout) ->
491    negotiate({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Timeout);
492negotiate({essl, _}, Socket, Timeout) ->
493    negotiate_ssl(Socket, Timeout).
494
495negotiate_ssl(Socket, Timeout) ->
496    ssl:handshake(Socket, Timeout).
497