PageRenderTime 6ms CodeModel.GetById 4ms app.highlight 32ms RepoModel.GetById 3ms app.codeStats 0ms

/lib/inets/src/http_lib/http_transport.erl

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