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.
@@ -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",
@@ -66,6 +66,11 @@ module Rack
66
66
  serve_rails(env)
67
67
  end
68
68
  end
69
+
70
+ # Never spawn threads for a request
71
+ def deferred?(env)
72
+ false
73
+ end
69
74
 
70
75
  protected
71
76
 
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 int server_socket_unix(const char *path, int access_mask);
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 = EBB_FIELD_VALUE_PAIR;
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 request_method_cb(void *data, const char *at, size_t length)
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, EBB_CONTENT_LENGTH, at, length);
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
- if(total_request_size == client->read) {
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
- static client_init(ebb_server *server, ebb_client *client)
163
+
164
+ static void on_client_writable(struct ev_loop *loop, ev_io *watcher, int revents)
286
165
  {
287
- assert(client->in_use == FALSE);
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
- /* does ragel fuck up if request buffer isn't null? */
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->open = TRUE;
295
- client->server = server;
199
+ assert(client->written <= client->response_buffer->len);
200
+ //g_message("wrote %d bytes. total: %d", (int)sent, (int)(client->written));
296
201
 
297
- /* DO SOCKET STUFF */
298
- socklen_t len;
299
- client->fd = accept(server->fd, (struct sockaddr*)&(server->sockaddr), &len);
300
- if(client->fd < 0) {
301
- perror("accept()");
302
- client->open = FALSE;
303
- return;
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
- int flags = fcntl(client->fd, F_GETFL, 0);
307
- assert(0 <= fcntl(client->fd, F_SETFL, flags | O_NONBLOCK));
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(&(client->parser));
246
+ http_parser_init(&client->parser);
311
247
  client->parser.data = client;
312
- client->parser.http_field = http_field_cb;
313
- client->parser.request_method = request_method_cb;
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 = client->nread_from_body = 0;
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->status_written = FALSE;
331
- client->headers_written = FALSE;
332
- client->body_written = FALSE;
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(server, client);
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 = g_string_new("");
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
- if (listen(sfd, EBB_MAX_CLIENTS) < 0) {
487
- perror("listen()");
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
- server->request_watcher.data = server;
497
- ev_init (&server->request_watcher, on_request);
498
- ev_io_set (&server->request_watcher, server->fd, EV_READ | EV_ERROR);
499
- ev_io_start (server->loop, &server->request_watcher);
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
- return server->fd;
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 ebb_server_listen_on_socket(ebb_server *server, const char *socketpath)
514
+ int ebb_server_clients_in_use_p(ebb_server *server)
509
515
  {
510
- // int fd = server_socket_unix(socketpath, 0755);
511
- // if(fd < 0) return 0;
512
- // server->socketpath = strdup(socketpath);
513
- // server->fd = fd;
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
- if(client->upload_file) {
536
- fclose(client->upload_file);
537
- unlink(client->upload_file_filename);
538
- }
554
+ client->ip = NULL;
539
555
 
540
- /* here we do not free the already allocated GString client->response_buffer
541
- * that we're holding the response in. we reuse it again -
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
- static void on_client_writable(struct ev_loop *loop, ev_io *watcher, int revents)
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
- , human_status
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 ebb_client_begin_transmission(ebb_client *client)
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
- /* assure the socket is still in non-blocking mode */
645
- int flags = fcntl(client->fd, F_GETFL, 0);
646
- if(0 > fcntl(client->fd, F_SETFL, flags | O_NONBLOCK)) {
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->headers_written = TRUE;
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
- assert(client->in_use);
671
- if(!client->open) return -1;
672
- assert(client_finished_parsing);
673
-
674
- if(client->upload_file) {
675
- read = fread(buffer, 1, length, client->upload_file);
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
- /* The following socket creation routines are modified and stolen from memcached */
692
-
693
-
694
- static int server_socket_unix(const char *path, int access_mask) {
695
- int sfd;
696
- struct linger ling = {0, 0};
697
- struct sockaddr_un addr;
698
- struct stat tstat;
699
- int flags =1;
700
- int old_umask;
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
+ // }