src/ebb.c in ebb-0.0.2 vs src/ebb.c in ebb-0.0.3

- old
+ new

@@ -1,8 +1,8 @@ -/* Ebb Web Server - * Copyright (c) 2007 Ry Dahl - * This software is released under the "MIT License". See README file for details. +/* The Ebb Web Server + * Copyright (c) 2008 Ry Dahl. This software is released under the MIT + * License. See README file for details. */ #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <arpa/inet.h> @@ -30,58 +30,44 @@ #define ramp(a) (a > 0 ? a : 0) static int server_socket(const int port); static int server_socket_unix(const char *path, int access_mask); -#define env_add(client, field,flen,value,vlen) \ - client->env_fields[client->env_size] = field; \ - client->env_field_lengths[client->env_size] = flen; \ - client->env_values[client->env_size] = value; \ - client->env_value_lengths[client->env_size] = vlen; \ - client->env_size += 1; -#define env_add_const(client,field,value,vlen) \ - client->env_fields[client->env_size] = NULL; \ - client->env_field_lengths[client->env_size] = field; \ - client->env_values[client->env_size] = value; \ - client->env_value_lengths[client->env_size] = vlen; \ - client->env_size += 1; -#define env_error(client) \ - client->env_fields[client->env_size] = NULL; \ - client->env_field_lengths[client->env_size] = -1; \ - client->env_values[client->env_size] = NULL; \ - client->env_value_lengths[client->env_size] = -1; \ - client->env_size += 1; - -int env_has_error(ebb_client *client) +void env_add(ebb_client *client, const char *field, int flen, const char *value, int vlen) { - int i; - for(i = 0; i < client->env_size; i++) - if(client->env_field_lengths[i] < 0) - return TRUE; - return FALSE; + if(client->env_size >= EBB_MAX_ENV) { + client->parser.overflow_error = TRUE; + return; + } + client->env[client->env_size].type = EBB_FIELD_VALUE_PAIR; + client->env[client->env_size].field = field; + client->env[client->env_size].field_length = flen; + client->env[client->env_size].value = value; + client->env[client->env_size].value_length = vlen; + client->env_size += 1; } -/** Defines common length and error messages for input length validation. */ -#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." -/** Validates the max length of given input and throws an exception if over. */ -#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { env_error(client); g_message(MAX_##N##_LENGTH_ERR); } +void env_add_const(ebb_client *client, int type, const char *value, int vlen) +{ + if(client->env_size >= EBB_MAX_ENV) { + client->parser.overflow_error = TRUE; + return; + } + client->env[client->env_size].type = type; + client->env[client->env_size].field = NULL; + client->env[client->env_size].field_length = -1; + client->env[client->env_size].value = value; + client->env[client->env_size].value_length = vlen; + client->env_size += 1; +} -/* Defines the maximum allowed lengths for various input elements.*/ -DEF_MAX_LENGTH(FIELD_NAME, 256); -DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024); -DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12); -DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */ -DEF_MAX_LENGTH(REQUEST_PATH, 1024); -DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10)); -DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32))); - void http_field_cb(void *data, const char *field, size_t flen, const char *value, size_t vlen) { ebb_client *client = (ebb_client*)(data); - VALIDATE_MAX_LENGTH(flen, FIELD_NAME); - VALIDATE_MAX_LENGTH(vlen, FIELD_VALUE); + assert(field != NULL); + assert(value != NULL); env_add(client, field, flen, value, vlen); } void request_method_cb(void *data, const char *at, size_t length) @@ -92,35 +78,31 @@ void request_uri_cb(void *data, const char *at, size_t length) { ebb_client *client = (ebb_client*)(data); - VALIDATE_MAX_LENGTH(length, REQUEST_URI); env_add_const(client, EBB_REQUEST_URI, at, length); } void fragment_cb(void *data, const char *at, size_t length) { ebb_client *client = (ebb_client*)(data); - VALIDATE_MAX_LENGTH(length, FRAGMENT); env_add_const(client, EBB_FRAGMENT, at, length); } void request_path_cb(void *data, const char *at, size_t length) { ebb_client *client = (ebb_client*)(data); - VALIDATE_MAX_LENGTH(length, REQUEST_PATH); env_add_const(client, EBB_REQUEST_PATH, at, length); } void query_string_cb(void *data, const char *at, size_t length) { ebb_client *client = (ebb_client*)(data); - VALIDATE_MAX_LENGTH(length, QUERY_STRING); env_add_const(client, EBB_QUERY_STRING, at, length); } void http_version_cb(void *data, const char *at, size_t length) @@ -244,10 +226,11 @@ } written += received; } rewind(tmpfile); // g_debug("%d bytes written to file %s", written, client->upload_file_filename); + dispatch(client); return NULL; error: ebb_client_close(client); return NULL; } @@ -262,43 +245,45 @@ assert(client->server->loop == loop); assert(&client->read_watcher == watcher); ssize_t read = recv( client->fd , client->request_buffer + client->read - , EBB_BUFFERSIZE - client->read - 1 /* -1 is for making ragel happy below */ + , EBB_BUFFERSIZE - client->read , 0 ); - if(read <= 0) goto error; /* XXX is this the right action to take for read==0 ? */ + if(read < 0) goto error; /* XXX is this the right action to take for read==0 ? */ + if(read == 0) return; client->read += read; ev_timer_again(loop, &client->timeout_watcher); + if(client->read == EBB_BUFFERSIZE) goto error; + if(FALSE == client_finished_parsing) { - client->request_buffer[client->read] = '\0'; /* make ragel happy */ http_parser_execute( &client->parser , client->request_buffer , client->read , client->parser.nread ); if(http_parser_has_error(&client->parser)) goto error; } - if(total_request_size == client->read) { - ev_io_stop(loop, watcher); - client->nread_from_body = 0; - dispatch(client); - return; + if(client_finished_parsing) { + if(total_request_size == client->read) { + ev_io_stop(loop, watcher); + client->nread_from_body = 0; + dispatch(client); + return; + } + if(total_request_size > EBB_BUFFERSIZE ) { + /* read body into file - in a thread */ + ev_io_stop(loop, watcher); + pthread_t thread; + assert(0 <= pthread_create(&thread, NULL, read_body_into_file, client)); + pthread_detach(thread); + return; + } } - - if(client_finished_parsing && total_request_size > EBB_BUFFERSIZE ) { - /* read body into file - in a thread */ - pthread_t thread; - ev_io_stop(loop, watcher); - assert(0 <= pthread_create(&thread, NULL, read_body_into_file, client)); - pthread_join(thread, NULL); - dispatch(client); - return; - } return; error: if(read < 0) g_message("Error recving data: %s", strerror(errno)); ebb_client_close(client); } @@ -336,11 +321,16 @@ #ifdef DEBUG int count = 0; for(i = 0; i < EBB_MAX_CLIENTS; i++) if(server->clients[i].open) count += 1; g_debug("%d open connections", count); + + /* does ragel fuck up if request buffer isn't null? */ + for(i=0; i< EBB_BUFFERSIZE; i++) + client->request_buffer[i] = 'A'; #endif + client->open = TRUE; client->server = server; /* DO SOCKET STUFF */ socklen_t len; @@ -360,15 +350,20 @@ client->parser.query_string = query_string_cb; client->parser.http_version = http_version_cb; client->parser.content_length = content_length_cb; /* OTHER */ + client->env_size = 0; client->read = client->nread_from_body = 0; client->response_buffer->len = 0; /* see note in ebb_client_close */ client->content_length = 0; + client->status_sent = FALSE; + client->headers_sent = FALSE; + client->body_sent = FALSE; + /* SETUP READ AND TIMEOUT WATCHERS */ client->read_watcher.data = client; ev_init(&client->read_watcher, on_readable); ev_io_set(&client->read_watcher, client->fd, EV_READ | EV_ERROR); ev_io_start(server->loop, &client->read_watcher); @@ -424,15 +419,12 @@ void ebb_server_unlisten(ebb_server *server) { if(server->open) { - //g_message("Stopping Ebb server"); int i; ebb_client *client; - //for(i=0; i < EBB_MAX_CLIENTS; i++) - // ebb_client_close(client); ev_io_stop(server->loop, &server->request_watcher); close(server->fd); if(server->socketpath) unlink(server->socketpath); server->open = FALSE; @@ -536,11 +528,32 @@ if(client->written == client->response_buffer->len) ebb_client_close(client); } +void ebb_client_write_status(ebb_client *client, int status, const char *human_status) +{ + assert(client->status_sent == FALSE); + g_string_append_printf( client->response_buffer + , "HTTP/1.1 %d %s\r\n" + , status + , human_status + ); + client->status_sent = TRUE; +} +void ebb_client_write_header(ebb_client *client, const char *field, const char *value) +{ + assert(client->status_sent == TRUE); + assert(client->headers_sent == FALSE); + g_string_append_printf( client->response_buffer + , "%s: %s\r\n" + , field + , value + ); +} + void ebb_client_write(ebb_client *client, const char *data, int length) { g_string_append_len(client->response_buffer, data, length); } @@ -703,7 +716,6 @@ perror("listen()"); close(sfd); return -1; } return sfd; -} - +} \ No newline at end of file