ebb 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +10 -44
- data/Rakefile +123 -0
- data/ext/ebb.c +794 -0
- data/ext/ebb.h +130 -0
- data/ext/ebb_ffi.c +575 -0
- data/ext/ebb_request_parser.c +5339 -0
- data/ext/ebb_request_parser.h +97 -0
- data/ext/ebb_request_parser.rl +513 -0
- data/{src → ext}/extconf.rb +12 -8
- data/ext/rbtree.c +408 -0
- data/ext/rbtree.h +54 -0
- data/lib/ebb.rb +311 -0
- data/lib/ebb/version.rb +4 -0
- data/libev/ev++.h +803 -0
- data/libev/ev.c +24 -6
- data/libev/ev.h +4 -0
- data/libev/ev_select.c +50 -15
- data/libev/ev_vars.h +3 -0
- data/libev/ev_win32.c +3 -0
- data/libev/ev_wrap.h +2 -0
- data/libev/event.c +403 -0
- data/libev/event.h +152 -0
- metadata +26 -40
- data/benchmark/application.rb +0 -93
- data/benchmark/server_test.rb +0 -193
- data/bin/ebb_rails +0 -4
- data/ruby_lib/ebb.rb +0 -257
- data/ruby_lib/ebb/runner.rb +0 -134
- data/ruby_lib/ebb/runner/rails.rb +0 -31
- data/ruby_lib/rack/adapter/rails.rb +0 -159
- data/src/ebb.c +0 -627
- data/src/ebb.h +0 -102
- data/src/ebb_ruby.c +0 -306
- data/src/parser.c +0 -2860
- data/src/parser.h +0 -53
- data/test/basic_test.rb +0 -46
- data/test/ebb_rails_test.rb +0 -34
- data/test/env_test.rb +0 -110
- data/test/helper.rb +0 -138
data/src/ebb.c
DELETED
@@ -1,627 +0,0 @@
|
|
1
|
-
/* The Ebb Web Server
|
2
|
-
* Copyright (c) 2008 Ry Dahl. This software is released under the MIT
|
3
|
-
* License. See README file for details.
|
4
|
-
*/
|
5
|
-
#include <unistd.h>
|
6
|
-
#include <fcntl.h>
|
7
|
-
#include <sys/types.h>
|
8
|
-
#include <arpa/inet.h>
|
9
|
-
#include <netinet/tcp.h>
|
10
|
-
#include <sys/un.h>
|
11
|
-
#include <netdb.h>
|
12
|
-
|
13
|
-
#include <stdio.h>
|
14
|
-
#include <string.h>
|
15
|
-
#include <stdlib.h>
|
16
|
-
#include <errno.h>
|
17
|
-
#include <signal.h>
|
18
|
-
#include <assert.h>
|
19
|
-
|
20
|
-
#define EV_STANDALONE 1
|
21
|
-
#include <ev.c>
|
22
|
-
#include <glib.h>
|
23
|
-
|
24
|
-
#include "parser.h"
|
25
|
-
#include "ebb.h"
|
26
|
-
|
27
|
-
#define min(a,b) (a < b ? a : b)
|
28
|
-
#define ramp(a) (a > 0 ? a : 0)
|
29
|
-
|
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
|
-
|
38
|
-
|
39
|
-
void env_add(ebb_client *client, const char *field, int flen, const char *value, int vlen)
|
40
|
-
{
|
41
|
-
if(client->env_size >= EBB_MAX_ENV) {
|
42
|
-
client->parser.overflow_error = TRUE;
|
43
|
-
return;
|
44
|
-
}
|
45
|
-
struct ebb_env_item * const item = &client->env[client->env_size++];
|
46
|
-
item->type = -1;
|
47
|
-
item->field_length = flen;
|
48
|
-
item->value_length = vlen;
|
49
|
-
item->field = field;
|
50
|
-
item->value = value;
|
51
|
-
}
|
52
|
-
|
53
|
-
|
54
|
-
void env_add_const(ebb_client *client, int type, const char *value, int vlen)
|
55
|
-
{
|
56
|
-
if(client->env_size >= EBB_MAX_ENV) {
|
57
|
-
client->parser.overflow_error = TRUE;
|
58
|
-
return;
|
59
|
-
}
|
60
|
-
struct ebb_env_item * const item = &client->env[client->env_size++];
|
61
|
-
item->type = type;
|
62
|
-
item->field_length = -1;
|
63
|
-
item->value_length = vlen;
|
64
|
-
item->field = NULL;
|
65
|
-
item->value = value;
|
66
|
-
}
|
67
|
-
|
68
|
-
|
69
|
-
void http_field_cb(void *data, const char *field, size_t flen, const char *value, size_t vlen)
|
70
|
-
{
|
71
|
-
ebb_client *client = (ebb_client*)(data);
|
72
|
-
assert(field != NULL);
|
73
|
-
assert(value != NULL);
|
74
|
-
env_add(client, field, flen, value, vlen);
|
75
|
-
}
|
76
|
-
|
77
|
-
|
78
|
-
void on_element(void *data, int type, const char *at, size_t length)
|
79
|
-
{
|
80
|
-
ebb_client *client = (ebb_client*)(data);
|
81
|
-
env_add_const(client, type, at, length);
|
82
|
-
}
|
83
|
-
|
84
|
-
|
85
|
-
static void dispatch(ebb_client *client)
|
86
|
-
{
|
87
|
-
ebb_server *server = client->server;
|
88
|
-
if(client->open == FALSE)
|
89
|
-
return;
|
90
|
-
client->in_use = TRUE;
|
91
|
-
|
92
|
-
/* XXX decide if to use keep-alive or not? */
|
93
|
-
|
94
|
-
server->request_cb(client, server->request_cb_data);
|
95
|
-
}
|
96
|
-
|
97
|
-
|
98
|
-
static void on_timeout(struct ev_loop *loop, ev_timer *watcher, int revents)
|
99
|
-
{
|
100
|
-
ebb_client *client = (ebb_client*)(watcher->data);
|
101
|
-
|
102
|
-
assert(client->server->loop == loop);
|
103
|
-
assert(&(client->timeout_watcher) == watcher);
|
104
|
-
|
105
|
-
ebb_client_close(client);
|
106
|
-
#ifdef DEBUG
|
107
|
-
g_message("peer timed out");
|
108
|
-
#endif
|
109
|
-
}
|
110
|
-
|
111
|
-
#define client_finished_parsing http_parser_is_finished(&client->parser)
|
112
|
-
#define total_request_size (client->parser.content_length + client->parser.nread)
|
113
|
-
|
114
|
-
static void on_client_readable(struct ev_loop *loop, ev_io *watcher, int revents)
|
115
|
-
{
|
116
|
-
ebb_client *client = (ebb_client*)(watcher->data);
|
117
|
-
|
118
|
-
assert(client->in_use == FALSE);
|
119
|
-
assert(client->open);
|
120
|
-
assert(client->server->open);
|
121
|
-
assert(client->server->loop == loop);
|
122
|
-
assert(&client->read_watcher == watcher);
|
123
|
-
|
124
|
-
ssize_t read = recv( client->fd
|
125
|
-
, client->request_buffer + client->read
|
126
|
-
, EBB_BUFFERSIZE - client->read
|
127
|
-
, 0
|
128
|
-
);
|
129
|
-
if(read < 0) goto error;
|
130
|
-
if(read == 0) goto error; /* XXX is this the right action to take for read==0 ? */
|
131
|
-
client->read += read;
|
132
|
-
ev_timer_again(loop, &client->timeout_watcher);
|
133
|
-
|
134
|
-
// if(client->read == EBB_BUFFERSIZE) goto error;
|
135
|
-
|
136
|
-
if(FALSE == client_finished_parsing) {
|
137
|
-
http_parser_execute( &client->parser
|
138
|
-
, client->request_buffer
|
139
|
-
, client->read
|
140
|
-
, client->parser.nread
|
141
|
-
);
|
142
|
-
if(http_parser_has_error(&client->parser)) goto error;
|
143
|
-
}
|
144
|
-
|
145
|
-
if(client_finished_parsing) {
|
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;
|
150
|
-
ev_io_stop(loop, watcher);
|
151
|
-
dispatch(client);
|
152
|
-
return;
|
153
|
-
}
|
154
|
-
}
|
155
|
-
return;
|
156
|
-
error:
|
157
|
-
#ifdef DEBUG
|
158
|
-
if(read < 0) g_message("Error recving data: %s", strerror(errno));
|
159
|
-
#endif
|
160
|
-
ebb_client_close(client);
|
161
|
-
}
|
162
|
-
|
163
|
-
|
164
|
-
static void on_client_writable(struct ev_loop *loop, ev_io *watcher, int revents)
|
165
|
-
{
|
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) {
|
188
|
-
#ifdef DEBUG
|
189
|
-
g_message("Error writing: %s", strerror(errno));
|
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;
|
198
|
-
|
199
|
-
assert(client->written <= client->response_buffer->len);
|
200
|
-
//g_message("wrote %d bytes. total: %d", (int)sent, (int)(client->written));
|
201
|
-
|
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 = sizeof(struct sockaddr);
|
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;
|
237
|
-
}
|
238
|
-
|
239
|
-
set_nonblock(client->fd);
|
240
|
-
|
241
|
-
/* IP Address */
|
242
|
-
if(client->server->port)
|
243
|
-
client->ip = inet_ntoa(client->sockaddr.sin_addr);
|
244
|
-
|
245
|
-
/* INITIALIZE http_parser */
|
246
|
-
http_parser_init(&client->parser);
|
247
|
-
client->parser.data = client;
|
248
|
-
client->parser.http_field = http_field_cb;
|
249
|
-
client->parser.on_element = on_element;
|
250
|
-
|
251
|
-
/* OTHER */
|
252
|
-
client->env_size = 0;
|
253
|
-
client->read = 0;
|
254
|
-
if(client->request_buffer == NULL) {
|
255
|
-
/* Only allocate the request_buffer once */
|
256
|
-
client->request_buffer = (char*)malloc(EBB_BUFFERSIZE);
|
257
|
-
}
|
258
|
-
client->keep_alive = FALSE;
|
259
|
-
client->status_written = client->headers_written = client->body_written = FALSE;
|
260
|
-
client->written = 0;
|
261
|
-
|
262
|
-
if(client->response_buffer != NULL)
|
263
|
-
g_string_free(client->response_buffer, TRUE);
|
264
|
-
client->response_buffer = g_string_new("");
|
265
|
-
|
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
|
-
|
273
|
-
client->read_watcher.data = client;
|
274
|
-
ev_init(&client->read_watcher, on_client_readable);
|
275
|
-
ev_io_set(&client->read_watcher, client->fd, EV_READ | EV_ERROR);
|
276
|
-
ev_io_start(client->server->loop, &client->read_watcher);
|
277
|
-
|
278
|
-
client->timeout_watcher.data = client;
|
279
|
-
ev_timer_init(&client->timeout_watcher, on_timeout, EBB_TIMEOUT, 0);
|
280
|
-
ev_timer_start(client->server->loop, &client->timeout_watcher);
|
281
|
-
}
|
282
|
-
|
283
|
-
|
284
|
-
static void on_request(struct ev_loop *loop, ev_io *watcher, int revents)
|
285
|
-
{
|
286
|
-
ebb_server *server = (ebb_server*)(watcher->data);
|
287
|
-
assert(server->open);
|
288
|
-
assert(server->loop == loop);
|
289
|
-
assert(&server->request_watcher == watcher);
|
290
|
-
|
291
|
-
if(EV_ERROR & revents) {
|
292
|
-
g_message("on_request() got error event, closing server.");
|
293
|
-
ebb_server_unlisten(server);
|
294
|
-
return;
|
295
|
-
}
|
296
|
-
/* Now we're going to initialize the client
|
297
|
-
* and set up her callbacks for read and write
|
298
|
-
* the client won't get passed back to the user, however,
|
299
|
-
* until the request is complete and parsed.
|
300
|
-
*/
|
301
|
-
int i;
|
302
|
-
ebb_client *client = NULL;
|
303
|
-
/* Get next availible peer */
|
304
|
-
for(i=0; i < EBB_MAX_CLIENTS; i++)
|
305
|
-
if(!server->clients[i].in_use && !server->clients[i].open) {
|
306
|
-
client = &(server->clients[i]);
|
307
|
-
break;
|
308
|
-
}
|
309
|
-
if(client == NULL) {
|
310
|
-
g_message("Too many peers. Refusing connections.");
|
311
|
-
return;
|
312
|
-
}
|
313
|
-
|
314
|
-
#ifdef DEBUG
|
315
|
-
int count = 0;
|
316
|
-
for(i = 0; i < EBB_MAX_CLIENTS; i++)
|
317
|
-
if(server->clients[i].open) count += 1;
|
318
|
-
g_debug("%d open connections", count);
|
319
|
-
#endif
|
320
|
-
|
321
|
-
client_init(client);
|
322
|
-
}
|
323
|
-
|
324
|
-
|
325
|
-
ebb_server* ebb_server_alloc()
|
326
|
-
{
|
327
|
-
ebb_server *server = g_new0(ebb_server, 1);
|
328
|
-
return server;
|
329
|
-
}
|
330
|
-
|
331
|
-
|
332
|
-
void ebb_server_init( ebb_server *server
|
333
|
-
, struct ev_loop *loop
|
334
|
-
, ebb_request_cb request_cb
|
335
|
-
, void *request_cb_data
|
336
|
-
)
|
337
|
-
{
|
338
|
-
int i;
|
339
|
-
for(i=0; i < EBB_MAX_CLIENTS; i++) {
|
340
|
-
server->clients[i].request_buffer = NULL;
|
341
|
-
server->clients[i].response_buffer = NULL;
|
342
|
-
server->clients[i].open = FALSE;
|
343
|
-
server->clients[i].in_use = FALSE;
|
344
|
-
server->clients[i].server = server;
|
345
|
-
}
|
346
|
-
|
347
|
-
server->request_cb = request_cb;
|
348
|
-
server->request_cb_data = request_cb_data;
|
349
|
-
server->loop = loop;
|
350
|
-
server->open = FALSE;
|
351
|
-
server->fd = -1;
|
352
|
-
return;
|
353
|
-
error:
|
354
|
-
ebb_server_free(server);
|
355
|
-
return;
|
356
|
-
}
|
357
|
-
|
358
|
-
|
359
|
-
void ebb_server_free(ebb_server *server)
|
360
|
-
{
|
361
|
-
ebb_server_unlisten(server);
|
362
|
-
|
363
|
-
if(server->port)
|
364
|
-
free(server->port);
|
365
|
-
if(server->socketpath)
|
366
|
-
free(server->socketpath);
|
367
|
-
free(server);
|
368
|
-
}
|
369
|
-
|
370
|
-
|
371
|
-
void ebb_server_unlisten(ebb_server *server)
|
372
|
-
{
|
373
|
-
if(server->open) {
|
374
|
-
int i;
|
375
|
-
ebb_client *client;
|
376
|
-
ev_io_stop(server->loop, &server->request_watcher);
|
377
|
-
close(server->fd);
|
378
|
-
if(server->socketpath) {
|
379
|
-
unlink(server->socketpath);
|
380
|
-
server->socketpath = NULL;
|
381
|
-
}
|
382
|
-
if(server->port) {
|
383
|
-
free(server->port);
|
384
|
-
server->port = NULL;
|
385
|
-
}
|
386
|
-
server->open = FALSE;
|
387
|
-
}
|
388
|
-
}
|
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
|
-
|
415
|
-
int ebb_server_listen_on_port(ebb_server *server, const int port)
|
416
|
-
{
|
417
|
-
int sfd = -1;
|
418
|
-
struct linger ling = {0, 0};
|
419
|
-
struct sockaddr_in addr;
|
420
|
-
int flags = 1;
|
421
|
-
|
422
|
-
if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
423
|
-
perror("socket()");
|
424
|
-
goto error;
|
425
|
-
}
|
426
|
-
|
427
|
-
flags = 1;
|
428
|
-
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
|
429
|
-
setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
|
430
|
-
setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
|
431
|
-
setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
|
432
|
-
|
433
|
-
/*
|
434
|
-
* the memset call clears nonstandard fields in some impementations
|
435
|
-
* that otherwise mess things up.
|
436
|
-
*/
|
437
|
-
memset(&addr, 0, sizeof(addr));
|
438
|
-
|
439
|
-
addr.sin_family = AF_INET;
|
440
|
-
addr.sin_port = htons(port);
|
441
|
-
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
442
|
-
|
443
|
-
if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
444
|
-
perror("bind()");
|
445
|
-
goto error;
|
446
|
-
}
|
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()");
|
473
|
-
goto error;
|
474
|
-
}
|
475
|
-
|
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
|
-
}
|
480
|
-
|
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;
|
508
|
-
error:
|
509
|
-
if(sfd > 0) close(sfd);
|
510
|
-
return -1;
|
511
|
-
}
|
512
|
-
|
513
|
-
|
514
|
-
int ebb_server_clients_in_use_p(ebb_server *server)
|
515
|
-
{
|
516
|
-
int i;
|
517
|
-
for(i = 0; i < EBB_MAX_CLIENTS; i++)
|
518
|
-
if(server->clients[i].in_use) return TRUE;
|
519
|
-
return FALSE;
|
520
|
-
}
|
521
|
-
|
522
|
-
|
523
|
-
void ebb_client_release(ebb_client *client)
|
524
|
-
{
|
525
|
-
assert(client->in_use);
|
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
|
-
|
542
|
-
if(client->written == client->response_buffer->len)
|
543
|
-
ebb_client_close(client);
|
544
|
-
}
|
545
|
-
|
546
|
-
|
547
|
-
void ebb_client_close(ebb_client *client)
|
548
|
-
{
|
549
|
-
if(client->open) {
|
550
|
-
ev_io_stop(client->server->loop, &client->read_watcher);
|
551
|
-
ev_io_stop(client->server->loop, &client->write_watcher);
|
552
|
-
ev_timer_stop(client->server->loop, &client->timeout_watcher);
|
553
|
-
|
554
|
-
client->ip = NULL;
|
555
|
-
|
556
|
-
g_string_free(client->response_buffer, TRUE);
|
557
|
-
client->response_buffer = NULL;
|
558
|
-
|
559
|
-
close(client->fd);
|
560
|
-
client->open = FALSE;
|
561
|
-
}
|
562
|
-
}
|
563
|
-
|
564
|
-
|
565
|
-
void ebb_client_write_status(ebb_client *client, int status, const char *reason_phrase)
|
566
|
-
{
|
567
|
-
assert(client->in_use);
|
568
|
-
if(!client->open) return;
|
569
|
-
assert(client->status_written == FALSE);
|
570
|
-
g_string_append_printf( client->response_buffer
|
571
|
-
, "HTTP/1.1 %d %s\r\n"
|
572
|
-
, status
|
573
|
-
, reason_phrase
|
574
|
-
);
|
575
|
-
client->status_written = TRUE;
|
576
|
-
}
|
577
|
-
|
578
|
-
|
579
|
-
void ebb_client_write_header(ebb_client *client, const char *field, const char *value)
|
580
|
-
{
|
581
|
-
assert(client->in_use);
|
582
|
-
if(!client->open) return;
|
583
|
-
assert(client->status_written == TRUE);
|
584
|
-
assert(client->headers_written == FALSE);
|
585
|
-
|
586
|
-
if(strcmp(field, "Connection") == 0 && strcmp(value, "Keep-Alive") == 0) {
|
587
|
-
client->keep_alive = TRUE;
|
588
|
-
}
|
589
|
-
g_string_append_printf( client->response_buffer
|
590
|
-
, "%s: %s\r\n"
|
591
|
-
, field
|
592
|
-
, value
|
593
|
-
);
|
594
|
-
}
|
595
|
-
|
596
|
-
|
597
|
-
void ebb_client_write_body(ebb_client *client, const char *data, int length)
|
598
|
-
{
|
599
|
-
assert(client->in_use);
|
600
|
-
if(!client->open) return;
|
601
|
-
|
602
|
-
if(client->headers_written == FALSE) {
|
603
|
-
g_string_append(client->response_buffer, "\r\n");
|
604
|
-
client->headers_written = TRUE;
|
605
|
-
}
|
606
|
-
|
607
|
-
g_string_append_len(client->response_buffer, data, length);
|
608
|
-
|
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);
|
615
|
-
}
|
616
|
-
}
|
617
|
-
|
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
|
-
// }
|