ebb 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
// }
|