ebb 0.1.0 → 0.2.0
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.
- data/README +4 -7
- data/benchmark/application.rb +12 -4
- data/benchmark/server_test.rb +10 -11
- data/bin/ebb_rails +0 -0
- data/libev/ev.c +235 -128
- data/libev/ev.h +84 -27
- data/libev/ev_epoll.c +30 -22
- data/libev/ev_kqueue.c +30 -22
- data/libev/ev_poll.c +30 -22
- data/libev/ev_port.c +30 -22
- data/libev/ev_select.c +34 -26
- data/libev/ev_vars.h +49 -0
- data/libev/ev_win32.c +31 -23
- data/libev/ev_wrap.h +12 -0
- data/ruby_lib/ebb.rb +94 -67
- data/ruby_lib/ebb/runner.rb +4 -5
- data/ruby_lib/ebb/runner/rails.rb +1 -4
- data/ruby_lib/rack/adapter/rails.rb +5 -0
- data/src/ebb.c +261 -387
- data/src/ebb.h +19 -29
- data/src/ebb_ruby.c +113 -108
- data/src/extconf.rb +0 -1
- data/src/parser.c +1755 -724
- data/src/parser.h +13 -10
- data/test/basic_test.rb +18 -1
- data/test/env_test.rb +6 -5
- data/test/helper.rb +53 -1
- metadata +3 -4
- data/benchmark/bench_results.rb +0 -58
@@ -11,10 +11,7 @@ module Ebb
|
|
11
11
|
# defaults for ebb_rails
|
12
12
|
@options.update(
|
13
13
|
:environment => 'development',
|
14
|
-
:port => 3000
|
15
|
-
# rails has a mutex lock around each request - threaded processing
|
16
|
-
# will only slow things down
|
17
|
-
:threaded_processing => false
|
14
|
+
:port => 3000
|
18
15
|
)
|
19
16
|
|
20
17
|
@parser.on("-e", "--env ENV",
|
data/src/ebb.c
CHANGED
@@ -17,11 +17,9 @@
|
|
17
17
|
#include <signal.h>
|
18
18
|
#include <assert.h>
|
19
19
|
|
20
|
-
#include <pthread.h>
|
21
|
-
#include <glib.h>
|
22
|
-
|
23
20
|
#define EV_STANDALONE 1
|
24
21
|
#include <ev.c>
|
22
|
+
#include <glib.h>
|
25
23
|
|
26
24
|
#include "parser.h"
|
27
25
|
#include "ebb.h"
|
@@ -29,7 +27,14 @@
|
|
29
27
|
#define min(a,b) (a < b ? a : b)
|
30
28
|
#define ramp(a) (a > 0 ? a : 0)
|
31
29
|
|
32
|
-
static
|
30
|
+
static void client_init(ebb_client *client);
|
31
|
+
|
32
|
+
static void set_nonblock(int fd)
|
33
|
+
{
|
34
|
+
int flags = fcntl(fd, F_GETFL, 0);
|
35
|
+
assert(0 <= fcntl(fd, F_SETFL, flags | O_NONBLOCK) && "Setting socket non-block failed!");
|
36
|
+
}
|
37
|
+
|
33
38
|
|
34
39
|
void env_add(ebb_client *client, const char *field, int flen, const char *value, int vlen)
|
35
40
|
{
|
@@ -37,7 +42,7 @@ void env_add(ebb_client *client, const char *field, int flen, const char *value,
|
|
37
42
|
client->parser.overflow_error = TRUE;
|
38
43
|
return;
|
39
44
|
}
|
40
|
-
client->env[client->env_size].type =
|
45
|
+
client->env[client->env_size].type = -1;
|
41
46
|
client->env[client->env_size].field = field;
|
42
47
|
client->env[client->env_size].field_length = flen;
|
43
48
|
client->env[client->env_size].value = value;
|
@@ -70,75 +75,22 @@ void http_field_cb(void *data, const char *field, size_t flen, const char *value
|
|
70
75
|
}
|
71
76
|
|
72
77
|
|
73
|
-
void
|
74
|
-
{
|
75
|
-
ebb_client *client = (ebb_client*)(data);
|
76
|
-
env_add_const(client, EBB_REQUEST_METHOD, at, length);
|
77
|
-
}
|
78
|
-
|
79
|
-
|
80
|
-
void request_uri_cb(void *data, const char *at, size_t length)
|
81
|
-
{
|
82
|
-
ebb_client *client = (ebb_client*)(data);
|
83
|
-
env_add_const(client, EBB_REQUEST_URI, at, length);
|
84
|
-
}
|
85
|
-
|
86
|
-
|
87
|
-
void fragment_cb(void *data, const char *at, size_t length)
|
88
|
-
{
|
89
|
-
ebb_client *client = (ebb_client*)(data);
|
90
|
-
env_add_const(client, EBB_FRAGMENT, at, length);
|
91
|
-
}
|
92
|
-
|
93
|
-
|
94
|
-
void request_path_cb(void *data, const char *at, size_t length)
|
95
|
-
{
|
96
|
-
ebb_client *client = (ebb_client*)(data);
|
97
|
-
env_add_const(client, EBB_REQUEST_PATH, at, length);
|
98
|
-
}
|
99
|
-
|
100
|
-
|
101
|
-
void query_string_cb(void *data, const char *at, size_t length)
|
102
|
-
{
|
103
|
-
ebb_client *client = (ebb_client*)(data);
|
104
|
-
env_add_const(client, EBB_QUERY_STRING, at, length);
|
105
|
-
}
|
106
|
-
|
107
|
-
|
108
|
-
void http_version_cb(void *data, const char *at, size_t length)
|
109
|
-
{
|
110
|
-
ebb_client *client = (ebb_client*)(data);
|
111
|
-
env_add_const(client, EBB_HTTP_VERSION, at, length);
|
112
|
-
}
|
113
|
-
|
114
|
-
|
115
|
-
void content_length_cb(void *data, const char *at, size_t length)
|
78
|
+
void on_element(void *data, int type, const char *at, size_t length)
|
116
79
|
{
|
117
80
|
ebb_client *client = (ebb_client*)(data);
|
118
|
-
env_add_const(client,
|
119
|
-
/* atoi_length - why isn't this in the statndard library? i hate c */
|
120
|
-
assert(client->content_length == 0);
|
121
|
-
int i, mult;
|
122
|
-
for(mult=1, i=length-1; i>=0; i--, mult*=10)
|
123
|
-
client->content_length += (at[i] - '0') * mult;
|
81
|
+
env_add_const(client, type, at, length);
|
124
82
|
}
|
125
83
|
|
126
84
|
|
127
85
|
static void dispatch(ebb_client *client)
|
128
86
|
{
|
129
87
|
ebb_server *server = client->server;
|
130
|
-
|
131
88
|
if(client->open == FALSE)
|
132
89
|
return;
|
133
|
-
|
134
|
-
/* Set the env variables */
|
135
|
-
if(server->port) {
|
136
|
-
env_add_const(client, EBB_SERVER_PORT
|
137
|
-
, server->port
|
138
|
-
, strlen(server->port)
|
139
|
-
);
|
140
|
-
}
|
141
90
|
client->in_use = TRUE;
|
91
|
+
|
92
|
+
/* XXX decide if to use keep-alive or not? */
|
93
|
+
|
142
94
|
server->request_cb(client, server->request_cb_data);
|
143
95
|
}
|
144
96
|
|
@@ -157,77 +109,7 @@ static void on_timeout(struct ev_loop *loop, ev_timer *watcher, int revents)
|
|
157
109
|
}
|
158
110
|
|
159
111
|
#define client_finished_parsing http_parser_is_finished(&client->parser)
|
160
|
-
#define total_request_size (client->content_length + client->parser.nread)
|
161
|
-
|
162
|
-
static void* read_body_into_file(void *_client)
|
163
|
-
{
|
164
|
-
ebb_client *client = (ebb_client*)_client;
|
165
|
-
static unsigned int id;
|
166
|
-
FILE *tmpfile;
|
167
|
-
|
168
|
-
assert(client->open);
|
169
|
-
assert(client->server->open);
|
170
|
-
assert(client->content_length > 0);
|
171
|
-
assert(client_finished_parsing);
|
172
|
-
|
173
|
-
/* set blocking socket */
|
174
|
-
int flags = fcntl(client->fd, F_GETFL, 0);
|
175
|
-
assert(0 <= fcntl(client->fd, F_SETFL, flags & ~O_NONBLOCK));
|
176
|
-
|
177
|
-
sprintf(client->upload_file_filename, "/tmp/ebb_upload_%010d", id++);
|
178
|
-
tmpfile = fopen(client->upload_file_filename, "w+");
|
179
|
-
if(tmpfile == NULL) g_message("Cannot open tmpfile %s", client->upload_file_filename);
|
180
|
-
client->upload_file = tmpfile;
|
181
|
-
|
182
|
-
size_t body_head_length = client->read - client->parser.nread;
|
183
|
-
size_t written = 0, r;
|
184
|
-
while(written < body_head_length) {
|
185
|
-
r = fwrite( client->request_buffer + sizeof(char)*(client->parser.nread + written)
|
186
|
-
, sizeof(char)
|
187
|
-
, body_head_length - written
|
188
|
-
, tmpfile
|
189
|
-
);
|
190
|
-
if(r <= 0) {
|
191
|
-
ebb_client_close(client);
|
192
|
-
return NULL;
|
193
|
-
}
|
194
|
-
written += r;
|
195
|
-
}
|
196
|
-
|
197
|
-
int bufsize = 5*1024;
|
198
|
-
char buffer[bufsize];
|
199
|
-
size_t received;
|
200
|
-
while(written < client->content_length) {
|
201
|
-
received = recv(client->fd
|
202
|
-
, buffer
|
203
|
-
, min(client->content_length - written, bufsize)
|
204
|
-
, 0
|
205
|
-
);
|
206
|
-
if(received < 0) goto error;
|
207
|
-
client->read += received;
|
208
|
-
|
209
|
-
ssize_t w = 0;
|
210
|
-
int rv;
|
211
|
-
while(w < received) {
|
212
|
-
rv = fwrite( buffer + w*sizeof(char)
|
213
|
-
, sizeof(char)
|
214
|
-
, received - w
|
215
|
-
, tmpfile
|
216
|
-
);
|
217
|
-
if(rv <= 0) goto error;
|
218
|
-
w += rv;
|
219
|
-
}
|
220
|
-
written += received;
|
221
|
-
}
|
222
|
-
rewind(tmpfile);
|
223
|
-
// g_debug("%d bytes written to file %s", written, client->upload_file_filename);
|
224
|
-
dispatch(client);
|
225
|
-
return NULL;
|
226
|
-
error:
|
227
|
-
ebb_client_close(client);
|
228
|
-
return NULL;
|
229
|
-
}
|
230
|
-
|
112
|
+
#define total_request_size (client->parser.content_length + client->parser.nread)
|
231
113
|
|
232
114
|
static void on_client_readable(struct ev_loop *loop, ev_io *watcher, int revents)
|
233
115
|
{
|
@@ -244,12 +126,12 @@ static void on_client_readable(struct ev_loop *loop, ev_io *watcher, int revents
|
|
244
126
|
, EBB_BUFFERSIZE - client->read
|
245
127
|
, 0
|
246
128
|
);
|
247
|
-
if(read < 0) goto error;
|
129
|
+
if(read < 0) goto error;
|
248
130
|
if(read == 0) goto error; /* XXX is this the right action to take for read==0 ? */
|
249
131
|
client->read += read;
|
250
132
|
ev_timer_again(loop, &client->timeout_watcher);
|
251
133
|
|
252
|
-
if(client->read == EBB_BUFFERSIZE) goto error;
|
134
|
+
// if(client->read == EBB_BUFFERSIZE) goto error;
|
253
135
|
|
254
136
|
if(FALSE == client_finished_parsing) {
|
255
137
|
http_parser_execute( &client->parser
|
@@ -261,88 +143,144 @@ static void on_client_readable(struct ev_loop *loop, ev_io *watcher, int revents
|
|
261
143
|
}
|
262
144
|
|
263
145
|
if(client_finished_parsing) {
|
264
|
-
|
146
|
+
assert(client->read <= total_request_size);
|
147
|
+
if(total_request_size == client->read || total_request_size > EBB_BUFFERSIZE) {
|
148
|
+
client->body_head = client->request_buffer + client->parser.nread;
|
149
|
+
client->body_head_len = client->read - client->parser.nread;
|
265
150
|
ev_io_stop(loop, watcher);
|
266
|
-
client->nread_from_body = 0;
|
267
151
|
dispatch(client);
|
268
152
|
return;
|
269
153
|
}
|
270
|
-
if(total_request_size > EBB_BUFFERSIZE ) {
|
271
|
-
/* read body into file - in a thread */
|
272
|
-
ev_io_stop(loop, watcher);
|
273
|
-
pthread_t thread;
|
274
|
-
assert(0 <= pthread_create(&thread, NULL, read_body_into_file, client));
|
275
|
-
pthread_detach(thread);
|
276
|
-
return;
|
277
|
-
}
|
278
154
|
}
|
279
155
|
return;
|
280
156
|
error:
|
157
|
+
#ifdef DEBUG
|
281
158
|
if(read < 0) g_message("Error recving data: %s", strerror(errno));
|
159
|
+
#endif
|
282
160
|
ebb_client_close(client);
|
283
161
|
}
|
284
162
|
|
285
|
-
|
163
|
+
|
164
|
+
static void on_client_writable(struct ev_loop *loop, ev_io *watcher, int revents)
|
286
165
|
{
|
287
|
-
|
166
|
+
ebb_client *client = (ebb_client*)(watcher->data);
|
167
|
+
ssize_t sent;
|
168
|
+
|
169
|
+
if(client->status_written == FALSE || client->headers_written == FALSE) {
|
170
|
+
g_message("no status or headers - closing connection.");
|
171
|
+
goto error;
|
172
|
+
}
|
173
|
+
|
174
|
+
if(EV_ERROR & revents) {
|
175
|
+
g_message("on_client_writable() got error event, closing peer");
|
176
|
+
goto error;
|
177
|
+
}
|
178
|
+
|
179
|
+
//if(client->written != 0)
|
180
|
+
// g_debug("total written: %d", (int)(client->written));
|
181
|
+
|
182
|
+
sent = send( client->fd
|
183
|
+
, client->response_buffer->str + sizeof(gchar)*(client->written)
|
184
|
+
, client->response_buffer->len - client->written
|
185
|
+
, 0
|
186
|
+
);
|
187
|
+
if(sent < 0) {
|
288
188
|
#ifdef DEBUG
|
289
|
-
|
290
|
-
for(i=0; i< EBB_BUFFERSIZE; i++)
|
291
|
-
client->request_buffer[i] = 'A';
|
189
|
+
g_message("Error writing: %s", strerror(errno));
|
292
190
|
#endif
|
191
|
+
goto error;
|
192
|
+
} else if(sent == 0) {
|
193
|
+
/* is this the wrong thing to do? */
|
194
|
+
g_message("Sent zero bytes? Closing connection");
|
195
|
+
goto error;
|
196
|
+
}
|
197
|
+
client->written += sent;
|
293
198
|
|
294
|
-
client->
|
295
|
-
client->
|
199
|
+
assert(client->written <= client->response_buffer->len);
|
200
|
+
//g_message("wrote %d bytes. total: %d", (int)sent, (int)(client->written));
|
296
201
|
|
297
|
-
|
298
|
-
|
299
|
-
client->
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
202
|
+
ev_timer_again(loop, &client->timeout_watcher);
|
203
|
+
|
204
|
+
if(client->written == client->response_buffer->len) {
|
205
|
+
/* stop the write watcher. to be restarted by the next call to ebb_client_write_body
|
206
|
+
* or if client->body_written is set (by using ebb_client_release) then
|
207
|
+
* we close the connection
|
208
|
+
*/
|
209
|
+
ev_io_stop(loop, watcher);
|
210
|
+
if(client->body_written) {
|
211
|
+
client->keep_alive ? client_init(client) : ebb_client_close(client);
|
212
|
+
}
|
213
|
+
}
|
214
|
+
return;
|
215
|
+
error:
|
216
|
+
ebb_client_close(client);
|
217
|
+
}
|
218
|
+
|
219
|
+
|
220
|
+
static void client_init(ebb_client *client)
|
221
|
+
{
|
222
|
+
assert(client->in_use == FALSE);
|
223
|
+
|
224
|
+
/* If the client is already open, reuse the fd, just reset all the parameters
|
225
|
+
* this would happen in the case of a keep_alive request
|
226
|
+
*/
|
227
|
+
if(!client->open) {
|
228
|
+
/* DO SOCKET STUFF */
|
229
|
+
socklen_t len;
|
230
|
+
int fd = accept(client->server->fd, (struct sockaddr*)&(client->sockaddr), &len);
|
231
|
+
if(fd < 0) {
|
232
|
+
perror("accept()");
|
233
|
+
return;
|
234
|
+
}
|
235
|
+
client->open = TRUE;
|
236
|
+
client->fd = fd;
|
304
237
|
}
|
305
238
|
|
306
|
-
|
307
|
-
|
239
|
+
set_nonblock(client->fd);
|
240
|
+
|
241
|
+
/* IP Address */
|
242
|
+
if(client->server->port)
|
243
|
+
client->ip = inet_ntoa(client->sockaddr.sin_addr);
|
308
244
|
|
309
245
|
/* INITIALIZE http_parser */
|
310
|
-
http_parser_init(&
|
246
|
+
http_parser_init(&client->parser);
|
311
247
|
client->parser.data = client;
|
312
|
-
client->parser.http_field
|
313
|
-
client->parser.
|
314
|
-
client->parser.request_uri = request_uri_cb;
|
315
|
-
client->parser.fragment = fragment_cb;
|
316
|
-
client->parser.request_path = request_path_cb;
|
317
|
-
client->parser.query_string = query_string_cb;
|
318
|
-
client->parser.http_version = http_version_cb;
|
319
|
-
client->parser.content_length = content_length_cb;
|
248
|
+
client->parser.http_field = http_field_cb;
|
249
|
+
client->parser.on_element = on_element;
|
320
250
|
|
321
251
|
/* OTHER */
|
322
252
|
client->env_size = 0;
|
323
|
-
client->read =
|
324
|
-
client->response_buffer->len = 0; /* see note in ebb_client_close */
|
325
|
-
client->content_length = 0;
|
253
|
+
client->read = 0;
|
326
254
|
if(client->request_buffer == NULL) {
|
255
|
+
/* Only allocate the request_buffer once */
|
327
256
|
client->request_buffer = (char*)malloc(EBB_BUFFERSIZE);
|
328
257
|
}
|
258
|
+
client->keep_alive = FALSE;
|
259
|
+
client->status_written = client->headers_written = client->body_written = FALSE;
|
260
|
+
client->written = 0;
|
329
261
|
|
330
|
-
client->
|
331
|
-
|
332
|
-
client->
|
333
|
-
client->began_transmission = FALSE;
|
262
|
+
if(client->response_buffer != NULL)
|
263
|
+
g_string_free(client->response_buffer, TRUE);
|
264
|
+
client->response_buffer = g_string_new("");
|
334
265
|
|
335
266
|
/* SETUP READ AND TIMEOUT WATCHERS */
|
267
|
+
client->write_watcher.data = client;
|
268
|
+
ev_init (&client->write_watcher, on_client_writable);
|
269
|
+
ev_io_set (&client->write_watcher, client->fd, EV_WRITE | EV_ERROR);
|
270
|
+
/* Note, do not start write_watcher until there is something to be written.
|
271
|
+
* See ebb_client_write_body() */
|
272
|
+
|
336
273
|
client->read_watcher.data = client;
|
337
274
|
ev_init(&client->read_watcher, on_client_readable);
|
338
275
|
ev_io_set(&client->read_watcher, client->fd, EV_READ | EV_ERROR);
|
339
|
-
ev_io_start(server->loop, &client->read_watcher);
|
276
|
+
ev_io_start(client->server->loop, &client->read_watcher);
|
340
277
|
|
341
278
|
client->timeout_watcher.data = client;
|
342
279
|
ev_timer_init(&client->timeout_watcher, on_timeout, EBB_TIMEOUT, EBB_TIMEOUT);
|
343
|
-
ev_timer_start(server->loop, &client->timeout_watcher);
|
280
|
+
ev_timer_start(client->server->loop, &client->timeout_watcher);
|
344
281
|
}
|
345
282
|
|
283
|
+
|
346
284
|
static void on_request(struct ev_loop *loop, ev_io *watcher, int revents)
|
347
285
|
{
|
348
286
|
ebb_server *server = (ebb_server*)(watcher->data);
|
@@ -380,7 +318,7 @@ static void on_request(struct ev_loop *loop, ev_io *watcher, int revents)
|
|
380
318
|
g_debug("%d open connections", count);
|
381
319
|
#endif
|
382
320
|
|
383
|
-
client_init(
|
321
|
+
client_init(client);
|
384
322
|
}
|
385
323
|
|
386
324
|
|
@@ -400,9 +338,10 @@ void ebb_server_init( ebb_server *server
|
|
400
338
|
int i;
|
401
339
|
for(i=0; i < EBB_MAX_CLIENTS; i++) {
|
402
340
|
server->clients[i].request_buffer = NULL;
|
403
|
-
server->clients[i].response_buffer =
|
341
|
+
server->clients[i].response_buffer = NULL;
|
404
342
|
server->clients[i].open = FALSE;
|
405
343
|
server->clients[i].in_use = FALSE;
|
344
|
+
server->clients[i].server = server;
|
406
345
|
}
|
407
346
|
|
408
347
|
server->request_cb = request_cb;
|
@@ -421,9 +360,6 @@ void ebb_server_free(ebb_server *server)
|
|
421
360
|
{
|
422
361
|
ebb_server_unlisten(server);
|
423
362
|
|
424
|
-
int i;
|
425
|
-
for(i=0; i < EBB_MAX_CLIENTS; i++)
|
426
|
-
g_string_free(server->clients[i].response_buffer, TRUE);
|
427
363
|
if(server->port)
|
428
364
|
free(server->port);
|
429
365
|
if(server->socketpath)
|
@@ -439,12 +375,43 @@ void ebb_server_unlisten(ebb_server *server)
|
|
439
375
|
ebb_client *client;
|
440
376
|
ev_io_stop(server->loop, &server->request_watcher);
|
441
377
|
close(server->fd);
|
442
|
-
if(server->socketpath)
|
378
|
+
if(server->socketpath) {
|
443
379
|
unlink(server->socketpath);
|
380
|
+
server->socketpath = NULL;
|
381
|
+
}
|
382
|
+
if(server->port) {
|
383
|
+
free(server->port);
|
384
|
+
server->port = NULL;
|
385
|
+
}
|
444
386
|
server->open = FALSE;
|
445
387
|
}
|
446
388
|
}
|
447
389
|
|
390
|
+
|
391
|
+
int ebb_server_listen_on_fd(ebb_server *server, const int sfd)
|
392
|
+
{
|
393
|
+
if (listen(sfd, EBB_MAX_CLIENTS) < 0) {
|
394
|
+
perror("listen()");
|
395
|
+
return -1;
|
396
|
+
}
|
397
|
+
|
398
|
+
set_nonblock(sfd); /* XXX: superfluous? */
|
399
|
+
|
400
|
+
server->fd = sfd;
|
401
|
+
assert(server->port == NULL);
|
402
|
+
assert(server->socketpath == NULL);
|
403
|
+
assert(server->open == FALSE);
|
404
|
+
server->open = TRUE;
|
405
|
+
|
406
|
+
server->request_watcher.data = server;
|
407
|
+
ev_init (&server->request_watcher, on_request);
|
408
|
+
ev_io_set (&server->request_watcher, server->fd, EV_READ | EV_ERROR);
|
409
|
+
ev_io_start (server->loop, &server->request_watcher);
|
410
|
+
|
411
|
+
return server->fd;
|
412
|
+
}
|
413
|
+
|
414
|
+
|
448
415
|
int ebb_server_listen_on_port(ebb_server *server, const int port)
|
449
416
|
{
|
450
417
|
int sfd = -1;
|
@@ -457,12 +424,6 @@ int ebb_server_listen_on_port(ebb_server *server, const int port)
|
|
457
424
|
goto error;
|
458
425
|
}
|
459
426
|
|
460
|
-
flags = fcntl(sfd, F_GETFL, 0);
|
461
|
-
if(fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
462
|
-
perror("setting O_NONBLOCK");
|
463
|
-
goto error;
|
464
|
-
}
|
465
|
-
|
466
427
|
flags = 1;
|
467
428
|
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
|
468
429
|
setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
|
@@ -483,36 +444,79 @@ int ebb_server_listen_on_port(ebb_server *server, const int port)
|
|
483
444
|
perror("bind()");
|
484
445
|
goto error;
|
485
446
|
}
|
486
|
-
|
487
|
-
|
447
|
+
|
448
|
+
int ret = ebb_server_listen_on_fd(server, sfd);
|
449
|
+
if (ret >= 0) {
|
450
|
+
assert(server->port == NULL);
|
451
|
+
server->port = malloc(sizeof(char)*8); /* for easy access to the port */
|
452
|
+
sprintf(server->port, "%d", port);
|
453
|
+
}
|
454
|
+
return ret;
|
455
|
+
error:
|
456
|
+
if(sfd > 0) close(sfd);
|
457
|
+
return -1;
|
458
|
+
}
|
459
|
+
|
460
|
+
|
461
|
+
int ebb_server_listen_on_unix_socket(ebb_server *server, const char *socketpath)
|
462
|
+
{
|
463
|
+
int sfd = -1;
|
464
|
+
struct linger ling = {0, 0};
|
465
|
+
struct sockaddr_un addr;
|
466
|
+
struct stat tstat;
|
467
|
+
int flags =1;
|
468
|
+
int old_umask = -1;
|
469
|
+
int access_mask = 0777;
|
470
|
+
|
471
|
+
if(( sfd = socket(AF_UNIX, SOCK_STREAM, 0) ) == -1) {
|
472
|
+
perror("socket()");
|
488
473
|
goto error;
|
489
474
|
}
|
490
|
-
server->fd = sfd;
|
491
|
-
server->port = malloc(sizeof(char)*8); /* for easy access to the port */
|
492
|
-
sprintf(server->port, "%d", port);
|
493
|
-
assert(server->open == FALSE);
|
494
|
-
server->open = TRUE;
|
495
475
|
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
476
|
+
/* Clean up a previous socket file if we left it around */
|
477
|
+
if(lstat(socketpath, &tstat) == 0 && S_ISSOCK(tstat.st_mode)) {
|
478
|
+
unlink(socketpath);
|
479
|
+
}
|
500
480
|
|
501
|
-
|
481
|
+
flags = 1;
|
482
|
+
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
|
483
|
+
setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
|
484
|
+
setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
|
485
|
+
|
486
|
+
/*
|
487
|
+
* the memset call clears nonstandard fields in some impementations
|
488
|
+
* that otherwise mess things up.
|
489
|
+
*/
|
490
|
+
memset(&addr, 0, sizeof(addr));
|
491
|
+
|
492
|
+
addr.sun_family = AF_UNIX;
|
493
|
+
strcpy(addr.sun_path, socketpath);
|
494
|
+
old_umask = umask( ~(access_mask & 0777) );
|
495
|
+
|
496
|
+
if(bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
497
|
+
perror("bind()");
|
498
|
+
goto error;
|
499
|
+
}
|
500
|
+
umask(old_umask);
|
501
|
+
|
502
|
+
int ret = ebb_server_listen_on_fd(server, sfd);
|
503
|
+
if (ret >= 0) {
|
504
|
+
assert(server->socketpath == NULL);
|
505
|
+
server->socketpath = strdup(socketpath);
|
506
|
+
}
|
507
|
+
return ret;
|
502
508
|
error:
|
503
509
|
if(sfd > 0) close(sfd);
|
504
510
|
return -1;
|
505
511
|
}
|
506
512
|
|
507
513
|
|
508
|
-
int
|
514
|
+
int ebb_server_clients_in_use_p(ebb_server *server)
|
509
515
|
{
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
// server_listen(server);
|
515
|
-
// return fd;
|
516
|
+
int i;
|
517
|
+
for(i = 0; i < EBB_MAX_CLIENTS; i++)
|
518
|
+
if(server->clients[i].in_use) return TRUE;
|
519
|
+
return FALSE;
|
516
520
|
}
|
517
521
|
|
518
522
|
|
@@ -520,6 +524,21 @@ void ebb_client_release(ebb_client *client)
|
|
520
524
|
{
|
521
525
|
assert(client->in_use);
|
522
526
|
client->in_use = FALSE;
|
527
|
+
|
528
|
+
if(client->headers_written == FALSE) {
|
529
|
+
g_string_append(client->response_buffer, "\r\n");
|
530
|
+
client->headers_written = TRUE;
|
531
|
+
}
|
532
|
+
client->body_written = TRUE;
|
533
|
+
|
534
|
+
/* If the write_watcher isn't yet active, then start it. It could be that
|
535
|
+
* we're streaming and the watcher has been stopped. In that case we
|
536
|
+
* start it again since we have more to write. */
|
537
|
+
if(ev_is_active(&client->write_watcher) == FALSE) {
|
538
|
+
set_nonblock(client->fd);
|
539
|
+
ev_io_start(client->server->loop, &client->write_watcher);
|
540
|
+
}
|
541
|
+
|
523
542
|
if(client->written == client->response_buffer->len)
|
524
543
|
ebb_client_close(client);
|
525
544
|
}
|
@@ -532,17 +551,10 @@ void ebb_client_close(ebb_client *client)
|
|
532
551
|
ev_io_stop(client->server->loop, &client->write_watcher);
|
533
552
|
ev_timer_stop(client->server->loop, &client->timeout_watcher);
|
534
553
|
|
535
|
-
|
536
|
-
fclose(client->upload_file);
|
537
|
-
unlink(client->upload_file_filename);
|
538
|
-
}
|
554
|
+
client->ip = NULL;
|
539
555
|
|
540
|
-
|
541
|
-
|
542
|
-
* presumably because the backend is going to keep sending such long
|
543
|
-
* requests.
|
544
|
-
*/
|
545
|
-
client->response_buffer->len = 0;
|
556
|
+
g_string_free(client->response_buffer, TRUE);
|
557
|
+
client->response_buffer = NULL;
|
546
558
|
|
547
559
|
close(client->fd);
|
548
560
|
client->open = FALSE;
|
@@ -550,54 +562,7 @@ void ebb_client_close(ebb_client *client)
|
|
550
562
|
}
|
551
563
|
|
552
564
|
|
553
|
-
|
554
|
-
{
|
555
|
-
ebb_client *client = (ebb_client*)(watcher->data);
|
556
|
-
ssize_t sent;
|
557
|
-
|
558
|
-
assert(client->status_written);
|
559
|
-
assert(client->headers_written);
|
560
|
-
assert(client->began_transmission);
|
561
|
-
|
562
|
-
if(EV_ERROR & revents) {
|
563
|
-
g_message("on_client_writable() got error event, closing peer");
|
564
|
-
ebb_client_close(client);
|
565
|
-
return;
|
566
|
-
}
|
567
|
-
|
568
|
-
//if(client->written != 0)
|
569
|
-
// g_debug("total written: %d", (int)(client->written));
|
570
|
-
|
571
|
-
sent = send( client->fd
|
572
|
-
, client->response_buffer->str + sizeof(gchar)*(client->written)
|
573
|
-
, client->response_buffer->len - client->written
|
574
|
-
, 0
|
575
|
-
);
|
576
|
-
if(sent < 0) {
|
577
|
-
#ifdef DEBUG
|
578
|
-
g_message("Error writing: %s", strerror(errno));
|
579
|
-
#endif
|
580
|
-
ebb_client_close(client);
|
581
|
-
return;
|
582
|
-
} else if(sent == 0) {
|
583
|
-
g_message("Sent zero bytes? Closing connection");
|
584
|
-
ebb_client_close(client);
|
585
|
-
}
|
586
|
-
client->written += sent;
|
587
|
-
|
588
|
-
assert(client->written <= client->response_buffer->len);
|
589
|
-
//g_message("wrote %d bytes. total: %d", (int)sent, (int)(client->written));
|
590
|
-
|
591
|
-
ev_timer_again(loop, &(client->timeout_watcher));
|
592
|
-
|
593
|
-
if(client->written == client->response_buffer->len) {
|
594
|
-
ev_io_stop(loop, watcher);
|
595
|
-
if(client->body_written)
|
596
|
-
ebb_client_close(client);
|
597
|
-
}
|
598
|
-
}
|
599
|
-
|
600
|
-
void ebb_client_write_status(ebb_client *client, int status, const char *human_status)
|
565
|
+
void ebb_client_write_status(ebb_client *client, int status, const char *reason_phrase)
|
601
566
|
{
|
602
567
|
assert(client->in_use);
|
603
568
|
if(!client->open) return;
|
@@ -605,17 +570,22 @@ void ebb_client_write_status(ebb_client *client, int status, const char *human_s
|
|
605
570
|
g_string_append_printf( client->response_buffer
|
606
571
|
, "HTTP/1.1 %d %s\r\n"
|
607
572
|
, status
|
608
|
-
,
|
573
|
+
, reason_phrase
|
609
574
|
);
|
610
575
|
client->status_written = TRUE;
|
611
576
|
}
|
612
577
|
|
578
|
+
|
613
579
|
void ebb_client_write_header(ebb_client *client, const char *field, const char *value)
|
614
580
|
{
|
615
581
|
assert(client->in_use);
|
616
582
|
if(!client->open) return;
|
617
583
|
assert(client->status_written == TRUE);
|
618
584
|
assert(client->headers_written == FALSE);
|
585
|
+
|
586
|
+
if(strcmp(field, "Connection") == 0 && strcmp(value, "Keep-Alive") == 0) {
|
587
|
+
client->keep_alive = TRUE;
|
588
|
+
}
|
619
589
|
g_string_append_printf( client->response_buffer
|
620
590
|
, "%s: %s\r\n"
|
621
591
|
, field
|
@@ -623,131 +593,35 @@ void ebb_client_write_header(ebb_client *client, const char *field, const char *
|
|
623
593
|
);
|
624
594
|
}
|
625
595
|
|
626
|
-
void ebb_client_write(ebb_client *client, const char *data, int length)
|
627
|
-
{
|
628
|
-
assert(client->in_use);
|
629
|
-
if(!client->open) return;
|
630
|
-
g_string_append_len(client->response_buffer, data, length);
|
631
|
-
if(client->began_transmission) {
|
632
|
-
/* restart the watcher if we're streaming */
|
633
|
-
ev_io_start(client->server->loop, &client->write_watcher);
|
634
|
-
}
|
635
|
-
}
|
636
|
-
|
637
596
|
|
638
|
-
void
|
597
|
+
void ebb_client_write_body(ebb_client *client, const char *data, int length)
|
639
598
|
{
|
640
599
|
assert(client->in_use);
|
641
600
|
if(!client->open) return;
|
642
|
-
assert(FALSE == ev_is_active(&client->write_watcher));
|
643
601
|
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
perror("fcntl()");
|
648
|
-
ebb_client_close(client);
|
649
|
-
return;
|
602
|
+
if(client->headers_written == FALSE) {
|
603
|
+
g_string_append(client->response_buffer, "\r\n");
|
604
|
+
client->headers_written = TRUE;
|
650
605
|
}
|
651
606
|
|
652
|
-
client->
|
653
|
-
client->began_transmission = TRUE;
|
654
|
-
client->written = 0;
|
655
|
-
client->write_watcher.data = client;
|
656
|
-
ev_init (&(client->write_watcher), on_client_writable);
|
657
|
-
ev_io_set (&(client->write_watcher), client->fd, EV_WRITE | EV_ERROR);
|
658
|
-
ev_io_start(client->server->loop, &client->write_watcher);
|
659
|
-
}
|
660
|
-
|
661
|
-
|
662
|
-
/* pass an allocated buffer and the length to read. this function will try to
|
663
|
-
* fill the buffer with that length of data read from the body of the request.
|
664
|
-
* the return value says how much was actually written.
|
665
|
-
*/
|
666
|
-
int ebb_client_read(ebb_client *client, char *buffer, int length)
|
667
|
-
{
|
668
|
-
size_t read;
|
607
|
+
g_string_append_len(client->response_buffer, data, length);
|
669
608
|
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
/* TODO error checking! */
|
677
|
-
return read;
|
678
|
-
} else {
|
679
|
-
char* request_body = client->request_buffer + client->parser.nread;
|
680
|
-
|
681
|
-
read = ramp(min(length, client->content_length - client->nread_from_body));
|
682
|
-
memcpy( buffer
|
683
|
-
, request_body + client->nread_from_body
|
684
|
-
, read
|
685
|
-
);
|
686
|
-
client->nread_from_body += read;
|
687
|
-
return read;
|
609
|
+
/* If the write_watcher isn't yet active, then start it. It could be that
|
610
|
+
* we're streaming and the watcher has been stopped. In that case we
|
611
|
+
* start it again since we have more to write. */
|
612
|
+
if(ev_is_active(&client->write_watcher) == FALSE) {
|
613
|
+
set_nonblock(client->fd);
|
614
|
+
ev_io_start(client->server->loop, &client->write_watcher);
|
688
615
|
}
|
689
616
|
}
|
690
617
|
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
if (!path) {
|
703
|
-
return -1;
|
704
|
-
}
|
705
|
-
|
706
|
-
if ((sfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
707
|
-
perror("socket()");
|
708
|
-
return -1;
|
709
|
-
}
|
710
|
-
|
711
|
-
if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
|
712
|
-
fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
713
|
-
perror("setting O_NONBLOCK");
|
714
|
-
close(sfd);
|
715
|
-
return -1;
|
716
|
-
}
|
717
|
-
|
718
|
-
/*
|
719
|
-
* Clean up a previous socket file if we left it around
|
720
|
-
*/
|
721
|
-
if (lstat(path, &tstat) == 0) {
|
722
|
-
if (S_ISSOCK(tstat.st_mode))
|
723
|
-
unlink(path);
|
724
|
-
}
|
725
|
-
|
726
|
-
flags = 1;
|
727
|
-
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
|
728
|
-
setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
|
729
|
-
setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
|
730
|
-
|
731
|
-
/*
|
732
|
-
* the memset call clears nonstandard fields in some impementations
|
733
|
-
* that otherwise mess things up.
|
734
|
-
*/
|
735
|
-
memset(&addr, 0, sizeof(addr));
|
736
|
-
|
737
|
-
addr.sun_family = AF_UNIX;
|
738
|
-
strcpy(addr.sun_path, path);
|
739
|
-
old_umask=umask( ~(access_mask&0777));
|
740
|
-
if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
741
|
-
perror("bind()");
|
742
|
-
close(sfd);
|
743
|
-
umask(old_umask);
|
744
|
-
return -1;
|
745
|
-
}
|
746
|
-
umask(old_umask);
|
747
|
-
if (listen(sfd, EBB_MAX_CLIENTS) == -1) {
|
748
|
-
perror("listen()");
|
749
|
-
close(sfd);
|
750
|
-
return -1;
|
751
|
-
}
|
752
|
-
return sfd;
|
753
|
-
}
|
618
|
+
// int ebb_client_should_keep_alive(ebb_client*)
|
619
|
+
// {
|
620
|
+
// /* TODO - return boolean */
|
621
|
+
// if env['HTTP_VERSION'] == 'HTTP/1.0'
|
622
|
+
// return true if env['HTTP_CONNECTION'] =~ /Keep-Alive/i
|
623
|
+
// else
|
624
|
+
// return true unless env['HTTP_CONNECTION'] =~ /close/i
|
625
|
+
// end
|
626
|
+
// false
|
627
|
+
// }
|