ebb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,152 @@
1
+ require 'cgi'
2
+
3
+ # Adapter to run a Rails app with any supported Rack handler.
4
+ # By default it will try to load the Rails application in the
5
+ # current directory in the development environment.
6
+ # Options:
7
+ # root: Root directory of the Rails app
8
+ # env: Rails environment to run in (development, production or test)
9
+ # Based on http://fuzed.rubyforge.org/ Rails adapter
10
+ module Rack
11
+ module Adapter
12
+ class Rails
13
+ def initialize(options={})
14
+ @root = options[:root] || Dir.pwd
15
+ @env = options[:environment] || 'development'
16
+ @prefix = options[:prefix]
17
+
18
+ load_application
19
+
20
+ @file_server = Rack::File.new(::File.join(RAILS_ROOT, "public"))
21
+ end
22
+
23
+ def load_application
24
+ ENV['RAILS_ENV'] = @env
25
+
26
+ require "#{@root}/config/environment"
27
+ require 'dispatcher'
28
+
29
+ ActionController::AbstractRequest.relative_url_root = @prefix if @prefix
30
+ end
31
+
32
+ # TODO refactor this in File#can_serve?(path) ??
33
+ def file_exist?(path)
34
+ full_path = ::File.join(@file_server.root, Utils.unescape(path))
35
+ ::File.file?(full_path) && ::File.readable?(full_path)
36
+ end
37
+
38
+ def serve_file(env)
39
+ @file_server.call(env)
40
+ end
41
+
42
+ def serve_rails(env)
43
+ request = Request.new(env)
44
+ response = Response.new
45
+
46
+ session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS
47
+ cgi = CGIWrapper.new(request, response)
48
+
49
+ Dispatcher.dispatch(cgi, session_options, response)
50
+
51
+ response.finish
52
+ end
53
+
54
+ def call(env)
55
+ path = env['PATH_INFO'].chomp('/')
56
+ cached_path = (path.empty? ? 'index' : path) + ActionController::Base.page_cache_extension
57
+
58
+ if file_exist?(path) # Serve the file if it's there
59
+ serve_file(env)
60
+ elsif file_exist?(cached_path) # Serve the page cache if it's there
61
+ env['PATH_INFO'] = cached_path
62
+ serve_file(env)
63
+ else # No static file, let Rails handle it
64
+ serve_rails(env)
65
+ end
66
+ end
67
+
68
+ protected
69
+
70
+ class CGIWrapper < ::CGI
71
+ def initialize(request, response, *args)
72
+ @request = request
73
+ @response = response
74
+ @args = *args
75
+ @input = request.body
76
+
77
+ super *args
78
+ end
79
+
80
+ def header(options = "text/html")
81
+ if options.is_a?(String)
82
+ @response['Content-Type'] = options unless @response['Content-Type']
83
+ else
84
+ @response['Content-Length'] = options.delete('Content-Length').to_s if options['Content-Length']
85
+
86
+ @response['Content-Type'] = options.delete('type') || "text/html"
87
+ @response['Content-Type'] += "; charset=" + options.delete('charset') if options['charset']
88
+
89
+ @response['Content-Language'] = options.delete('language') if options['language']
90
+ @response['Expires'] = options.delete('expires') if options['expires']
91
+
92
+ @response.status = options.delete('Status') if options['Status']
93
+
94
+ # Convert 'cookie' header to 'Set-Cookie' headers.
95
+ # Because Set-Cookie header can appear more the once in the response body,
96
+ # we store it in a line break seperated string that will be translated to
97
+ # multiple Set-Cookie header by the handler.
98
+ if cookie = options.delete('cookie')
99
+ cookies = []
100
+
101
+ case cookie
102
+ when Array then cookie.each { |c| cookies << c.to_s }
103
+ when Hash then cookie.each { |_, c| cookies << c.to_s }
104
+ else cookies << cookie.to_s
105
+ end
106
+
107
+ @output_cookies.each { |c| cookies << c.to_s } if @output_cookies
108
+
109
+ @response['Set-Cookie'] = [@response['Set-Cookie'], cookies].compact.join("\n")
110
+ end
111
+
112
+ options.each { |k,v| @response[k] = v }
113
+ end
114
+
115
+ ""
116
+ end
117
+
118
+ def params
119
+ @params ||= @request.params
120
+ end
121
+
122
+ def cookies
123
+ @request.cookies
124
+ end
125
+
126
+ def query_string
127
+ @request.query_string
128
+ end
129
+
130
+ # Used to wrap the normal args variable used inside CGI.
131
+ def args
132
+ @args
133
+ end
134
+
135
+ # Used to wrap the normal env_table variable used inside CGI.
136
+ def env_table
137
+ @request.env
138
+ end
139
+
140
+ # Used to wrap the normal stdinput variable used inside CGI.
141
+ def stdinput
142
+ @input
143
+ end
144
+
145
+ def stdoutput
146
+ STDERR.puts "stdoutput should not be used."
147
+ @response.body
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
data/src/ebb.c ADDED
@@ -0,0 +1,709 @@
1
+ /* Ebb Web Server
2
+ * Copyright (c) 2007 Ry Dahl
3
+ * This software is released under the "MIT 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
+ #include <pthread.h>
21
+ #include <glib.h>
22
+
23
+ #define EV_STANDALONE 1
24
+ #include <ev.c>
25
+
26
+ #include "parser.h"
27
+ #include "ebb.h"
28
+
29
+ #define min(a,b) (a < b ? a : b)
30
+ #define ramp(a) (a > 0 ? a : 0)
31
+
32
+ static int server_socket(const int port);
33
+ static int server_socket_unix(const char *path, int access_mask);
34
+
35
+ #define env_add(client, field,flen,value,vlen) \
36
+ client->env_fields[client->env_size] = field; \
37
+ client->env_field_lengths[client->env_size] = flen; \
38
+ client->env_values[client->env_size] = value; \
39
+ client->env_value_lengths[client->env_size] = vlen; \
40
+ client->env_size += 1;
41
+ #define env_add_const(client,field,value,vlen) \
42
+ client->env_fields[client->env_size] = NULL; \
43
+ client->env_field_lengths[client->env_size] = field; \
44
+ client->env_values[client->env_size] = value; \
45
+ client->env_value_lengths[client->env_size] = vlen; \
46
+ client->env_size += 1;
47
+ #define env_error(client) \
48
+ client->env_fields[client->env_size] = NULL; \
49
+ client->env_field_lengths[client->env_size] = -1; \
50
+ client->env_values[client->env_size] = NULL; \
51
+ client->env_value_lengths[client->env_size] = -1; \
52
+ client->env_size += 1;
53
+
54
+ int env_has_error(ebb_client *client)
55
+ {
56
+ int i;
57
+ for(i = 0; i < client->env_size; i++)
58
+ if(client->env_field_lengths[i] < 0)
59
+ return TRUE;
60
+ return FALSE;
61
+ }
62
+
63
+ /** Defines common length and error messages for input length validation. */
64
+ #define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP Parse Error: HTTP element " # N " is longer than the " # length " allowed length."
65
+
66
+ /** Validates the max length of given input and throws an exception if over. */
67
+ #define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { env_error(client); g_message(MAX_##N##_LENGTH_ERR); }
68
+
69
+ /* Defines the maximum allowed lengths for various input elements.*/
70
+ DEF_MAX_LENGTH(FIELD_NAME, 256);
71
+ DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
72
+ DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12);
73
+ DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
74
+ DEF_MAX_LENGTH(REQUEST_PATH, 1024);
75
+ DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
76
+ DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
77
+
78
+ void http_field_cb(void *data, const char *field, size_t flen, const char *value, size_t vlen)
79
+ {
80
+ ebb_client *client = (ebb_client*)(data);
81
+ VALIDATE_MAX_LENGTH(flen, FIELD_NAME);
82
+ VALIDATE_MAX_LENGTH(vlen, FIELD_VALUE);
83
+ env_add(client, field, flen, value, vlen);
84
+ }
85
+
86
+
87
+ void request_method_cb(void *data, const char *at, size_t length)
88
+ {
89
+ ebb_client *client = (ebb_client*)(data);
90
+ env_add_const(client, EBB_REQUEST_METHOD, at, length);
91
+ }
92
+
93
+
94
+ void request_uri_cb(void *data, const char *at, size_t length)
95
+ {
96
+ ebb_client *client = (ebb_client*)(data);
97
+ VALIDATE_MAX_LENGTH(length, REQUEST_URI);
98
+ env_add_const(client, EBB_REQUEST_URI, at, length);
99
+ }
100
+
101
+
102
+ void fragment_cb(void *data, const char *at, size_t length)
103
+ {
104
+ ebb_client *client = (ebb_client*)(data);
105
+ VALIDATE_MAX_LENGTH(length, FRAGMENT);
106
+ env_add_const(client, EBB_FRAGMENT, at, length);
107
+ }
108
+
109
+
110
+ void request_path_cb(void *data, const char *at, size_t length)
111
+ {
112
+ ebb_client *client = (ebb_client*)(data);
113
+ VALIDATE_MAX_LENGTH(length, REQUEST_PATH);
114
+ env_add_const(client, EBB_REQUEST_PATH, at, length);
115
+ }
116
+
117
+
118
+ void query_string_cb(void *data, const char *at, size_t length)
119
+ {
120
+ ebb_client *client = (ebb_client*)(data);
121
+ VALIDATE_MAX_LENGTH(length, QUERY_STRING);
122
+ env_add_const(client, EBB_QUERY_STRING, at, length);
123
+ }
124
+
125
+
126
+ void http_version_cb(void *data, const char *at, size_t length)
127
+ {
128
+ ebb_client *client = (ebb_client*)(data);
129
+ env_add_const(client, EBB_HTTP_VERSION, at, length);
130
+ }
131
+
132
+
133
+ void content_length_cb(void *data, const char *at, size_t length)
134
+ {
135
+ ebb_client *client = (ebb_client*)(data);
136
+ env_add_const(client, EBB_CONTENT_LENGTH, at, length);
137
+
138
+ /* i hate c. */
139
+ char buf[20];
140
+ strncpy(buf, at, length);
141
+ buf[length] = '\0';
142
+ client->content_length = atoi(buf);
143
+ }
144
+
145
+
146
+ const char* localhost_str = "0.0.0.0";
147
+ void dispatch(ebb_client *client)
148
+ {
149
+ ebb_server *server = client->server;
150
+
151
+ if(client->open == FALSE)
152
+ return;
153
+
154
+ /* Set the env variables */
155
+ if(server->port) {
156
+ env_add_const(client, EBB_SERVER_NAME
157
+ , localhost_str
158
+ , 7
159
+ );
160
+ env_add_const(client, EBB_SERVER_PORT
161
+ , server->port
162
+ , strlen(server->port)
163
+ );
164
+ }
165
+ server->request_cb(client, server->request_cb_data);
166
+ }
167
+
168
+
169
+ void on_timeout(struct ev_loop *loop, ev_timer *watcher, int revents)
170
+ {
171
+ ebb_client *client = (ebb_client*)(watcher->data);
172
+
173
+ assert(client->server->loop == loop);
174
+ assert(&(client->timeout_watcher) == watcher);
175
+
176
+ ebb_client_close(client);
177
+ #ifdef DEBUG
178
+ g_message("peer timed out");
179
+ #endif
180
+ }
181
+
182
+ #define client_finished_parsing http_parser_is_finished(&client->parser)
183
+ #define total_request_size (client->content_length + client->parser.nread)
184
+
185
+ void* read_body_into_file(void *_client)
186
+ {
187
+ ebb_client *client = (ebb_client*)_client;
188
+ static unsigned int id;
189
+ FILE *tmpfile;
190
+
191
+ assert(client->open);
192
+ assert(client->server->open);
193
+ assert(client->content_length > 0);
194
+ assert(client_finished_parsing);
195
+
196
+ /* set blocking socket */
197
+ int flags = fcntl(client->fd, F_GETFL, 0);
198
+ assert(0 <= fcntl(client->fd, F_SETFL, flags & ~O_NONBLOCK));
199
+
200
+ sprintf(client->upload_file_filename, "/tmp/ebb_upload_%010d", id++);
201
+ tmpfile = fopen(client->upload_file_filename, "w+");
202
+ if(tmpfile == NULL) g_message("Cannot open tmpfile %s", client->upload_file_filename);
203
+ client->upload_file = tmpfile;
204
+
205
+ size_t body_head_length = client->read - client->parser.nread;
206
+ size_t written = 0, r;
207
+ while(written < body_head_length) {
208
+ r = fwrite( client->request_buffer + sizeof(char)*(client->parser.nread + written)
209
+ , sizeof(char)
210
+ , body_head_length - written
211
+ , tmpfile
212
+ );
213
+ if(r <= 0) {
214
+ ebb_client_close(client);
215
+ return NULL;
216
+ }
217
+ written += r;
218
+ }
219
+
220
+ // g_debug("wrote request header to file. written: %d, content_length: %d", written, client->content_length);
221
+
222
+ int bufsize = 5*1024;
223
+ char buffer[bufsize];
224
+ size_t received;
225
+ while(written < client->content_length) {
226
+ received = recv(client->fd
227
+ , buffer
228
+ , min(client->content_length - written, bufsize)
229
+ , 0
230
+ );
231
+ if(received < 0) goto error;
232
+ client->read += received;
233
+
234
+ ssize_t w = 0;
235
+ int rv;
236
+ while(w < received) {
237
+ rv = fwrite( buffer + w*sizeof(char)
238
+ , sizeof(char)
239
+ , received - w
240
+ , tmpfile
241
+ );
242
+ if(rv <= 0) goto error;
243
+ w += rv;
244
+ }
245
+ written += received;
246
+ }
247
+ rewind(tmpfile);
248
+ // g_debug("%d bytes written to file %s", written, client->upload_file_filename);
249
+ return NULL;
250
+ error:
251
+ ebb_client_close(client);
252
+ return NULL;
253
+ }
254
+
255
+
256
+ void on_readable(struct ev_loop *loop, ev_io *watcher, int revents)
257
+ {
258
+ ebb_client *client = (ebb_client*)(watcher->data);
259
+
260
+ assert(client->open);
261
+ assert(client->server->open);
262
+ assert(client->server->loop == loop);
263
+ assert(&client->read_watcher == watcher);
264
+
265
+ ssize_t read = recv( client->fd
266
+ , client->request_buffer + client->read
267
+ , EBB_BUFFERSIZE - client->read - 1 /* -1 is for making ragel happy below */
268
+ , 0
269
+ );
270
+ if(read <= 0) goto error; /* XXX is this the right action to take for read==0 ? */
271
+ client->read += read;
272
+ ev_timer_again(loop, &client->timeout_watcher);
273
+
274
+ if(FALSE == client_finished_parsing) {
275
+ client->request_buffer[client->read] = '\0'; /* make ragel happy */
276
+ http_parser_execute( &client->parser
277
+ , client->request_buffer
278
+ , client->read
279
+ , client->parser.nread
280
+ );
281
+ if(http_parser_has_error(&client->parser)) goto error;
282
+ }
283
+
284
+ if(total_request_size == client->read) {
285
+ ev_io_stop(loop, watcher);
286
+ client->nread_from_body = 0;
287
+ dispatch(client);
288
+ return;
289
+ }
290
+
291
+ if(client_finished_parsing && total_request_size > EBB_BUFFERSIZE ) {
292
+ /* read body into file - in a thread */
293
+ pthread_t thread;
294
+ ev_io_stop(loop, watcher);
295
+ assert(0 <= pthread_create(&thread, NULL, read_body_into_file, client));
296
+ pthread_join(thread, NULL);
297
+ dispatch(client);
298
+ return;
299
+ }
300
+ return;
301
+ error:
302
+ if(read < 0) g_message("Error recving data: %s", strerror(errno));
303
+ ebb_client_close(client);
304
+ }
305
+
306
+ void on_request(struct ev_loop *loop, ev_io *watcher, int revents)
307
+ {
308
+ ebb_server *server = (ebb_server*)(watcher->data);
309
+ assert(server->open);
310
+ assert(server->loop == loop);
311
+ assert(&server->request_watcher == watcher);
312
+
313
+ if(EV_ERROR & revents) {
314
+ g_message("on_request() got error event, closing server.");
315
+ ebb_server_unlisten(server);
316
+ return;
317
+ }
318
+ /* Now we're going to initialize the client
319
+ * and set up her callbacks for read and write
320
+ * the client won't get passed back to the user, however,
321
+ * until the request is complete and parsed.
322
+ */
323
+ int i;
324
+ ebb_client *client;
325
+ /* Get next availible peer */
326
+ for(i=0; i < EBB_MAX_CLIENTS; i++)
327
+ if(!server->clients[i].open) {
328
+ client = &(server->clients[i]);
329
+ break;
330
+ }
331
+ if(client == NULL) {
332
+ g_message("Too many peers. Refusing connections.");
333
+ return;
334
+ }
335
+
336
+ #ifdef DEBUG
337
+ int count = 0;
338
+ for(i = 0; i < EBB_MAX_CLIENTS; i++)
339
+ if(server->clients[i].open) count += 1;
340
+ g_debug("%d open connections", count);
341
+ #endif
342
+ client->open = TRUE;
343
+ client->server = server;
344
+
345
+ /* DO SOCKET STUFF */
346
+ socklen_t len;
347
+ client->fd = accept(server->fd, (struct sockaddr*)&(server->sockaddr), &len);
348
+ assert(client->fd >= 0);
349
+ int flags = fcntl(client->fd, F_GETFL, 0);
350
+ assert(0 <= fcntl(client->fd, F_SETFL, flags | O_NONBLOCK));
351
+
352
+ /* INITIALIZE http_parser */
353
+ http_parser_init(&(client->parser));
354
+ client->parser.data = client;
355
+ client->parser.http_field = http_field_cb;
356
+ client->parser.request_method = request_method_cb;
357
+ client->parser.request_uri = request_uri_cb;
358
+ client->parser.fragment = fragment_cb;
359
+ client->parser.request_path = request_path_cb;
360
+ client->parser.query_string = query_string_cb;
361
+ client->parser.http_version = http_version_cb;
362
+ client->parser.content_length = content_length_cb;
363
+
364
+ /* OTHER */
365
+ client->env_size = 0;
366
+ client->read = client->nread_from_body = 0;
367
+ client->response_buffer->len = 0; /* see note in ebb_client_close */
368
+ client->content_length = 0;
369
+
370
+ /* SETUP READ AND TIMEOUT WATCHERS */
371
+ client->read_watcher.data = client;
372
+ ev_init(&client->read_watcher, on_readable);
373
+ ev_io_set(&client->read_watcher, client->fd, EV_READ | EV_ERROR);
374
+ ev_io_start(server->loop, &client->read_watcher);
375
+
376
+ client->timeout_watcher.data = client;
377
+ ev_timer_init(&client->timeout_watcher, on_timeout, EBB_TIMEOUT, EBB_TIMEOUT);
378
+ ev_timer_start(server->loop, &client->timeout_watcher);
379
+ }
380
+
381
+
382
+ ebb_server* ebb_server_alloc()
383
+ {
384
+ ebb_server *server = g_new0(ebb_server, 1);
385
+ return server;
386
+ }
387
+
388
+
389
+ void ebb_server_init( ebb_server *server
390
+ , struct ev_loop *loop
391
+ , ebb_request_cb request_cb
392
+ , void *request_cb_data
393
+ )
394
+ {
395
+ int i;
396
+ for(i=0; i < EBB_MAX_CLIENTS; i++)
397
+ server->clients[i].response_buffer = g_string_new("");
398
+
399
+ server->request_cb = request_cb;
400
+ server->request_cb_data = request_cb_data;
401
+ server->loop = loop;
402
+ server->open = FALSE;
403
+ server->fd = -1;
404
+ return;
405
+ error:
406
+ ebb_server_free(server);
407
+ return;
408
+ }
409
+
410
+
411
+ void ebb_server_free(ebb_server *server)
412
+ {
413
+ ebb_server_unlisten(server);
414
+
415
+ int i;
416
+ for(i=0; i < EBB_MAX_CLIENTS; i++)
417
+ g_string_free(server->clients[i].response_buffer, TRUE);
418
+ if(server->port)
419
+ free(server->port);
420
+ if(server->socketpath)
421
+ free(server->socketpath);
422
+ free(server);
423
+ }
424
+
425
+
426
+ void ebb_server_unlisten(ebb_server *server)
427
+ {
428
+ if(server->open) {
429
+ //g_message("Stopping Ebb server");
430
+ int i;
431
+ ebb_client *client;
432
+ //for(i=0; i < EBB_MAX_CLIENTS; i++)
433
+ // ebb_client_close(client);
434
+ ev_io_stop(server->loop, &server->request_watcher);
435
+ close(server->fd);
436
+ if(server->socketpath)
437
+ unlink(server->socketpath);
438
+ server->open = FALSE;
439
+ }
440
+ }
441
+
442
+
443
+ void ebb_server_listen(ebb_server *server)
444
+ {
445
+ int r = listen(server->fd, EBB_MAX_CLIENTS);
446
+ assert(r >= 0);
447
+ assert(server->open == FALSE);
448
+ server->open = TRUE;
449
+
450
+ server->request_watcher.data = server;
451
+ ev_init (&server->request_watcher, on_request);
452
+ ev_io_set (&server->request_watcher, server->fd, EV_READ | EV_ERROR);
453
+ ev_io_start (server->loop, &server->request_watcher);
454
+ }
455
+
456
+
457
+ int ebb_server_listen_on_port(ebb_server *server, const int port)
458
+ {
459
+ int fd = server_socket(port);
460
+ if(fd < 0) return 0;
461
+ server->port = malloc(sizeof(char)*8); /* for easy access to the port */
462
+ sprintf(server->port, "%d", port);
463
+ server->fd = fd;
464
+ ebb_server_listen(server);
465
+ return fd;
466
+ }
467
+
468
+
469
+ int ebb_server_listen_on_socket(ebb_server *server, const char *socketpath)
470
+ {
471
+ int fd = server_socket_unix(socketpath, 0755);
472
+ if(fd < 0) return 0;
473
+ server->socketpath = strdup(socketpath);
474
+ server->fd = fd;
475
+ ebb_server_listen(server);
476
+ return fd;
477
+ }
478
+
479
+
480
+ void ebb_client_close(ebb_client *client)
481
+ {
482
+ if(client->open) {
483
+ ev_io_stop(client->server->loop, &client->read_watcher);
484
+ ev_io_stop(client->server->loop, &client->write_watcher);
485
+ ev_timer_stop(client->server->loop, &client->timeout_watcher);
486
+
487
+ if(client->upload_file) {
488
+ fclose(client->upload_file);
489
+ unlink(client->upload_file_filename);
490
+ }
491
+
492
+ /* here we do not free the already allocated GString client->response_buffer
493
+ * that we're holding the response in. we reuse it again -
494
+ * presumably because the backend is going to keep sending such long
495
+ * requests.
496
+ */
497
+ client->response_buffer->len = 0;
498
+
499
+ close(client->fd);
500
+ client->open = FALSE;
501
+ }
502
+ }
503
+
504
+
505
+ void on_client_writable(struct ev_loop *loop, ev_io *watcher, int revents)
506
+ {
507
+ ebb_client *client = (ebb_client*)(watcher->data);
508
+ ssize_t sent;
509
+
510
+ if(EV_ERROR & revents) {
511
+ g_message("on_client_writable() got error event, closing peer");
512
+ return;
513
+ }
514
+
515
+ //if(client->written != 0)
516
+ // g_debug("total written: %d", (int)(client->written));
517
+
518
+ sent = send( client->fd
519
+ , client->response_buffer->str + sizeof(gchar)*(client->written)
520
+ , client->response_buffer->len - client->written
521
+ , 0
522
+ );
523
+ if(sent < 0) {
524
+ #ifdef DEBUG
525
+ g_message("Error writing: %s", strerror(errno));
526
+ #endif
527
+ ebb_client_close(client);
528
+ return;
529
+ }
530
+ client->written += sent;
531
+
532
+ assert(client->written <= client->response_buffer->len);
533
+ //g_message("wrote %d bytes. total: %d", (int)sent, (int)(client->written));
534
+
535
+ ev_timer_again(loop, &(client->timeout_watcher));
536
+
537
+ if(client->written == client->response_buffer->len)
538
+ ebb_client_close(client);
539
+ }
540
+
541
+
542
+ void ebb_client_write(ebb_client *client, const char *data, int length)
543
+ {
544
+ g_string_append_len(client->response_buffer, data, length);
545
+ }
546
+
547
+
548
+ void ebb_client_finished(ebb_client *client)
549
+ {
550
+ assert(client->open);
551
+ assert(FALSE == ev_is_active(&(client->write_watcher)));
552
+
553
+ /* assure the socket is still in non-blocking mode
554
+ * in the ruby binding, for example, i change this flag
555
+ */
556
+ int flags = fcntl(client->fd, F_GETFL, 0);
557
+ if(0 > fcntl(client->fd, F_SETFL, flags | O_NONBLOCK)) {
558
+ perror("fcntl()");
559
+ ebb_client_close(client);
560
+ return;
561
+ }
562
+
563
+ client->written = 0;
564
+ client->write_watcher.data = client;
565
+ ev_init (&(client->write_watcher), on_client_writable);
566
+ ev_io_set (&(client->write_watcher), client->fd, EV_WRITE | EV_ERROR);
567
+ ev_io_start(client->server->loop, &(client->write_watcher));
568
+ }
569
+
570
+
571
+ /* pass an allocated buffer and the length to read. this function will try to
572
+ * fill the buffer with that length of data read from the body of the request.
573
+ * the return value says how much was actually written.
574
+ */
575
+ int ebb_client_read(ebb_client *client, char *buffer, int length)
576
+ {
577
+ size_t read;
578
+
579
+ assert(client->open);
580
+ assert(client_finished_parsing);
581
+
582
+ if(client->upload_file) {
583
+ read = fread(buffer, 1, length, client->upload_file);
584
+ /* TODO error checking! */
585
+ return read;
586
+ } else {
587
+ char* request_body = client->request_buffer + client->parser.nread;
588
+
589
+ read = ramp(min(length, client->content_length - client->nread_from_body));
590
+ memcpy( buffer
591
+ , request_body + client->nread_from_body
592
+ , read
593
+ );
594
+ client->nread_from_body += read;
595
+ return read;
596
+ }
597
+ }
598
+
599
+ /* The following socket creation routines are modified and stolen from memcached */
600
+
601
+ static int server_socket(const int port) {
602
+ int sfd;
603
+ struct linger ling = {0, 0};
604
+ struct sockaddr_in addr;
605
+ int flags =1;
606
+
607
+ if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
608
+ perror("socket()");
609
+ return -1;
610
+ }
611
+
612
+ if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
613
+ fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
614
+ perror("setting O_NONBLOCK");
615
+ close(sfd);
616
+ return -1;
617
+ }
618
+
619
+ flags = 1;
620
+ setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
621
+ setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
622
+ setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
623
+ setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
624
+
625
+ /*
626
+ * the memset call clears nonstandard fields in some impementations
627
+ * that otherwise mess things up.
628
+ */
629
+ memset(&addr, 0, sizeof(addr));
630
+
631
+ addr.sin_family = AF_INET;
632
+ addr.sin_port = htons(port);
633
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
634
+
635
+ if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
636
+ perror("bind()");
637
+ close(sfd);
638
+ return -1;
639
+ }
640
+ if (listen(sfd, EBB_MAX_CLIENTS) == -1) {
641
+ perror("listen()");
642
+ close(sfd);
643
+ return -1;
644
+ }
645
+ return sfd;
646
+ }
647
+
648
+
649
+ static int server_socket_unix(const char *path, int access_mask) {
650
+ int sfd;
651
+ struct linger ling = {0, 0};
652
+ struct sockaddr_un addr;
653
+ struct stat tstat;
654
+ int flags =1;
655
+ int old_umask;
656
+
657
+ if (!path) {
658
+ return -1;
659
+ }
660
+
661
+ if ((sfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
662
+ perror("socket()");
663
+ return -1;
664
+ }
665
+
666
+ if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
667
+ fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
668
+ perror("setting O_NONBLOCK");
669
+ close(sfd);
670
+ return -1;
671
+ }
672
+
673
+ /*
674
+ * Clean up a previous socket file if we left it around
675
+ */
676
+ if (lstat(path, &tstat) == 0) {
677
+ if (S_ISSOCK(tstat.st_mode))
678
+ unlink(path);
679
+ }
680
+
681
+ flags = 1;
682
+ setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
683
+ setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
684
+ setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
685
+
686
+ /*
687
+ * the memset call clears nonstandard fields in some impementations
688
+ * that otherwise mess things up.
689
+ */
690
+ memset(&addr, 0, sizeof(addr));
691
+
692
+ addr.sun_family = AF_UNIX;
693
+ strcpy(addr.sun_path, path);
694
+ old_umask=umask( ~(access_mask&0777));
695
+ if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
696
+ perror("bind()");
697
+ close(sfd);
698
+ umask(old_umask);
699
+ return -1;
700
+ }
701
+ umask(old_umask);
702
+ if (listen(sfd, EBB_MAX_CLIENTS) == -1) {
703
+ perror("listen()");
704
+ close(sfd);
705
+ return -1;
706
+ }
707
+ return sfd;
708
+ }
709
+