ruby binding clean-up
[ebb.git] / src / ebb.c
blobe76edb4051f10ff4a7b42fe15784c6c0f18f037a
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>
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <errno.h>
17 #include <signal.h>
18 #include <assert.h>
20 #include <pthread.h>
21 #include <glib.h>
23 #define EV_STANDALONE 1
24 #include <ev.c>
26 #include "parser.h"
27 #include "ebb.h"
29 #define min(a,b) (a < b ? a : b)
30 #define ramp(a) (a > 0 ? a : 0)
32 static int server_socket(const int port);
33 static int server_socket_unix(const char *path, int access_mask);
35 void env_add(ebb_client *client, const char *field, int flen, const char *value, int vlen)
37 if(client->env_size >= EBB_MAX_ENV) {
38 client->parser.overflow_error = TRUE;
39 return;
41 client->env[client->env_size].type = EBB_FIELD_VALUE_PAIR;
42 client->env[client->env_size].field = field;
43 client->env[client->env_size].field_length = flen;
44 client->env[client->env_size].value = value;
45 client->env[client->env_size].value_length = vlen;
46 client->env_size += 1;
50 void env_add_const(ebb_client *client, int type, const char *value, int vlen)
52 if(client->env_size >= EBB_MAX_ENV) {
53 client->parser.overflow_error = TRUE;
54 return;
56 client->env[client->env_size].type = type;
57 client->env[client->env_size].field = NULL;
58 client->env[client->env_size].field_length = -1;
59 client->env[client->env_size].value = value;
60 client->env[client->env_size].value_length = vlen;
61 client->env_size += 1;
65 void http_field_cb(void *data, const char *field, size_t flen, const char *value, size_t vlen)
67 ebb_client *client = (ebb_client*)(data);
68 assert(field != NULL);
69 assert(value != NULL);
70 env_add(client, field, flen, value, vlen);
74 void request_method_cb(void *data, const char *at, size_t length)
76 ebb_client *client = (ebb_client*)(data);
77 env_add_const(client, EBB_REQUEST_METHOD, at, length);
81 void request_uri_cb(void *data, const char *at, size_t length)
83 ebb_client *client = (ebb_client*)(data);
84 env_add_const(client, EBB_REQUEST_URI, at, length);
88 void fragment_cb(void *data, const char *at, size_t length)
90 ebb_client *client = (ebb_client*)(data);
91 env_add_const(client, EBB_FRAGMENT, at, length);
95 void request_path_cb(void *data, const char *at, size_t length)
97 ebb_client *client = (ebb_client*)(data);
98 env_add_const(client, EBB_REQUEST_PATH, at, length);
102 void query_string_cb(void *data, const char *at, size_t length)
104 ebb_client *client = (ebb_client*)(data);
105 env_add_const(client, EBB_QUERY_STRING, at, length);
109 void http_version_cb(void *data, const char *at, size_t length)
111 ebb_client *client = (ebb_client*)(data);
112 env_add_const(client, EBB_HTTP_VERSION, at, length);
116 void content_length_cb(void *data, const char *at, size_t length)
118 ebb_client *client = (ebb_client*)(data);
119 env_add_const(client, EBB_CONTENT_LENGTH, at, length);
120 /* atoi_length - why isn't this in the statndard library? i hate c */
121 int i, mult;
122 for(mult=1, i=length-1; i>=0; i--, mult*=10)
123 client->content_length += (at[i] - '0') * mult;
127 const char* localhost_str = "0.0.0.0";
128 void dispatch(ebb_client *client)
130 ebb_server *server = client->server;
132 if(client->open == FALSE)
133 return;
135 /* Set the env variables */
136 if(server->port) {
137 env_add_const(client, EBB_SERVER_NAME
138 , localhost_str
141 env_add_const(client, EBB_SERVER_PORT
142 , server->port
143 , strlen(server->port)
146 server->request_cb(client, server->request_cb_data);
150 void on_timeout(struct ev_loop *loop, ev_timer *watcher, int revents)
152 ebb_client *client = (ebb_client*)(watcher->data);
154 assert(client->server->loop == loop);
155 assert(&(client->timeout_watcher) == watcher);
157 ebb_client_close(client);
158 #ifdef DEBUG
159 g_message("peer timed out");
160 #endif
163 #define client_finished_parsing http_parser_is_finished(&client->parser)
164 #define total_request_size (client->content_length + client->parser.nread)
166 void* read_body_into_file(void *_client)
168 ebb_client *client = (ebb_client*)_client;
169 static unsigned int id;
170 FILE *tmpfile;
172 assert(client->open);
173 assert(client->server->open);
174 assert(client->content_length > 0);
175 assert(client_finished_parsing);
177 /* set blocking socket */
178 int flags = fcntl(client->fd, F_GETFL, 0);
179 assert(0 <= fcntl(client->fd, F_SETFL, flags & ~O_NONBLOCK));
181 sprintf(client->upload_file_filename, "/tmp/ebb_upload_%010d", id++);
182 tmpfile = fopen(client->upload_file_filename, "w+");
183 if(tmpfile == NULL) g_message("Cannot open tmpfile %s", client->upload_file_filename);
184 client->upload_file = tmpfile;
186 size_t body_head_length = client->read - client->parser.nread;
187 size_t written = 0, r;
188 while(written < body_head_length) {
189 r = fwrite( client->request_buffer + sizeof(char)*(client->parser.nread + written)
190 , sizeof(char)
191 , body_head_length - written
192 , tmpfile
194 if(r <= 0) {
195 ebb_client_close(client);
196 return NULL;
198 written += r;
201 int bufsize = 5*1024;
202 char buffer[bufsize];
203 size_t received;
204 while(written < client->content_length) {
205 received = recv(client->fd
206 , buffer
207 , min(client->content_length - written, bufsize)
210 if(received < 0) goto error;
211 client->read += received;
213 ssize_t w = 0;
214 int rv;
215 while(w < received) {
216 rv = fwrite( buffer + w*sizeof(char)
217 , sizeof(char)
218 , received - w
219 , tmpfile
221 if(rv <= 0) goto error;
222 w += rv;
224 written += received;
226 rewind(tmpfile);
227 // g_debug("%d bytes written to file %s", written, client->upload_file_filename);
228 dispatch(client);
229 return NULL;
230 error:
231 ebb_client_close(client);
232 return NULL;
236 void on_readable(struct ev_loop *loop, ev_io *watcher, int revents)
238 ebb_client *client = (ebb_client*)(watcher->data);
240 assert(client->open);
241 assert(client->server->open);
242 assert(client->server->loop == loop);
243 assert(&client->read_watcher == watcher);
245 ssize_t read = recv( client->fd
246 , client->request_buffer + client->read
247 , EBB_BUFFERSIZE - client->read
250 if(read < 0) goto error; /* XXX is this the right action to take for read==0 ? */
251 if(read == 0) return;
252 client->read += read;
253 ev_timer_again(loop, &client->timeout_watcher);
255 if(client->read == EBB_BUFFERSIZE) goto error;
257 if(FALSE == client_finished_parsing) {
258 http_parser_execute( &client->parser
259 , client->request_buffer
260 , client->read
261 , client->parser.nread
263 if(http_parser_has_error(&client->parser)) goto error;
266 if(client_finished_parsing) {
267 if(total_request_size == client->read) {
268 ev_io_stop(loop, watcher);
269 client->nread_from_body = 0;
270 dispatch(client);
271 return;
273 if(total_request_size > EBB_BUFFERSIZE ) {
274 /* read body into file - in a thread */
275 ev_io_stop(loop, watcher);
276 pthread_t thread;
277 assert(0 <= pthread_create(&thread, NULL, read_body_into_file, client));
278 pthread_detach(thread);
279 return;
282 return;
283 error:
284 if(read < 0) g_message("Error recving data: %s", strerror(errno));
285 ebb_client_close(client);
289 void on_request(struct ev_loop *loop, ev_io *watcher, int revents)
291 ebb_server *server = (ebb_server*)(watcher->data);
292 assert(server->open);
293 assert(server->loop == loop);
294 assert(&server->request_watcher == watcher);
296 if(EV_ERROR & revents) {
297 g_message("on_request() got error event, closing server.");
298 ebb_server_unlisten(server);
299 return;
301 /* Now we're going to initialize the client
302 * and set up her callbacks for read and write
303 * the client won't get passed back to the user, however,
304 * until the request is complete and parsed.
306 int i;
307 ebb_client *client;
308 /* Get next availible peer */
309 for(i=0; i < EBB_MAX_CLIENTS; i++)
310 if(!server->clients[i].open) {
311 client = &(server->clients[i]);
312 break;
314 if(client == NULL) {
315 g_message("Too many peers. Refusing connections.");
316 return;
319 #ifdef DEBUG
320 int count = 0;
321 for(i = 0; i < EBB_MAX_CLIENTS; i++)
322 if(server->clients[i].open) count += 1;
323 g_debug("%d open connections", count);
325 /* does ragel fuck up if request buffer isn't null? */
326 for(i=0; i< EBB_BUFFERSIZE; i++)
327 client->request_buffer[i] = 'A';
328 #endif
330 client->open = TRUE;
331 client->server = server;
333 /* DO SOCKET STUFF */
334 socklen_t len;
335 client->fd = accept(server->fd, (struct sockaddr*)&(server->sockaddr), &len);
336 assert(client->fd >= 0);
337 int flags = fcntl(client->fd, F_GETFL, 0);
338 assert(0 <= fcntl(client->fd, F_SETFL, flags | O_NONBLOCK));
340 /* INITIALIZE http_parser */
341 http_parser_init(&(client->parser));
342 client->parser.data = client;
343 client->parser.http_field = http_field_cb;
344 client->parser.request_method = request_method_cb;
345 client->parser.request_uri = request_uri_cb;
346 client->parser.fragment = fragment_cb;
347 client->parser.request_path = request_path_cb;
348 client->parser.query_string = query_string_cb;
349 client->parser.http_version = http_version_cb;
350 client->parser.content_length = content_length_cb;
352 /* OTHER */
354 client->env_size = 0;
355 client->read = client->nread_from_body = 0;
356 client->response_buffer->len = 0; /* see note in ebb_client_close */
357 client->content_length = 0;
359 client->status_sent = FALSE;
360 client->headers_sent = FALSE;
361 client->body_sent = FALSE;
363 /* SETUP READ AND TIMEOUT WATCHERS */
364 client->read_watcher.data = client;
365 ev_init(&client->read_watcher, on_readable);
366 ev_io_set(&client->read_watcher, client->fd, EV_READ | EV_ERROR);
367 ev_io_start(server->loop, &client->read_watcher);
369 client->timeout_watcher.data = client;
370 ev_timer_init(&client->timeout_watcher, on_timeout, EBB_TIMEOUT, EBB_TIMEOUT);
371 ev_timer_start(server->loop, &client->timeout_watcher);
375 ebb_server* ebb_server_alloc()
377 ebb_server *server = g_new0(ebb_server, 1);
378 return server;
382 void ebb_server_init( ebb_server *server
383 , struct ev_loop *loop
384 , ebb_request_cb request_cb
385 , void *request_cb_data
388 int i;
389 for(i=0; i < EBB_MAX_CLIENTS; i++)
390 server->clients[i].response_buffer = g_string_new("");
392 server->request_cb = request_cb;
393 server->request_cb_data = request_cb_data;
394 server->loop = loop;
395 server->open = FALSE;
396 server->fd = -1;
397 return;
398 error:
399 ebb_server_free(server);
400 return;
404 void ebb_server_free(ebb_server *server)
406 ebb_server_unlisten(server);
408 int i;
409 for(i=0; i < EBB_MAX_CLIENTS; i++)
410 g_string_free(server->clients[i].response_buffer, TRUE);
411 if(server->port)
412 free(server->port);
413 if(server->socketpath)
414 free(server->socketpath);
415 free(server);
419 void ebb_server_unlisten(ebb_server *server)
421 if(server->open) {
422 int i;
423 ebb_client *client;
424 ev_io_stop(server->loop, &server->request_watcher);
425 close(server->fd);
426 if(server->socketpath)
427 unlink(server->socketpath);
428 server->open = FALSE;
433 void ebb_server_listen(ebb_server *server)
435 int r = listen(server->fd, EBB_MAX_CLIENTS);
436 assert(r >= 0);
437 assert(server->open == FALSE);
438 server->open = TRUE;
440 server->request_watcher.data = server;
441 ev_init (&server->request_watcher, on_request);
442 ev_io_set (&server->request_watcher, server->fd, EV_READ | EV_ERROR);
443 ev_io_start (server->loop, &server->request_watcher);
447 int ebb_server_listen_on_port(ebb_server *server, const int port)
449 int sfd = -1;
450 struct linger ling = {0, 0};
451 struct sockaddr_in addr;
452 int flags = 1;
454 if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
455 perror("socket()");
456 goto error;
459 flags = fcntl(sfd, F_GETFL, 0);
460 if(fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
461 perror("setting O_NONBLOCK");
462 goto error;
465 flags = 1;
466 setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
467 setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
468 setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
469 setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
472 * the memset call clears nonstandard fields in some impementations
473 * that otherwise mess things up.
475 memset(&addr, 0, sizeof(addr));
477 addr.sin_family = AF_INET;
478 addr.sin_port = htons(port);
479 addr.sin_addr.s_addr = htonl(INADDR_ANY);
481 if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
482 perror("bind()");
483 goto error;
485 if (listen(sfd, EBB_MAX_CLIENTS) < 0) {
486 perror("listen()");
487 goto error;
489 server->fd = sfd;
490 server->port = malloc(sizeof(char)*8); /* for easy access to the port */
491 sprintf(server->port, "%d", port);
492 ebb_server_listen(server);
493 return server->fd;
494 error:
495 if(sfd > 0) close(sfd);
496 return -1;
500 int ebb_server_listen_on_socket(ebb_server *server, const char *socketpath)
502 int fd = server_socket_unix(socketpath, 0755);
503 if(fd < 0) return 0;
504 server->socketpath = strdup(socketpath);
505 server->fd = fd;
506 ebb_server_listen(server);
507 return fd;
511 void ebb_client_close(ebb_client *client)
513 if(client->open) {
514 ev_io_stop(client->server->loop, &client->read_watcher);
515 ev_io_stop(client->server->loop, &client->write_watcher);
516 ev_timer_stop(client->server->loop, &client->timeout_watcher);
518 if(client->upload_file) {
519 fclose(client->upload_file);
520 unlink(client->upload_file_filename);
523 /* here we do not free the already allocated GString client->response_buffer
524 * that we're holding the response in. we reuse it again -
525 * presumably because the backend is going to keep sending such long
526 * requests.
528 client->response_buffer->len = 0;
530 close(client->fd);
531 client->open = FALSE;
536 void on_client_writable(struct ev_loop *loop, ev_io *watcher, int revents)
538 ebb_client *client = (ebb_client*)(watcher->data);
539 ssize_t sent;
541 if(EV_ERROR & revents) {
542 g_message("on_client_writable() got error event, closing peer");
543 return;
546 //if(client->written != 0)
547 // g_debug("total written: %d", (int)(client->written));
549 sent = send( client->fd
550 , client->response_buffer->str + sizeof(gchar)*(client->written)
551 , client->response_buffer->len - client->written
554 if(sent < 0) {
555 #ifdef DEBUG
556 g_message("Error writing: %s", strerror(errno));
557 #endif
558 ebb_client_close(client);
559 return;
561 client->written += sent;
563 assert(client->written <= client->response_buffer->len);
564 //g_message("wrote %d bytes. total: %d", (int)sent, (int)(client->written));
566 ev_timer_again(loop, &(client->timeout_watcher));
568 if(client->written == client->response_buffer->len)
569 ebb_client_close(client);
572 void ebb_client_write_status(ebb_client *client, int status, const char *human_status)
574 assert(client->status_sent == FALSE);
575 g_string_append_printf( client->response_buffer
576 , "HTTP/1.1 %d %s\r\n"
577 , status
578 , human_status
580 client->status_sent = TRUE;
583 void ebb_client_write_header(ebb_client *client, const char *field, const char *value)
585 assert(client->status_sent == TRUE);
586 assert(client->headers_sent == FALSE);
587 g_string_append_printf( client->response_buffer
588 , "%s: %s\r\n"
589 , field
590 , value
594 void ebb_client_write(ebb_client *client, const char *data, int length)
596 g_string_append_len(client->response_buffer, data, length);
600 void ebb_client_finished(ebb_client *client)
602 assert(client->open);
603 assert(FALSE == ev_is_active(&(client->write_watcher)));
605 /* assure the socket is still in non-blocking mode
606 * in the ruby binding, for example, i change this flag
608 int flags = fcntl(client->fd, F_GETFL, 0);
609 if(0 > fcntl(client->fd, F_SETFL, flags | O_NONBLOCK)) {
610 perror("fcntl()");
611 ebb_client_close(client);
612 return;
615 client->written = 0;
616 client->write_watcher.data = client;
617 ev_init (&(client->write_watcher), on_client_writable);
618 ev_io_set (&(client->write_watcher), client->fd, EV_WRITE | EV_ERROR);
619 ev_io_start(client->server->loop, &(client->write_watcher));
623 /* pass an allocated buffer and the length to read. this function will try to
624 * fill the buffer with that length of data read from the body of the request.
625 * the return value says how much was actually written.
627 int ebb_client_read(ebb_client *client, char *buffer, int length)
629 size_t read;
631 assert(client->open);
632 assert(client_finished_parsing);
634 if(client->upload_file) {
635 read = fread(buffer, 1, length, client->upload_file);
636 /* TODO error checking! */
637 return read;
638 } else {
639 char* request_body = client->request_buffer + client->parser.nread;
641 read = ramp(min(length, client->content_length - client->nread_from_body));
642 memcpy( buffer
643 , request_body + client->nread_from_body
644 , read
646 client->nread_from_body += read;
647 return read;
651 /* The following socket creation routines are modified and stolen from memcached */
654 static int server_socket_unix(const char *path, int access_mask) {
655 int sfd;
656 struct linger ling = {0, 0};
657 struct sockaddr_un addr;
658 struct stat tstat;
659 int flags =1;
660 int old_umask;
662 if (!path) {
663 return -1;
666 if ((sfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
667 perror("socket()");
668 return -1;
671 if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
672 fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
673 perror("setting O_NONBLOCK");
674 close(sfd);
675 return -1;
679 * Clean up a previous socket file if we left it around
681 if (lstat(path, &tstat) == 0) {
682 if (S_ISSOCK(tstat.st_mode))
683 unlink(path);
686 flags = 1;
687 setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
688 setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
689 setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
692 * the memset call clears nonstandard fields in some impementations
693 * that otherwise mess things up.
695 memset(&addr, 0, sizeof(addr));
697 addr.sun_family = AF_UNIX;
698 strcpy(addr.sun_path, path);
699 old_umask=umask( ~(access_mask&0777));
700 if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
701 perror("bind()");
702 close(sfd);
703 umask(old_umask);
704 return -1;
706 umask(old_umask);
707 if (listen(sfd, EBB_MAX_CLIENTS) == -1) {
708 perror("listen()");
709 close(sfd);
710 return -1;
712 return sfd;