diff options
author | Adam Chlipala <adamc@hcoop.net> | 2009-06-23 15:40:35 -0400 |
---|---|---|
committer | Adam Chlipala <adamc@hcoop.net> | 2009-06-23 15:40:35 -0400 |
commit | 1109a4e1c8b10a8f524c1406a4db98eff55b435c (patch) | |
tree | af01ca9d932ba6488f14fb3216de25677bf98634 | |
parent | 3602f46fee1c01d173177298abd3caa58e3d946b (diff) |
Further refactoring of request.c to work with CGI
-rw-r--r-- | include/request.h | 5 | ||||
-rw-r--r-- | include/urweb.h | 3 | ||||
-rw-r--r-- | src/c/driver.c | 105 | ||||
-rw-r--r-- | src/c/request.c | 54 | ||||
-rw-r--r-- | src/c/urweb.c | 72 |
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; } |