capricorn 2.0.8 → 2.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. data/erlang/lib/capricorn/ebin/capricorn.app +2 -1
  2. data/erlang/lib/capricorn/include/capricorn.hrl +1 -0
  3. data/erlang/lib/capricorn/src/cap_cluster_gems.erl +6 -1
  4. data/erlang/lib/capricorn/src/cap_console_dispatcher.erl +214 -0
  5. data/erlang/lib/capricorn/src/cap_machine_apps.erl +25 -1
  6. data/erlang/lib/capricorn/src/cap_sup.erl +14 -0
  7. data/erlang/lib/ejson/Makefile +24 -0
  8. data/erlang/lib/ejson/ebin/ejson.app +9 -0
  9. data/erlang/lib/ejson/include/ejson.hrl +40 -0
  10. data/erlang/lib/ejson/rebar.config +3 -0
  11. data/erlang/lib/ejson/src/ejson.erl +22 -0
  12. data/erlang/lib/ejson/src/ejson_decode.erl +337 -0
  13. data/erlang/lib/ejson/src/ejson_encode.erl +124 -0
  14. data/erlang/lib/ejson/test/arrays.escript +47 -0
  15. data/erlang/lib/ejson/test/compound.escript +56 -0
  16. data/erlang/lib/ejson/test/literals.escript +30 -0
  17. data/erlang/lib/ejson/test/numbers.escript +70 -0
  18. data/erlang/lib/ejson/test/objects.escript +51 -0
  19. data/erlang/lib/ejson/test/strings.escript +49 -0
  20. data/erlang/lib/ejson/test/timing.escript +43 -0
  21. data/erlang/lib/ejson/test/timing.json +382 -0
  22. data/erlang/lib/ejson/vendor/mochijson2.erl +621 -0
  23. data/erlang/lib/ejson/vendor/rfc4627.erl +625 -0
  24. data/erlang/lib/misultin/LICENSE.txt +41 -0
  25. data/erlang/lib/misultin/Makefile +26 -0
  26. data/erlang/lib/misultin/README.txt +120 -0
  27. data/erlang/lib/misultin/ebin/misultin.app +9 -0
  28. data/erlang/lib/misultin/examples/misultin_compress.erl +43 -0
  29. data/erlang/lib/misultin/examples/misultin_echo.erl +58 -0
  30. data/erlang/lib/misultin/examples/misultin_file.erl +43 -0
  31. data/erlang/lib/misultin/examples/misultin_gen_server.erl +158 -0
  32. data/erlang/lib/misultin/examples/misultin_get_variable.erl +55 -0
  33. data/erlang/lib/misultin/examples/misultin_hello_world.erl +43 -0
  34. data/erlang/lib/misultin/examples/misultin_rest.erl +68 -0
  35. data/erlang/lib/misultin/examples/misultin_ssl.erl +51 -0
  36. data/erlang/lib/misultin/examples/misultin_stream.erl +55 -0
  37. data/erlang/lib/misultin/examples/misultin_websocket_event_example.erl +103 -0
  38. data/erlang/lib/misultin/examples/misultin_websocket_example.erl +95 -0
  39. data/erlang/lib/misultin/include/misultin.hrl +95 -0
  40. data/erlang/lib/misultin/make.bat +55 -0
  41. data/erlang/lib/misultin/priv/README.txt +12 -0
  42. data/erlang/lib/misultin/priv/test_certificate.pem +21 -0
  43. data/erlang/lib/misultin/priv/test_privkey.pem +18 -0
  44. data/erlang/lib/misultin/rebar.config +3 -0
  45. data/erlang/lib/misultin/src/misultin.app.src +9 -0
  46. data/erlang/lib/misultin/src/misultin.erl +338 -0
  47. data/erlang/lib/misultin/src/misultin_http.erl +488 -0
  48. data/erlang/lib/misultin/src/misultin_req.erl +280 -0
  49. data/erlang/lib/misultin/src/misultin_socket.erl +193 -0
  50. data/erlang/lib/misultin/src/misultin_utility.erl +357 -0
  51. data/erlang/lib/misultin/src/misultin_websocket.erl +252 -0
  52. data/erlang/lib/misultin/src/misultin_ws.erl +78 -0
  53. data/erlang/rebar.config +2 -0
  54. data/erlang/rel/overlay/etc/capricorn/app.config +4 -0
  55. data/erlang/rel/reltool.config +5 -0
  56. data/lib/capricorn/recipes/apache-debian.rb +1 -1
  57. data/lib/capricorn/recipes/centos-plesk.rb +1 -1
  58. data/lib/capricorn/recipes/debian-plesk95.rb +1 -2
  59. data/lib/capricorn/recipes/macports.rb +1 -1
  60. data/lib/capricorn/version.rb +1 -1
  61. metadata +51 -4
@@ -0,0 +1,280 @@
1
+ % ==========================================================================================================
2
+ % MISULTIN - Request
3
+ %
4
+ % >-|-|-(°>
5
+ %
6
+ % Copyright (C) 2010, Roberto Ostinelli <roberto@ostinelli.net>,
7
+ % Bob Ippolito <bob@mochimedia.com> for Mochi Media, Inc.
8
+ % All rights reserved.
9
+ %
10
+ % Code portions from Bob Ippolito have been originally taken under MIT license from MOCHIWEB:
11
+ % <http://code.google.com/p/mochiweb/>
12
+ %
13
+ % BSD License
14
+ %
15
+ % Redistribution and use in source and binary forms, with or without modification, are permitted provided
16
+ % that the following conditions are met:
17
+ %
18
+ % * Redistributions of source code must retain the above copyright notice, this list of conditions and the
19
+ % following disclaimer.
20
+ % * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
21
+ % the following disclaimer in the documentation and/or other materials provided with the distribution.
22
+ % * Neither the name of the authors nor the names of its contributors may be used to endorse or promote
23
+ % products derived from this software without specific prior written permission.
24
+ %
25
+ % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
26
+ % WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27
+ % PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28
+ % ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29
+ % TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
+ % HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31
+ % NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ % POSSIBILITY OF SUCH DAMAGE.
33
+ % ==========================================================================================================
34
+ -module(misultin_req, [Req, SocketPid]).
35
+ -vsn("0.6.1").
36
+
37
+ % macros
38
+ -define(PERCENT, 37). % $\%
39
+ -define(FULLSTOP, 46). % $\.
40
+ -define(IS_HEX(C), ((C >= $0 andalso C =< $9) orelse
41
+ (C >= $a andalso C =< $f) orelse
42
+ (C >= $A andalso C =< $F))).
43
+ -define(FILE_READ_BUFFER, 64*1012).
44
+
45
+ % API
46
+ -export([raw/0]).
47
+ -export([ok/1, ok/2, ok/3, respond/2, respond/3, respond/4, stream/1, stream/2, stream/3]).
48
+ -export([get/1, parse_qs/0, parse_post/0, file/1, file/2, resource/1]).
49
+
50
+ % includes
51
+ -include("../include/misultin.hrl").
52
+ -include_lib("kernel/include/file.hrl").
53
+
54
+
55
+ % ============================ \/ API ======================================================================
56
+
57
+ % Description: Returns raw request content.
58
+ raw() ->
59
+ Req.
60
+
61
+ % Description: Get request info.
62
+ get(socket) ->
63
+ Req#req.socket;
64
+ get(socket_mode) ->
65
+ Req#req.socket_mode;
66
+ get(peer_addr) ->
67
+ Req#req.peer_addr;
68
+ get(peer_port) ->
69
+ Req#req.peer_port;
70
+ get(peer_cert) ->
71
+ Req#req.peer_cert;
72
+ get(connection) ->
73
+ Req#req.connection;
74
+ get(content_length) ->
75
+ Req#req.content_length;
76
+ get(vsn) ->
77
+ Req#req.vsn;
78
+ get(method) ->
79
+ Req#req.method;
80
+ get(uri) ->
81
+ Req#req.uri;
82
+ get(args) ->
83
+ Req#req.args;
84
+ get(headers) ->
85
+ Req#req.headers;
86
+ get(body) ->
87
+ Req#req.body.
88
+
89
+ % Description: Formats a 200 response.
90
+ ok(Template) ->
91
+ ok([], Template).
92
+ ok(Headers, Template) ->
93
+ respond(200, Headers, Template).
94
+ ok(Headers, Template, Vars) ->
95
+ respond(200, Headers, Template, Vars).
96
+
97
+ % Description: Formats a response.
98
+ respond(HttpCode, Template) ->
99
+ respond(HttpCode, [], Template).
100
+ respond(HttpCode, Headers, Template) ->
101
+ {HttpCode, Headers, Template}.
102
+ respond(HttpCode, Headers, Template, Vars) when is_list(Template) =:= true ->
103
+ {HttpCode, Headers, io_lib:format(Template, Vars)}.
104
+
105
+ % Description: Start stream.
106
+ stream(close) ->
107
+ catch SocketPid ! stream_close;
108
+ stream(head) ->
109
+ stream(head, 200, []);
110
+ stream(Template) ->
111
+ catch SocketPid ! {stream_data, Template}.
112
+ stream(head, Headers) ->
113
+ stream(head, 200, Headers);
114
+ stream(Template, Vars) when is_list(Template) =:= true ->
115
+ catch SocketPid ! {stream_data, io_lib:format(Template, Vars)}.
116
+ stream(head, HttpCode, Headers) ->
117
+ catch SocketPid ! {stream_head, HttpCode, Headers}.
118
+
119
+ % Description: Sends a file to the browser.
120
+ file(FilePath) ->
121
+ file_send(FilePath, []).
122
+ % Description: Sends a file for download.
123
+ file(attachment, FilePath) ->
124
+ % get filename
125
+ FileName = filename:basename(FilePath),
126
+ file_send(FilePath, [{'Content-Disposition', lists:flatten(io_lib:format("attachment; filename=~s", [FileName]))}]).
127
+
128
+ % Description: Parse QueryString
129
+ parse_qs() ->
130
+ parse_qs(Req#req.args).
131
+
132
+ % Description: Parse Post
133
+ parse_post() ->
134
+ % get header confirmation
135
+ case misultin_utility:get_key_value('Content-Type', Req#req.headers) of
136
+ undefined ->
137
+ [];
138
+ ContentType ->
139
+ [Type|_CharSet] = string:tokens(ContentType, ";"),
140
+ case Type of
141
+ "application/x-www-form-urlencoded" ->
142
+ parse_qs(Req#req.body);
143
+ _Other ->
144
+ []
145
+ end
146
+ end.
147
+
148
+ % Description: Sets resource elements for restful services.
149
+ resource(Options) when is_list(Options) ->
150
+ % clean uri
151
+ {_UriType, RawUri} = Req#req.uri,
152
+ Uri = lists:foldl(fun(Option, Acc) -> clean_uri(Option, Acc) end, RawUri, Options),
153
+ % split
154
+ string:tokens(Uri, "/").
155
+
156
+ % ============================ /\ API ======================================================================
157
+
158
+
159
+
160
+ % ============================ \/ INTERNAL FUNCTIONS =======================================================
161
+
162
+ % parse querystring & post
163
+ parse_qs(Binary) when is_binary(Binary) ->
164
+ parse_qs(binary_to_list(Binary));
165
+ parse_qs(String) ->
166
+ parse_qs(String, []).
167
+ parse_qs([], Acc) ->
168
+ lists:reverse(Acc);
169
+ parse_qs(String, Acc) ->
170
+ {Key, Rest} = parse_qs_key(String),
171
+ {Value, Rest1} = parse_qs_value(Rest),
172
+ parse_qs(Rest1, [{Key, Value} | Acc]).
173
+ parse_qs_key(String) ->
174
+ parse_qs_key(String, []).
175
+ parse_qs_key([], Acc) ->
176
+ {qs_revdecode(Acc), ""};
177
+ parse_qs_key([$= | Rest], Acc) ->
178
+ {qs_revdecode(Acc), Rest};
179
+ parse_qs_key(Rest=[$; | _], Acc) ->
180
+ {qs_revdecode(Acc), Rest};
181
+ parse_qs_key(Rest=[$& | _], Acc) ->
182
+ {qs_revdecode(Acc), Rest};
183
+ parse_qs_key([C | Rest], Acc) ->
184
+ parse_qs_key(Rest, [C | Acc]).
185
+ parse_qs_value(String) ->
186
+ parse_qs_value(String, []).
187
+ parse_qs_value([], Acc) ->
188
+ {qs_revdecode(Acc), ""};
189
+ parse_qs_value([$; | Rest], Acc) ->
190
+ {qs_revdecode(Acc), Rest};
191
+ parse_qs_value([$& | Rest], Acc) ->
192
+ {qs_revdecode(Acc), Rest};
193
+ parse_qs_value([C | Rest], Acc) ->
194
+ parse_qs_value(Rest, [C | Acc]).
195
+
196
+ % revdecode
197
+ qs_revdecode(S) ->
198
+ qs_revdecode(S, []).
199
+ qs_revdecode([], Acc) ->
200
+ Acc;
201
+ qs_revdecode([$+ | Rest], Acc) ->
202
+ qs_revdecode(Rest, [$\s | Acc]);
203
+ qs_revdecode([Lo, Hi, ?PERCENT | Rest], Acc) when ?IS_HEX(Lo), ?IS_HEX(Hi) ->
204
+ qs_revdecode(Rest, [(unhexdigit(Lo) bor (unhexdigit(Hi) bsl 4)) | Acc]);
205
+ qs_revdecode([C | Rest], Acc) ->
206
+ qs_revdecode(Rest, [C | Acc]).
207
+
208
+ % unexdigit
209
+ unhexdigit(C) when C >= $0, C =< $9 -> C - $0;
210
+ unhexdigit(C) when C >= $a, C =< $f -> C - $a + 10;
211
+ unhexdigit(C) when C >= $A, C =< $F -> C - $A + 10.
212
+
213
+ % unquote
214
+ unquote(Binary) when is_binary(Binary) ->
215
+ unquote(binary_to_list(Binary));
216
+ unquote(String) ->
217
+ qs_revdecode(lists:reverse(String)).
218
+
219
+ % Description: Clean URI.
220
+ clean_uri(lowercase, Uri) ->
221
+ string:to_lower(Uri);
222
+ clean_uri(urldecode, Uri) ->
223
+ unquote(Uri);
224
+ % ignore unexisting option
225
+ clean_uri(_Unavailable, Uri) ->
226
+ Uri.
227
+
228
+ % sending of a file
229
+ file_send(FilePath, Headers) ->
230
+ % get file size
231
+ case file:read_file_info(FilePath) of
232
+ {ok, FileInfo} ->
233
+ % get filesize
234
+ FileSize = FileInfo#file_info.size,
235
+ % send headers
236
+ HeadersFull = [{'Content-Type', misultin_utility:get_content_type(FilePath)}, {'Content-Size', FileSize} | Headers],
237
+ stream(head, HeadersFull),
238
+ % do the gradual sending
239
+ case file_open_and_send(FilePath) of
240
+ {error, _Reason} ->
241
+ {raw, misultin_utility:get_http_status_code(500)};
242
+ ok ->
243
+ % sending successful
244
+ ok
245
+ end;
246
+ {error, _Reason} ->
247
+ {raw, misultin_utility:get_http_status_code(500)}
248
+ end.
249
+ file_open_and_send(FilePath) ->
250
+ case file:open(FilePath, [read, binary]) of
251
+ {error, Reason} ->
252
+ {error, Reason};
253
+ {ok, IoDevice} ->
254
+ % read portions
255
+ case file_read_and_send(IoDevice, 0) of
256
+ {error, Reason} ->
257
+ file:close(IoDevice),
258
+ {error, Reason};
259
+ ok ->
260
+ file:close(IoDevice),
261
+ ok
262
+ end
263
+ end.
264
+ file_read_and_send(IoDevice, Position) ->
265
+ % read buffer
266
+ case file:pread(IoDevice, Position, ?FILE_READ_BUFFER) of
267
+ {ok, Data} ->
268
+ % file read, send
269
+ stream(Data),
270
+ % loop
271
+ file_read_and_send(IoDevice, Position + ?FILE_READ_BUFFER);
272
+ eof ->
273
+ % finished, close
274
+ stream(close),
275
+ ok;
276
+ {error, Reason} ->
277
+ {error, Reason}
278
+ end.
279
+
280
+ % ============================ /\ INTERNAL FUNCTIONS =======================================================
@@ -0,0 +1,193 @@
1
+ % ==========================================================================================================
2
+ % MISULTIN - Socket
3
+ %
4
+ % >-|-|-(°>
5
+ %
6
+ % Copyright (C) 2010, Roberto Ostinelli <roberto@ostinelli.net>, Sean Hinde.
7
+ % All rights reserved.
8
+ %
9
+ % Code portions from Sean Hinde have been originally taken under BSD license from Trapexit at the address:
10
+ % <http://www.trapexit.org/A_fast_web_server_demonstrating_some_undocumented_Erlang_features>
11
+ %
12
+ % BSD License
13
+ %
14
+ % Redistribution and use in source and binary forms, with or without modification, are permitted provided
15
+ % that the following conditions are met:
16
+ %
17
+ % * Redistributions of source code must retain the above copyright notice, this list of conditions and the
18
+ % following disclaimer.
19
+ % * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
20
+ % the following disclaimer in the documentation and/or other materials provided with the distribution.
21
+ % * Neither the name of the authors nor the names of its contributors may be used to endorse or promote
22
+ % products derived from this software without specific prior written permission.
23
+ %
24
+ % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
25
+ % WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26
+ % PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
27
+ % ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28
+ % TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
+ % HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30
+ % NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
+ % POSSIBILITY OF SUCH DAMAGE.
32
+ % ==========================================================================================================
33
+ -module(misultin_socket).
34
+ -vsn("0.6.1").
35
+
36
+ % API
37
+ -export([start_link/5]).
38
+
39
+ % callbacks
40
+ -export([listener/5]).
41
+
42
+ % internal
43
+ -export([listen/3, setopts/3, recv/4, send/3, close/2]).
44
+
45
+ % includes
46
+ -include("../include/misultin.hrl").
47
+
48
+
49
+ % ============================ \/ API ======================================================================
50
+
51
+ % Function: {ok,Pid} | ignore | {error, Error}
52
+ % Description: Starts the socket.
53
+ start_link(ListenSocket, ListenPort, RecvTimeout, SocketMode, CustomOpts) ->
54
+ proc_lib:spawn_link(?MODULE, listener, [ListenSocket, ListenPort, RecvTimeout, SocketMode, CustomOpts]).
55
+
56
+ % Function: {ok,Pid} | ignore | {error, Error}
57
+ % Description: Starts the socket.
58
+ listener(ListenSocket, ListenPort, RecvTimeout, SocketMode, CustomOpts) ->
59
+ case catch accept(ListenSocket, SocketMode) of
60
+ {ok, {sslsocket, _, _} = Sock} ->
61
+ % received a SSL socket -> spawn a ssl_accept process to avoid locking the main listener
62
+ spawn(fun() ->
63
+ case ssl:ssl_accept(Sock, 60000) of
64
+ ok ->
65
+ create_socket_pid(Sock, ListenPort, RecvTimeout, SocketMode, CustomOpts);
66
+ {error, _Reason} ->
67
+ % could not negotiate a SSL transaction, leave process
68
+ ?LOG_WARNING("could not negotiate a SSL transaction: ~p", [_Reason]),
69
+ catch close(Sock, SocketMode)
70
+ end
71
+ end),
72
+ % get back to accept loop
73
+ listener(ListenSocket, ListenPort, RecvTimeout, SocketMode, CustomOpts);
74
+ {ok, Sock} ->
75
+ % received a HTTP socket
76
+ create_socket_pid(Sock, ListenPort, RecvTimeout, SocketMode, CustomOpts),
77
+ % get back to accept loop
78
+ listener(ListenSocket, ListenPort, RecvTimeout, SocketMode, CustomOpts);
79
+ {error, _Error} ->
80
+ ?LOG_WARNING("accept failed with error: ~p", [_Error]),
81
+ % get back to accept loop
82
+ listener(ListenSocket, ListenPort, RecvTimeout, SocketMode, CustomOpts);
83
+ {'EXIT', Error} ->
84
+ ?LOG_ERROR("accept exited with error: ~p, quitting process", [Error]),
85
+ exit({error, {accept_failed, Error}})
86
+ end.
87
+
88
+ % ============================ /\ API ======================================================================
89
+
90
+
91
+ % ============================ \/ INTERNAL FUNCTIONS =======================================================
92
+
93
+ % start socket Pid
94
+ create_socket_pid(Sock, ListenPort, RecvTimeout, SocketMode, CustomOpts) ->
95
+ ?LOG_DEBUG("accepted an incoming TCP connection in ~p mode on socket ~p, spawning controlling process", [SocketMode, Sock]),
96
+ Pid = spawn(fun() ->
97
+ receive
98
+ set ->
99
+ ?LOG_DEBUG("activated controlling process ~p", [self()]),
100
+ % get peer address and port
101
+ {PeerAddr, PeerPort} = peername(Sock, SocketMode),
102
+ % get peer certificate, if any
103
+ PeerCert = peercert(Sock, SocketMode),
104
+ % jump to external callback
105
+ ?LOG_DEBUG("jump to connection logic", []),
106
+ misultin_http:handle_data(Sock, SocketMode, ListenPort, PeerAddr, PeerPort, PeerCert, RecvTimeout, CustomOpts)
107
+ after 60000 ->
108
+ ?LOG_ERROR("timeout waiting for set in controlling process, closing socket", []),
109
+ catch close(Sock, SocketMode)
110
+ end
111
+ end),
112
+ % set controlling process
113
+ case controlling_process(Sock, Pid, SocketMode) of
114
+ ok ->
115
+ Pid ! set;
116
+ {error, _Reason} ->
117
+ ?LOG_ERROR("could not set controlling process: ~p, closing socket", [_Reason]),
118
+ catch close(Sock, SocketMode)
119
+ end.
120
+
121
+ % socket listen
122
+ listen(Port, Options, http) -> gen_tcp:listen(Port, Options);
123
+ listen(Port, Options, ssl) -> ssl:listen(Port, Options).
124
+
125
+ % socket accept
126
+ accept(ListenSocket, http) -> gen_tcp:accept(ListenSocket);
127
+ accept(ListenSocket, ssl) ->
128
+ try ssl:transport_accept(ListenSocket)
129
+ catch
130
+ error:{badmatch, {error, Reason}} ->
131
+ {error, Reason}
132
+ end.
133
+
134
+ % socket controlling process
135
+ controlling_process(Sock, Pid, http) -> gen_tcp:controlling_process(Sock, Pid);
136
+ controlling_process(Sock, Pid, ssl) -> ssl:controlling_process(Sock, Pid).
137
+
138
+ % Function: -> {PeerAddr, PeerPort} | PeerAddr = list() | undefined | PeerPort = integer() | undefined
139
+ % Description: Get socket peername
140
+ peername(Sock, http) -> peername(Sock, fun inet:peername/1);
141
+ peername(Sock, ssl) -> peername(Sock, fun ssl:peername/1);
142
+ peername(Sock, F) ->
143
+ case F(Sock) of
144
+ {ok, {Addr, Port}} ->
145
+ {Addr, Port};
146
+ {error, _Reason} ->
147
+ {undefined, undefined}
148
+ end.
149
+
150
+ % Function: -> Certificate | undefined
151
+ % Description: Get socket certificate
152
+ peercert(_Sock, http) -> undefined;
153
+ peercert(Sock, ssl) ->
154
+ case ssl:peercert(Sock) of
155
+ {ok, Cert} -> Cert;
156
+ {error, _Reason} -> undefined
157
+ end.
158
+
159
+ % socket set options
160
+ setopts(Sock, Options, http) -> inet:setopts(Sock, Options);
161
+ setopts(Sock, Options, ssl) -> ssl:setopts(Sock, Options).
162
+
163
+ % socket receive
164
+ recv(Sock, Len, RecvTimeout, http) -> gen_tcp:recv(Sock, Len, RecvTimeout);
165
+ recv(Sock, Len, RecvTimeout, ssl) -> ssl:recv(Sock, Len, RecvTimeout).
166
+
167
+ % socket send
168
+ send(Sock, Data, http) -> send(Sock, Data, fun gen_tcp:send/2);
169
+ send(Sock, Data, ssl) -> send(Sock, Data, fun ssl:send/2);
170
+ send(Sock, Data, F) ->
171
+ ?LOG_DEBUG("sending data: ~p", [Data]),
172
+ case F(Sock, Data) of
173
+ ok ->
174
+ ok;
175
+ {error, _Reason} ->
176
+ ?LOG_ERROR("worker crash: ~p", [_Reason]),
177
+ exit(normal)
178
+ end.
179
+
180
+ % TCP close
181
+ close(Sock, http) -> close(Sock, fun gen_tcp:close/1);
182
+ close(Sock, ssl) -> close(Sock, fun ssl:close/1);
183
+ close(Sock, F) ->
184
+ ?LOG_DEBUG("closing socket", []),
185
+ case catch F(Sock) of
186
+ ok ->
187
+ ok;
188
+ _Else ->
189
+ ?LOG_WARNING("could not close socket: ~p", [_Else]),
190
+ exit(normal)
191
+ end.
192
+
193
+ % ============================ /\ INTERNAL FUNCTIONS =======================================================