capricorn 2.0.8 → 2.0.9

Sign up to get free protection for your applications and to get access to all the features.
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 =======================================================