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