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:handshake(Socket, Timeout). 491