Mercurial > urweb
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 |