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