comparison 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
comparison
equal deleted inserted replaced
736:796e42c93c48 737:d049d31a1966
1 #define _GNU_SOURCE
2
1 #include <stdio.h> 3 #include <stdio.h>
2
3 #include <string.h> 4 #include <string.h>
4 #include <stdlib.h> 5 #include <stdlib.h>
5 #include <sys/types.h> 6 #include <sys/types.h>
6 #include <sys/socket.h> 7 #include <sys/socket.h>
7 #include <netinet/in.h> 8 #include <netinet/in.h>
145 } 146 }
146 147
147 static void *worker(void *data) { 148 static void *worker(void *data) {
148 int me = *(int *)data, retries_left = MAX_RETRIES; 149 int me = *(int *)data, retries_left = MAX_RETRIES;
149 uw_context ctx = new_context(); 150 uw_context ctx = new_context();
151 size_t buf_size = 1;
152 char *buf = malloc(buf_size);
150 153
151 while (1) { 154 while (1) {
152 char buf[uw_bufsize+1], *back = buf, *s, *post; 155 char *back = buf, *s, *post;
153 int sock, dont_close = 0; 156 int sock, dont_close = 0;
154 157
155 pthread_mutex_lock(&queue_mutex); 158 pthread_mutex_lock(&queue_mutex);
156 while (empty()) 159 while (empty())
157 pthread_cond_wait(&queue_cond, &queue_mutex); 160 pthread_cond_wait(&queue_cond, &queue_mutex);
160 163
161 printf("Handling connection with thread #%d.\n", me); 164 printf("Handling connection with thread #%d.\n", me);
162 165
163 while (1) { 166 while (1) {
164 unsigned retries_left = MAX_RETRIES; 167 unsigned retries_left = MAX_RETRIES;
165 int r = recv(sock, back, uw_bufsize - (back - buf), 0); 168 int r;
169
170 if (back - buf == buf_size) {
171 char *new_buf;
172 buf_size *= 2;
173 new_buf = realloc(buf, buf_size);
174 back = new_buf + (back - buf);
175 buf = new_buf;
176 }
177
178 r = recv(sock, back, buf_size - (back - buf), 0);
166 179
167 if (r < 0) { 180 if (r < 0) {
168 fprintf(stderr, "Recv failed\n"); 181 fprintf(stderr, "Recv failed\n");
169 break; 182 break;
170 } 183 }
180 *back = 0; 193 *back = 0;
181 194
182 if (s = strstr(buf, "\r\n\r\n")) { 195 if (s = strstr(buf, "\r\n\r\n")) {
183 failure_kind fk; 196 failure_kind fk;
184 int is_post = 0; 197 int is_post = 0;
198 char *boundary = NULL;
199 size_t boundary_len;
185 char *cmd, *path, *headers, path_copy[uw_bufsize+1], *inputs, *after_headers; 200 char *cmd, *path, *headers, path_copy[uw_bufsize+1], *inputs, *after_headers;
201
202 //printf("All: %s\n", buf);
186 203
187 s[2] = 0; 204 s[2] = 0;
188 after_headers = s + 4; 205 after_headers = s + 4;
189 206
190 if (!(s = strstr(buf, "\r\n"))) { 207 if (!(s = strstr(buf, "\r\n"))) {
194 211
195 *s = 0; 212 *s = 0;
196 headers = s + 2; 213 headers = s + 2;
197 cmd = s = buf; 214 cmd = s = buf;
198 215
199 printf("Read: %s\n", buf); 216 //printf("Read: %s\n", buf);
200 217
201 if (!strsep(&s, " ")) { 218 if (!strsep(&s, " ")) {
202 fprintf(stderr, "No first space in HTTP command\n"); 219 fprintf(stderr, "No first space in HTTP command\n");
203 break; 220 break;
204 } 221 }
206 uw_set_headers(ctx, headers); 223 uw_set_headers(ctx, headers);
207 224
208 if (!strcmp(cmd, "POST")) { 225 if (!strcmp(cmd, "POST")) {
209 char *clen_s = uw_Basis_requestHeader(ctx, "Content-length"); 226 char *clen_s = uw_Basis_requestHeader(ctx, "Content-length");
210 if (!clen_s) { 227 if (!clen_s) {
211 printf("No Content-length with POST\n"); 228 fprintf(stderr, "No Content-length with POST\n");
212 goto done; 229 goto done;
213 } 230 }
214 int clen = atoi(clen_s); 231 int clen = atoi(clen_s);
215 if (clen < 0) { 232 if (clen < 0) {
216 printf("Negative Content-length with POST\n"); 233 fprintf(stderr, "Negative Content-length with POST\n");
217 goto done; 234 goto done;
218 } 235 }
219 236
220 while (back - after_headers < clen) { 237 while (back - after_headers < clen) {
221 r = recv(sock, back, uw_bufsize - (back - buf), 0); 238 if (back - buf == buf_size) {
239 char *new_buf;
240 buf_size *= 2;
241 new_buf = realloc(buf, buf_size);
242 back = new_buf + (back - buf);
243 buf = new_buf;
244 }
245
246 r = recv(sock, back, buf_size - (back - buf), 0);
222 247
223 if (r < 0) { 248 if (r < 0) {
224 fprintf(stderr, "Recv failed\n"); 249 fprintf(stderr, "Recv failed\n");
225 goto done; 250 goto done;
226 } 251 }
233 back += r; 258 back += r;
234 *back = 0; 259 *back = 0;
235 } 260 }
236 261
237 is_post = 1; 262 is_post = 1;
263
264 clen_s = uw_Basis_requestHeader(ctx, "Content-type");
265 if (clen_s && !strncasecmp(clen_s, "multipart/form-data", 19)) {
266 if (strncasecmp(clen_s + 19, "; boundary=", 11)) {
267 fprintf(stderr, "Bad multipart boundary spec");
268 break;
269 }
270
271 boundary = clen_s + 28;
272 boundary[0] = '-';
273 boundary[1] = '-';
274 boundary_len = strlen(boundary);
275 }
238 } else if (strcmp(cmd, "GET")) { 276 } else if (strcmp(cmd, "GET")) {
239 fprintf(stderr, "Not ready for non-GET/POST command: %s\n", cmd); 277 fprintf(stderr, "Not ready for non-GET/POST command: %s\n", cmd);
240 break; 278 break;
241 } 279 }
242 280
260 fprintf(stderr, "Missing fields in .msgs request: %s, %s\n\n", id, pass); 298 fprintf(stderr, "Missing fields in .msgs request: %s, %s\n\n", id, pass);
261 } 299 }
262 break; 300 break;
263 } 301 }
264 302
265 if (is_post) 303 if (boundary) {
266 inputs = after_headers; 304 char *part = after_headers, *after_sub_headers, *header, *after_header;
267 else if (inputs = strchr(path, '?')) 305 size_t part_len;
268 *inputs++ = 0; 306
269 if (inputs) { 307 part = strstr(part, boundary);
270 char *name, *value; 308 if (!part) {
271 309 fprintf(stderr, "Missing first multipart boundary\n");
272 while (*inputs) { 310 break;
273 name = inputs; 311 }
274 if (inputs = strchr(inputs, '&')) 312 part += boundary_len;
275 *inputs++ = 0; 313
276 else 314 while (1) {
277 inputs = strchr(name, 0); 315 char *name = NULL, *filename = NULL, *type = NULL;
278 316
279 if (value = strchr(name, '=')) { 317 if (part[0] == '-' && part[1] == '-')
280 *value++ = 0; 318 break;
281 uw_set_input(ctx, name, value); 319
282 } 320 if (*part != '\r') {
283 else 321 fprintf(stderr, "No \\r after multipart boundary\n");
284 uw_set_input(ctx, name, ""); 322 goto done;
323 }
324 ++part;
325 if (*part != '\n') {
326 fprintf(stderr, "No \\n after multipart boundary\n");
327 goto done;
328 }
329 ++part;
330
331 if (!(after_sub_headers = strstr(part, "\r\n\r\n"))) {
332 fprintf(stderr, "Missing end of headers after multipart boundary\n");
333 goto done;
334 }
335 after_sub_headers[2] = 0;
336 after_sub_headers += 4;
337
338 for (header = part; after_header = strstr(header, "\r\n"); header = after_header + 2) {
339 char *colon, *after_colon;
340
341 *after_header = 0;
342 if (!(colon = strchr(header, ':'))) {
343 fprintf(stderr, "Missing colon in multipart sub-header\n");
344 goto done;
345 }
346 *colon++ = 0;
347 if (*colon++ != ' ') {
348 fprintf(stderr, "No space after colon in multipart sub-header\n");
349 goto done;
350 }
351
352 if (!strcasecmp(header, "Content-Disposition")) {
353 if (strncmp(colon, "form-data; ", 11)) {
354 fprintf(stderr, "Multipart data is not \"form-data\"\n");
355 goto done;
356 }
357
358 for (colon += 11; after_colon = strchr(colon, '='); colon = after_colon) {
359 char *data;
360 after_colon[0] = 0;
361 if (after_colon[1] != '"') {
362 fprintf(stderr, "Disposition setting is missing initial quote\n");
363 goto done;
364 }
365 data = after_colon+2;
366 if (!(after_colon = strchr(data, '"'))) {
367 fprintf(stderr, "Disposition setting is missing final quote\n");
368 goto done;
369 }
370 after_colon[0] = 0;
371 ++after_colon;
372 if (after_colon[0] == ';' && after_colon[1] == ' ')
373 after_colon += 2;
374
375 if (!strcasecmp(colon, "name"))
376 name = data;
377 else if (!strcasecmp(colon, "filename"))
378 filename = data;
379 }
380 } else if (!strcasecmp(header, "Content-Type")) {
381 type = colon;
382 }
383 }
384
385 part = memmem(after_sub_headers, back - after_sub_headers, boundary, boundary_len);
386 if (!part) {
387 fprintf(stderr, "Missing boundary after multipart payload\n");
388 goto done;
389 }
390 part[-2] = 0;
391 part_len = part - after_sub_headers - 2;
392 part[0] = 0;
393 part += boundary_len;
394
395 if (filename) {
396 uw_Basis_file *f = malloc(sizeof(uw_Basis_file));
397 uw_Basis_files fs = { 1, f };
398
399 f->name = filename;
400 f->data.size = part_len;
401 f->data.data = after_sub_headers;
402
403 uw_set_file_input(ctx, name, fs);
404 } else
405 uw_set_input(ctx, name, after_sub_headers);
406 }
407 }
408 else {
409 if (is_post)
410 inputs = after_headers;
411 else if (inputs = strchr(path, '?'))
412 *inputs++ = 0;
413
414 if (inputs) {
415 char *name, *value;
416
417 while (*inputs) {
418 name = inputs;
419 if (inputs = strchr(inputs, '&'))
420 *inputs++ = 0;
421 else
422 inputs = strchr(name, 0);
423
424 if (value = strchr(name, '=')) {
425 *value++ = 0;
426 uw_set_input(ctx, name, value);
427 }
428 else
429 uw_set_input(ctx, name, "");
430 }
285 } 431 }
286 } 432 }
287 433
288 printf("Serving URI %s....\n", path); 434 printf("Serving URI %s....\n", path);
289 435