diff src/c/driver.c @ 737:d049d31a1966

Initial support for blobs and upload
author Adam Chlipala <adamc@hcoop.net>
date Sat, 25 Apr 2009 13:59:11 -0400
parents f2a2be93331c
children 4bb7e1c0550a
line wrap: on
line diff
--- a/src/c/driver.c	Thu Apr 23 16:13:02 2009 -0400
+++ b/src/c/driver.c	Sat Apr 25 13:59:11 2009 -0400
@@ -1,5 +1,6 @@
+#define _GNU_SOURCE
+
 #include <stdio.h>
-
 #include <string.h>
 #include <stdlib.h>
 #include <sys/types.h>
@@ -147,9 +148,11 @@
 static void *worker(void *data) {
   int me = *(int *)data, retries_left = MAX_RETRIES;
   uw_context ctx = new_context();
+  size_t buf_size = 1;
+  char *buf = malloc(buf_size);
 
   while (1) {
-    char buf[uw_bufsize+1], *back = buf, *s, *post;
+    char *back = buf, *s, *post;
     int sock, dont_close = 0;
 
     pthread_mutex_lock(&queue_mutex);
@@ -162,7 +165,17 @@
 
     while (1) {
       unsigned retries_left = MAX_RETRIES;
-      int r = recv(sock, back, uw_bufsize - (back - buf), 0);
+      int r;
+
+      if (back - buf == buf_size) {
+        char *new_buf;
+        buf_size *= 2;
+        new_buf = realloc(buf, buf_size);
+        back = new_buf + (back - buf);
+        buf = new_buf;
+      }
+
+      r = recv(sock, back, buf_size - (back - buf), 0);
 
       if (r < 0) {
         fprintf(stderr, "Recv failed\n");
@@ -182,8 +195,12 @@
       if (s = strstr(buf, "\r\n\r\n")) {
         failure_kind fk;
         int is_post = 0;
+        char *boundary = NULL;
+        size_t boundary_len;
         char *cmd, *path, *headers, path_copy[uw_bufsize+1], *inputs, *after_headers;
 
+        //printf("All: %s\n", buf);
+
         s[2] = 0;
         after_headers = s + 4;
 
@@ -196,7 +213,7 @@
         headers = s + 2;
         cmd = s = buf;
 
-        printf("Read: %s\n", buf);
+        //printf("Read: %s\n", buf);
       
         if (!strsep(&s, " ")) {
           fprintf(stderr, "No first space in HTTP command\n");
@@ -208,17 +225,25 @@
         if (!strcmp(cmd, "POST")) {
           char *clen_s = uw_Basis_requestHeader(ctx, "Content-length");
           if (!clen_s) {
-            printf("No Content-length with POST\n");
+            fprintf(stderr, "No Content-length with POST\n");
             goto done;
           }
           int clen = atoi(clen_s);
           if (clen < 0) {
-            printf("Negative Content-length with POST\n");
+            fprintf(stderr, "Negative Content-length with POST\n");
             goto done;
           }
 
           while (back - after_headers < clen) {
-            r = recv(sock, back, uw_bufsize - (back - buf), 0);
+            if (back - buf == buf_size) {
+              char *new_buf;
+              buf_size *= 2;
+              new_buf = realloc(buf, buf_size);
+              back = new_buf + (back - buf);
+              buf = new_buf;
+            }
+
+            r = recv(sock, back, buf_size - (back - buf), 0);
 
             if (r < 0) {
               fprintf(stderr, "Recv failed\n");
@@ -235,6 +260,19 @@
           }
 
           is_post = 1;
+
+          clen_s = uw_Basis_requestHeader(ctx, "Content-type");
+          if (clen_s && !strncasecmp(clen_s, "multipart/form-data", 19)) {
+            if (strncasecmp(clen_s + 19, "; boundary=", 11)) {
+              fprintf(stderr, "Bad multipart boundary spec");
+              break;
+            }
+
+            boundary = clen_s + 28;
+            boundary[0] = '-';
+            boundary[1] = '-';
+            boundary_len = strlen(boundary);
+          }
         } else if (strcmp(cmd, "GET")) {
           fprintf(stderr, "Not ready for non-GET/POST command: %s\n", cmd);
           break;
@@ -262,26 +300,134 @@
           break;
         }
 
-        if (is_post)
-          inputs = after_headers;
-        else if (inputs = strchr(path, '?'))
-          *inputs++ = 0;
-        if (inputs) {
-          char *name, *value;
+        if (boundary) {
+          char *part = after_headers, *after_sub_headers, *header, *after_header;
+          size_t part_len;
 
-          while (*inputs) {
-            name = inputs;
-            if (inputs = strchr(inputs, '&'))
-              *inputs++ = 0;
-            else
-              inputs = strchr(name, 0);
+          part = strstr(part, boundary);
+          if (!part) {
+            fprintf(stderr, "Missing first multipart boundary\n");
+            break;
+          }
+          part += boundary_len;
 
-            if (value = strchr(name, '=')) {
-              *value++ = 0;
-              uw_set_input(ctx, name, value);
+          while (1) {
+            char *name = NULL, *filename = NULL, *type = NULL;
+
+            if (part[0] == '-' && part[1] == '-')
+              break;
+
+            if (*part != '\r') {
+              fprintf(stderr, "No \\r after multipart boundary\n");
+              goto done;
             }
-            else
-              uw_set_input(ctx, name, "");
+            ++part;
+            if (*part != '\n') {
+              fprintf(stderr, "No \\n after multipart boundary\n");
+              goto done;
+            }
+            ++part;
+            
+            if (!(after_sub_headers = strstr(part, "\r\n\r\n"))) {
+              fprintf(stderr, "Missing end of headers after multipart boundary\n");
+              goto done;
+            }
+            after_sub_headers[2] = 0;
+            after_sub_headers += 4;
+
+            for (header = part; after_header = strstr(header, "\r\n"); header = after_header + 2) {
+              char *colon, *after_colon;
+
+              *after_header = 0;
+              if (!(colon = strchr(header, ':'))) {
+                fprintf(stderr, "Missing colon in multipart sub-header\n");
+                goto done;
+              }
+              *colon++ = 0;
+              if (*colon++ != ' ') {
+                fprintf(stderr, "No space after colon in multipart sub-header\n");
+                goto done;
+              }
+
+              if (!strcasecmp(header, "Content-Disposition")) {
+                if (strncmp(colon, "form-data; ", 11)) {
+                  fprintf(stderr, "Multipart data is not \"form-data\"\n");
+                  goto done;
+                }
+
+                for (colon += 11; after_colon = strchr(colon, '='); colon = after_colon) {
+                  char *data;
+                  after_colon[0] = 0;
+                  if (after_colon[1] != '"') {
+                    fprintf(stderr, "Disposition setting is missing initial quote\n");
+                    goto done;
+                  }
+                  data = after_colon+2;
+                  if (!(after_colon = strchr(data, '"'))) {
+                    fprintf(stderr, "Disposition setting is missing final quote\n");
+                    goto done;
+                  }
+                  after_colon[0] = 0;
+                  ++after_colon;
+                  if (after_colon[0] == ';' && after_colon[1] == ' ')
+                    after_colon += 2;
+
+                  if (!strcasecmp(colon, "name"))
+                    name = data;
+                  else if (!strcasecmp(colon, "filename"))
+                    filename = data;
+                }
+              } else if (!strcasecmp(header, "Content-Type")) {
+                type = colon;
+              }
+            }
+
+            part = memmem(after_sub_headers, back - after_sub_headers, boundary, boundary_len);
+            if (!part) {
+              fprintf(stderr, "Missing boundary after multipart payload\n");
+              goto done;
+            }
+            part[-2] = 0;
+            part_len = part - after_sub_headers - 2;
+            part[0] = 0;
+            part += boundary_len;
+
+            if (filename) {
+              uw_Basis_file *f = malloc(sizeof(uw_Basis_file));
+              uw_Basis_files fs = { 1, f };
+
+              f->name = filename;
+              f->data.size = part_len;
+              f->data.data = after_sub_headers;
+
+              uw_set_file_input(ctx, name, fs);
+            } else
+              uw_set_input(ctx, name, after_sub_headers);
+          }
+        }
+        else {
+          if (is_post)
+            inputs = after_headers;
+          else if (inputs = strchr(path, '?'))
+            *inputs++ = 0;
+
+          if (inputs) {
+            char *name, *value;
+
+            while (*inputs) {
+              name = inputs;
+              if (inputs = strchr(inputs, '&'))
+                *inputs++ = 0;
+              else
+                inputs = strchr(name, 0);
+
+              if (value = strchr(name, '=')) {
+                *value++ = 0;
+                uw_set_input(ctx, name, value);
+              }
+              else
+                uw_set_input(ctx, name, "");
+            }
           }
         }