changeset 854:158d980889ac

Further refactoring of request.c to work with CGI
author Adam Chlipala <adamc@hcoop.net>
date Tue, 23 Jun 2009 15:40:35 -0400
parents 19fdeef40ada
children 28e42b22424d
files include/request.h include/urweb.h src/c/driver.c src/c/request.c src/c/urweb.c
diffstat 5 files changed, 130 insertions(+), 109 deletions(-) [+]
line wrap: on
line diff
--- a/include/request.h	Tue Jun 23 14:05:12 2009 -0400
+++ b/include/request.h	Tue Jun 23 15:40:35 2009 -0400
@@ -13,7 +13,10 @@
 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);
 
--- a/include/urweb.h	Tue Jun 23 14:05:12 2009 -0400
+++ b/include/urweb.h	Tue Jun 23 15:40:35 2009 -0400
@@ -24,8 +24,7 @@
 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);
--- a/src/c/driver.c	Tue Jun 23 14:05:12 2009 -0400
+++ b/src/c/driver.c	Tue Jun 23 15:40:35 2009 -0400
@@ -54,6 +54,25 @@
 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 @@
 
     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 @@
       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;      
+          }
         }
 
-        rr = uw_request(rc, ctx, buf, back - buf, sock);
+        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, method, path, query_string, body, back - body, sock);
         uw_send(ctx, sock);
 
         if (rr == SERVED || rr == FAILED)
@@ -127,6 +217,7 @@
       }
     }
 
+  done:
     uw_reset(ctx);
   }
 }
--- a/src/c/request.c	Tue Jun 23 14:05:12 2009 -0400
+++ b/src/c/request.c	Tue Jun 23 15:40:35 2009 -0400
@@ -151,40 +151,19 @@
   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 @@
       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 @@
       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 @@
   }
 
   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 @@
         }
       }
 
-      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 @@
     }
   }
   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;
--- a/src/c/urweb.c	Tue Jun 23 14:05:12 2009 -0400
+++ b/src/c/urweb.c	Tue Jun 23 15:40:35 2009 -0400
@@ -310,7 +310,8 @@
 } 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 @@
 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 @@
   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 @@
 }
 
 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_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 @@
     }
   }
 
-  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;
     }