summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Adam Chlipala <adamc@hcoop.net>2009-06-23 15:40:35 -0400
committerGravatar Adam Chlipala <adamc@hcoop.net>2009-06-23 15:40:35 -0400
commit1109a4e1c8b10a8f524c1406a4db98eff55b435c (patch)
treeaf01ca9d932ba6488f14fb3216de25677bf98634
parent3602f46fee1c01d173177298abd3caa58e3d946b (diff)
Further refactoring of request.c to work with CGI
-rw-r--r--include/request.h5
-rw-r--r--include/urweb.h3
-rw-r--r--src/c/driver.c105
-rw-r--r--src/c/request.c54
-rw-r--r--src/c/urweb.c72
5 files changed, 130 insertions, 109 deletions
diff --git a/include/request.h b/include/request.h
index 1111f47f..7a2dc517 100644
--- a/include/request.h
+++ b/include/request.h
@@ -13,7 +13,10 @@ void uw_sign(const char *in, char *out);
uw_request_context uw_new_request_context(void);
void uw_free_request_context(uw_request_context);
-request_result uw_request(uw_request_context, uw_context, char *request, size_t request_len, int sock);
+request_result uw_request(uw_request_context, uw_context,
+ char *method, char *path, char *query_string,
+ char *body, size_t body_len,
+ int sock);
uw_context uw_request_new_context(void);
diff --git a/include/urweb.h b/include/urweb.h
index a286f9c8..55347030 100644
--- a/include/urweb.h
+++ b/include/urweb.h
@@ -24,8 +24,7 @@ void uw_reset_keep_request(uw_context);
void uw_reset_keep_error_message(uw_context);
failure_kind uw_begin_init(uw_context);
-void uw_set_headers(uw_context, char *headers);
-void uw_headers_moved(uw_context ctx, char *headers);
+void uw_set_headers(uw_context, char *(*get_header)(void *, const char *), void *get_header_data);
failure_kind uw_begin(uw_context, char *path);
void uw_login(uw_context);
void uw_commit(uw_context);
diff --git a/src/c/driver.c b/src/c/driver.c
index 56eba9a6..e8345be2 100644
--- a/src/c/driver.c
+++ b/src/c/driver.c
@@ -54,6 +54,25 @@ static int dequeue() {
static pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER;
+static char *get_header(void *data, const char *h) {
+ char *s = data;
+ int len = strlen(h);
+ char *p;
+
+ while (p = strchr(s, ':')) {
+ if (p - s == len && !strncasecmp(s, h, len)) {
+ return p + 2;
+ } else {
+ if ((s = strchr(p, 0)) && s[1] != 0)
+ s += 2;
+ else
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
static void *worker(void *data) {
int me = *(int *)data;
uw_context ctx = uw_request_new_context();
@@ -75,7 +94,7 @@ static void *worker(void *data) {
while (1) {
int r;
- char *s1, *s2;
+ char *method, *path, *query_string, *headers, *body, *s, *s2;
if (back - buf == buf_size - 1) {
char *new_buf;
@@ -100,22 +119,93 @@ static void *worker(void *data) {
back += r;
*back = 0;
- if ((s1 = strstr(buf, "\r\n\r\n"))) {
+ if ((body = strstr(buf, "\r\n\r\n"))) {
request_result rr;
- if ((s2 = strcasestr(buf, "\r\nContent-Length: ")) && s2 < s1) {
+ body[0] = body[1] = 0;
+ body += 4;
+
+ if ((s = strcasestr(buf, "\r\nContent-Length: ")) && s < body) {
int clen;
- if (sscanf(s2 + 18, "%d\r\n", &clen) != 1) {
+ if (sscanf(s + 18, "%d\r\n", &clen) != 1) {
fprintf(stderr, "Malformed Content-Length header\n");
break;
}
- if (s1 + 4 + clen > back)
- continue;
+ while (back - body < clen) {
+ if (back - buf == buf_size - 1) {
+ char *new_buf;
+ buf_size *= 2;
+ new_buf = realloc(buf, buf_size);
+
+ back = new_buf + (back - buf);
+ body = new_buf + (body - buf);
+ s = new_buf + (s - buf);
+
+ buf = new_buf;
+ }
+
+ r = recv(sock, back, buf_size - 1 - (back - buf), 0);
+
+ if (r < 0) {
+ fprintf(stderr, "Recv failed\n");
+ close(sock);
+ goto done;
+ }
+
+ if (r == 0) {
+ fprintf(stderr, "Connection closed.\n");
+ close(sock);
+ goto done;
+ }
+
+ back += r;
+ *back = 0;
+ }
+ }
+
+ if (!(s = strstr(buf, "\r\n"))) {
+ fprintf(stderr, "No newline in request\n");
+ close(sock);
+ goto done;
+ }
+
+ *s = 0;
+ headers = s + 2;
+ method = s = buf;
+
+ if (!strsep(&s, " ")) {
+ fprintf(stderr, "No first space in HTTP command\n");
+ close(sock);
+ goto done;
+ }
+ path = s;
+
+ if (s = strchr(path, ' '))
+ *s = 0;
+
+ if (s = strchr(path, '?')) {
+ *s = 0;
+ query_string = s+1;
}
+ else
+ query_string = NULL;
+
+ s = headers;
+ while (s2 = strchr(s, '\r')) {
+ s = s2;
+
+ if (s[1] == 0)
+ break;
+
+ *s = 0;
+ s += 2;
+ }
+
+ uw_set_headers(ctx, get_header, headers);
- rr = uw_request(rc, ctx, buf, back - buf, sock);
+ rr = uw_request(rc, ctx, method, path, query_string, body, back - body, sock);
uw_send(ctx, sock);
if (rr == SERVED || rr == FAILED)
@@ -127,6 +217,7 @@ static void *worker(void *data) {
}
}
+ done:
uw_reset(ctx);
}
}
diff --git a/src/c/request.c b/src/c/request.c
index b13c6118..10a75673 100644
--- a/src/c/request.c
+++ b/src/c/request.c
@@ -151,40 +151,19 @@ void uw_free_request_context(uw_request_context r) {
free(r);
}
-request_result uw_request(uw_request_context rc, uw_context ctx, char *request, size_t request_len, int sock) {
+request_result uw_request(uw_request_context rc, uw_context ctx,
+ char *method, char *path, char *query_string,
+ char *body, size_t body_len,
+ int sock) {
int retries_left = MAX_RETRIES;
char *s;
failure_kind fk;
int is_post = 0, do_normal_send = 1;
char *boundary = NULL;
size_t boundary_len;
- char *cmd, *path, *headers, *inputs, *after_headers;
+ char *inputs;
- if (!(s = strstr(request, "\r\n\r\n"))) {
- fprintf(stderr, "No end of headers found in request\n");
- return FAILED;
- }
-
- s[2] = 0;
- after_headers = s + 4;
-
- if (!(s = strstr(request, "\r\n"))) {
- fprintf(stderr, "No newline in request\n");
- return FAILED;
- }
-
- *s = 0;
- headers = s + 2;
- cmd = s = request;
-
- if (!strsep(&s, " ")) {
- fprintf(stderr, "No first space in HTTP command\n");
- return FAILED;
- }
-
- uw_set_headers(ctx, headers);
-
- if (!strcmp(cmd, "POST")) {
+ if (!strcmp(method, "POST")) {
char *clen_s = uw_Basis_requestHeader(ctx, "Content-length");
if (!clen_s) {
fprintf(stderr, "No Content-length with POST\n");
@@ -196,7 +175,7 @@ request_result uw_request(uw_request_context rc, uw_context ctx, char *request,
return FAILED;
}
- if (request + request_len - after_headers < clen) {
+ if (body_len < clen) {
fprintf(stderr, "Request doesn't contain all POST data (according to Content-Length)\n");
return FAILED;
}
@@ -215,14 +194,8 @@ request_result uw_request(uw_request_context rc, uw_context ctx, char *request,
boundary[1] = '-';
boundary_len = strlen(boundary);
}
- } else if (strcmp(cmd, "GET")) {
- fprintf(stderr, "Not ready for non-GET/POST command: %s\n", cmd);
- return FAILED;
- }
-
- path = s;
- if (!strsep(&s, " ")) {
- fprintf(stderr, "No second space in HTTP command\n");
+ } else if (strcmp(method, "GET")) {
+ fprintf(stderr, "Not ready for non-GET/POST command: %s\n", method);
return FAILED;
}
@@ -248,7 +221,7 @@ request_result uw_request(uw_request_context rc, uw_context ctx, char *request,
}
if (boundary) {
- char *part = after_headers, *after_sub_headers, *header, *after_header;
+ char *part = body, *after_sub_headers, *header, *after_header;
size_t part_len;
part = strstr(part, boundary);
@@ -329,7 +302,7 @@ request_result uw_request(uw_request_context rc, uw_context ctx, char *request,
}
}
- part = memmem(after_sub_headers, request + request_len - after_sub_headers, boundary, boundary_len);
+ part = memmem(after_sub_headers, body + body_len - after_sub_headers, boundary, boundary_len);
if (!part) {
fprintf(stderr, "Missing boundary after multipart payload\n");
return FAILED;
@@ -353,10 +326,7 @@ request_result uw_request(uw_request_context rc, uw_context ctx, char *request,
}
}
else {
- if (is_post)
- inputs = after_headers;
- else if (inputs = strchr(path, '?'))
- *inputs++ = 0;
+ inputs = is_post ? body : query_string;
if (inputs) {
char *name, *value;
diff --git a/src/c/urweb.c b/src/c/urweb.c
index 864a5daa..3f71666a 100644
--- a/src/c/urweb.c
+++ b/src/c/urweb.c
@@ -310,7 +310,8 @@ typedef struct {
} transactional;
struct uw_context {
- char *headers, *headers_end;
+ char *(*get_header)(void *, const char *);
+ void *get_header_data;
buf outHeaders, page, heap, script;
input *inputs, *subinputs, *cur_container;
@@ -348,7 +349,8 @@ extern int uw_inputs_len, uw_timeout;
uw_context uw_init() {
uw_context ctx = malloc(sizeof(struct uw_context));
- ctx->headers = ctx->headers_end = NULL;
+ ctx->get_header = NULL;
+ ctx->get_header_data = NULL;
buf_init(&ctx->outHeaders, 0);
buf_init(&ctx->page, 0);
@@ -458,26 +460,9 @@ failure_kind uw_begin_init(uw_context ctx) {
return r;
}
-void uw_set_headers(uw_context ctx, char *headers) {
- char *s = headers, *s2;
- ctx->headers = headers;
-
- while (s2 = strchr(s, '\r')) {
- s = s2;
-
- if (s[1] == 0)
- break;
-
- *s = 0;
- s += 2;
- }
-
- ctx->headers_end = s;
-}
-
-void uw_headers_moved(uw_context ctx, char *headers) {
- ctx->headers_end = headers + (ctx->headers_end - ctx->headers);
- ctx->headers = headers;
+void uw_set_headers(uw_context ctx, char *(*get_header)(void *, const char *), void *get_header_data) {
+ ctx->get_header = get_header;
+ ctx->get_header_data = get_header_data;
}
int uw_db_begin(uw_context);
@@ -523,21 +508,7 @@ void uw_push_cleanup(uw_context ctx, void (*func)(void *), void *arg) {
}
uw_Basis_string uw_Basis_requestHeader(uw_context ctx, uw_Basis_string h) {
- int len = strlen(h);
- char *s = ctx->headers, *p;
-
- while (p = strchr(s, ':')) {
- if (p - s == len && !strncasecmp(s, h, len)) {
- return p + 2;
- } else {
- if ((s = strchr(p, 0)) && s < ctx->headers_end)
- s += 2;
- else
- return NULL;
- }
- }
-
- return NULL;
+ return ctx->get_header(ctx->get_header_data, h);
}
void uw_login(uw_context ctx) {
@@ -2377,7 +2348,7 @@ uw_Basis_blob uw_Basis_stringToBlob_error(uw_context ctx, uw_Basis_string s, siz
uw_Basis_string uw_Basis_get_cookie(uw_context ctx, uw_Basis_string c) {
int len = strlen(c);
- char *s = ctx->headers, *p = ctx->outHeaders.start;
+ char *p = ctx->outHeaders.start;
while (p = strstr(p, "\nSet-Cookie: ")) {
char *p2;
@@ -2396,25 +2367,12 @@ uw_Basis_string uw_Basis_get_cookie(uw_context ctx, uw_Basis_string c) {
}
}
- while (p = strchr(s, ':')) {
- if (!strncasecmp(s, "Cookie: ", 8)) {
- p += 2;
- while (1) {
- if (!strncmp(p, c, len)
- && p + len < ctx->headers_end && p[len] == '=')
- return p + 1 + len;
- else if (p = strchr(p, ';'))
- p += 2;
- else if ((s = strchr(s, 0)) && s < ctx->headers_end) {
- s += 2;
- break;
- }
- else
- return NULL;
- }
- } else {
- if ((s = strchr(p, 0)) && s < ctx->headers_end)
- s += 2;
+ if (p = uw_Basis_requestHeader(ctx, "Cookie")) {
+ while (1) {
+ if (!strncmp(p, c, len) && p[len] == '=')
+ return p + 1 + len;
+ else if (p = strchr(p, ';'))
+ p += 2;
else
return NULL;
}