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