Mercurial > urweb
comparison src/c/http.c @ 1979:81bc76aa4acd
Merge in upstream changes.
author | Patrick Hurst <phurst@mit.edu> |
---|---|
date | Sat, 18 Jan 2014 18:26:24 -0500 |
parents | 6b80900ddc66 |
children | c93fbd139732 |
comparison
equal
deleted
inserted
replaced
1978:c5143edaf3c7 | 1979:81bc76aa4acd |
---|---|
19 #include "queue.h" | 19 #include "queue.h" |
20 | 20 |
21 extern uw_app uw_application; | 21 extern uw_app uw_application; |
22 | 22 |
23 int uw_backlog = SOMAXCONN; | 23 int uw_backlog = SOMAXCONN; |
24 static int keepalive = 0; | 24 static int keepalive = 0, quiet = 0; |
25 | 25 |
26 static char *get_header(void *data, const char *h) { | 26 static char *get_header(void *data, const char *h) { |
27 char *s = data; | 27 char *s = data; |
28 int len = strlen(h); | 28 int len = strlen(h); |
29 char *p; | 29 char *p; |
60 | 60 |
61 vfprintf(stderr, fmt, ap); | 61 vfprintf(stderr, fmt, ap); |
62 } | 62 } |
63 | 63 |
64 static void log_debug(void *data, const char *fmt, ...) { | 64 static void log_debug(void *data, const char *fmt, ...) { |
65 va_list ap; | 65 if (!quiet) { |
66 va_start(ap, fmt); | 66 va_list ap; |
67 | 67 va_start(ap, fmt); |
68 vprintf(fmt, ap); | 68 |
69 vprintf(fmt, ap); | |
70 } | |
69 } | 71 } |
70 | 72 |
71 static void *worker(void *data) { | 73 static void *worker(void *data) { |
72 int me = *(int *)data; | 74 int me = *(int *)data; |
73 uw_context ctx = uw_request_new_context(me, &uw_application, NULL, log_error, log_debug); | 75 uw_context ctx = uw_request_new_context(me, &uw_application, NULL, log_error, log_debug); |
74 size_t buf_size = 2; | 76 size_t buf_size = 1024; |
75 char *buf = malloc(buf_size), *back = buf; | 77 char *buf = malloc(buf_size), *back = buf; |
76 uw_request_context rc = uw_new_request_context(); | 78 uw_request_context rc = uw_new_request_context(); |
77 int sock = 0; | 79 int sock = 0; |
78 | 80 |
79 while (1) { | 81 while (1) { |
80 if (sock == 0) { | 82 if (sock == 0) { |
81 back = buf; | 83 back = buf; |
82 sock = uw_dequeue(); | 84 sock = uw_dequeue(); |
83 } | 85 } |
84 | 86 |
85 printf("Handling connection with thread #%d.\n", me); | 87 if (!quiet) |
88 printf("Handling connection with thread #%d.\n", me); | |
86 | 89 |
87 while (1) { | 90 while (1) { |
88 int r; | 91 int r; |
89 char *method, *path, *query_string, *headers, *body, *after, *s, *s2; | 92 char *method, *path, *query_string, *headers, *body, *after, *s, *s2; |
90 | 93 |
94 new_buf = realloc(buf, buf_size); | 97 new_buf = realloc(buf, buf_size); |
95 back = new_buf + (back - buf); | 98 back = new_buf + (back - buf); |
96 buf = new_buf; | 99 buf = new_buf; |
97 } | 100 } |
98 | 101 |
99 r = recv(sock, back, buf_size - 1 - (back - buf), 0); | |
100 | |
101 if (r < 0) { | |
102 fprintf(stderr, "Recv failed\n"); | |
103 close(sock); | |
104 sock = 0; | |
105 break; | |
106 } | |
107 | |
108 if (r == 0) { | |
109 printf("Connection closed.\n"); | |
110 close(sock); | |
111 sock = 0; | |
112 break; | |
113 } | |
114 | |
115 back += r; | |
116 *back = 0; | 102 *back = 0; |
117 | 103 body = strstr(buf, "\r\n\r\n"); |
118 if ((body = strstr(buf, "\r\n\r\n"))) { | 104 if (body == NULL) { |
105 r = recv(sock, back, buf_size - 1 - (back - buf), 0); | |
106 | |
107 if (r < 0) { | |
108 if (!quiet) | |
109 fprintf(stderr, "Recv failed\n"); | |
110 close(sock); | |
111 sock = 0; | |
112 break; | |
113 } | |
114 | |
115 if (r == 0) { | |
116 if (!quiet) | |
117 printf("Connection closed.\n"); | |
118 close(sock); | |
119 sock = 0; | |
120 break; | |
121 } | |
122 | |
123 back += r; | |
124 *back = 0; | |
125 } | |
126 | |
127 if (body != NULL || (body = strstr(buf, "\r\n\r\n"))) { | |
119 request_result rr; | 128 request_result rr; |
120 int should_keepalive = 0; | 129 int should_keepalive = 0; |
121 | 130 |
122 body[0] = body[1] = 0; | 131 body[0] = body[1] = 0; |
123 body += 4; | 132 body += 4; |
146 } | 155 } |
147 | 156 |
148 r = recv(sock, back, buf_size - 1 - (back - buf), 0); | 157 r = recv(sock, back, buf_size - 1 - (back - buf), 0); |
149 | 158 |
150 if (r < 0) { | 159 if (r < 0) { |
151 fprintf(stderr, "Recv failed\n"); | 160 if (!quiet) |
161 fprintf(stderr, "Recv failed\n"); | |
152 close(sock); | 162 close(sock); |
153 sock = 0; | 163 sock = 0; |
154 goto done; | 164 goto done; |
155 } | 165 } |
156 | 166 |
157 if (r == 0) { | 167 if (r == 0) { |
158 fprintf(stderr, "Connection closed.\n"); | 168 if (!quiet) |
169 fprintf(stderr, "Connection closed.\n"); | |
159 close(sock); | 170 close(sock); |
160 sock = 0; | 171 sock = 0; |
161 goto done; | 172 goto done; |
162 } | 173 } |
163 | 174 |
204 else | 215 else |
205 query_string = NULL; | 216 query_string = NULL; |
206 | 217 |
207 s = headers; | 218 s = headers; |
208 while ((s2 = strchr(s, '\r'))) { | 219 while ((s2 = strchr(s, '\r'))) { |
220 if (s2 == s) { | |
221 *s = 0; | |
222 break; | |
223 } | |
224 | |
209 s = s2; | 225 s = s2; |
210 | 226 |
211 if (s[1] == 0) | 227 if (s[1] == 0) |
212 break; | 228 break; |
213 | 229 |
216 } | 232 } |
217 | 233 |
218 uw_set_headers(ctx, get_header, headers); | 234 uw_set_headers(ctx, get_header, headers); |
219 uw_set_env(ctx, get_env, NULL); | 235 uw_set_env(ctx, get_env, NULL); |
220 | 236 |
221 printf("Serving URI %s....\n", path); | 237 if (!quiet) |
238 printf("Serving URI %s....\n", path); | |
222 rr = uw_request(rc, ctx, method, path, query_string, body, back - body, | 239 rr = uw_request(rc, ctx, method, path, query_string, body, back - body, |
223 on_success, on_failure, | 240 on_success, on_failure, |
224 NULL, log_error, log_debug, | 241 NULL, log_error, log_debug, |
225 sock, uw_really_send, close); | 242 sock, uw_really_send, close); |
226 | 243 |
227 if (rr != KEEP_OPEN) { | 244 if (rr != KEEP_OPEN) { |
228 char clen[100]; | |
229 | |
230 if (keepalive) { | 245 if (keepalive) { |
231 char *connection = uw_Basis_requestHeader(ctx, "Connection"); | 246 char *connection = uw_Basis_requestHeader(ctx, "Connection"); |
232 | 247 |
233 should_keepalive = !(connection && !strcmp(connection, "close")); | 248 should_keepalive = !(connection && !strcmp(connection, "close")); |
234 } | 249 } |
235 | 250 |
236 if (!should_keepalive) | 251 if (!should_keepalive) |
237 uw_write_header(ctx, "Connection: close\r\n"); | 252 uw_write_header(ctx, "Connection: close\r\n"); |
238 | 253 |
239 sprintf(clen, "Content-length: %d\r\n", uw_pagelen(ctx)); | 254 if (!uw_has_contentLength(ctx)) { |
240 uw_write_header(ctx, clen); | 255 char clen[100]; |
256 | |
257 sprintf(clen, "Content-length: %d\r\n", uw_pagelen(ctx)); | |
258 uw_write_header(ctx, clen); | |
259 } | |
260 | |
241 uw_send(ctx, sock); | 261 uw_send(ctx, sock); |
242 } | 262 } |
243 | 263 |
244 if (rr == SERVED || rr == FAILED) { | 264 if (rr == SERVED || rr == FAILED) { |
245 if (should_keepalive) { | 265 if (should_keepalive) { |
246 // In case any other requests are queued up, shift | 266 // In case any other requests are queued up, shift |
247 // unprocessed part of buffer to front. | 267 // unprocessed part of buffer to front. |
248 int kept = back - after; | 268 int kept = back - after; |
249 memmove(buf, after, kept); | 269 |
250 back = buf + kept; | 270 if (kept == 0) { |
271 // No pipelining going on here. | |
272 // We'd might as well try to switch to a different connection, | |
273 // while we wait for more input on this one. | |
274 uw_enqueue(sock); | |
275 sock = 0; | |
276 } else { | |
277 // More input! Move it to the front and continue in this loop. | |
278 memmove(buf, after, kept); | |
279 back = buf + kept; | |
280 } | |
251 } else { | 281 } else { |
252 close(sock); | 282 close(sock); |
253 sock = 0; | 283 sock = 0; |
254 } | 284 } |
255 } else if (rr != KEEP_OPEN) | 285 } else if (rr == KEEP_OPEN) |
286 sock = 0; | |
287 else | |
256 fprintf(stderr, "Illegal uw_request return code: %d\n", rr); | 288 fprintf(stderr, "Illegal uw_request return code: %d\n", rr); |
257 | 289 |
258 break; | 290 break; |
259 } | 291 } |
260 } | 292 } |
265 | 297 |
266 return NULL; | 298 return NULL; |
267 } | 299 } |
268 | 300 |
269 static void help(char *cmd) { | 301 static void help(char *cmd) { |
270 printf("Usage: %s [-p <port>] [-a <IP address>] [-t <thread count>] [-k]\nThe '-k' option turns on HTTP keepalive.\n", cmd); | 302 printf("Usage: %s [-p <port>] [-a <IP address>] [-t <thread count>] [-k] [-q]\nThe '-k' option turns on HTTP keepalive.\nThe '-q' option turns off some chatter on stdout.\n", cmd); |
271 } | 303 } |
272 | 304 |
273 static void sigint(int signum) { | 305 static void sigint(int signum) { |
274 printf("Exiting....\n"); | 306 printf("Exiting....\n"); |
275 exit(0); | 307 exit(0); |
289 signal(SIGPIPE, SIG_IGN); | 321 signal(SIGPIPE, SIG_IGN); |
290 | 322 |
291 my_addr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP | 323 my_addr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP |
292 memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero); | 324 memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero); |
293 | 325 |
294 while ((opt = getopt(argc, argv, "hp:a:t:k")) != -1) { | 326 while ((opt = getopt(argc, argv, "hp:a:t:kq")) != -1) { |
295 switch (opt) { | 327 switch (opt) { |
296 case '?': | 328 case '?': |
297 fprintf(stderr, "Unknown command-line option"); | 329 fprintf(stderr, "Unknown command-line option\n"); |
298 help(argv[0]); | 330 help(argv[0]); |
299 return 1; | 331 return 1; |
300 | 332 |
301 case 'h': | 333 case 'h': |
302 help(argv[0]); | 334 help(argv[0]); |
330 | 362 |
331 case 'k': | 363 case 'k': |
332 keepalive = 1; | 364 keepalive = 1; |
333 break; | 365 break; |
334 | 366 |
367 case 'q': | |
368 quiet = 1; | |
369 break; | |
370 | |
335 default: | 371 default: |
336 fprintf(stderr, "Unexpected getopt() behavior\n"); | 372 fprintf(stderr, "Unexpected getopt() behavior\n"); |
337 return 1; | 373 return 1; |
338 } | 374 } |
339 } | 375 } |
367 return 1; | 403 return 1; |
368 } | 404 } |
369 | 405 |
370 sin_size = sizeof their_addr; | 406 sin_size = sizeof their_addr; |
371 | 407 |
372 printf("Listening on port %d....\n", uw_port); | 408 if (!quiet) |
409 printf("Listening on port %d....\n", uw_port); | |
373 | 410 |
374 { | 411 { |
375 pthread_t thread; | 412 pthread_t thread; |
376 | 413 |
377 if (pthread_create_big(&thread, NULL, client_pruner, &ls)) { | 414 if (pthread_create_big(&thread, NULL, client_pruner, &ls)) { |
391 | 428 |
392 while (1) { | 429 while (1) { |
393 int new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); | 430 int new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); |
394 | 431 |
395 if (new_fd < 0) { | 432 if (new_fd < 0) { |
396 fprintf(stderr, "Socket accept failed\n"); | 433 if (!quiet) |
397 return 1; | 434 fprintf(stderr, "Socket accept failed\n"); |
398 } | 435 } else { |
399 | 436 if (!quiet) |
400 printf("Accepted connection.\n"); | 437 printf("Accepted connection.\n"); |
401 | 438 |
402 if (keepalive) { | 439 if (keepalive) { |
403 int flag = 1; | 440 int flag = 1; |
404 setsockopt(new_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); | 441 setsockopt(new_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); |
405 } | 442 } |
406 | 443 |
407 uw_enqueue(new_fd); | 444 uw_enqueue(new_fd); |
445 } | |
408 } | 446 } |
409 } | 447 } |
410 | 448 |
411 void *uw_init_client_data() { | 449 void *uw_init_client_data() { |
412 return NULL; | 450 return NULL; |
417 | 455 |
418 void uw_copy_client_data(void *dst, void *src) { | 456 void uw_copy_client_data(void *dst, void *src) { |
419 } | 457 } |
420 | 458 |
421 void uw_do_expunge(uw_context ctx, uw_Basis_client cli, void *data) { | 459 void uw_do_expunge(uw_context ctx, uw_Basis_client cli, void *data) { |
422 if (uw_get_app(ctx)->db_begin(ctx)) | 460 uw_ensure_transaction(ctx); |
423 uw_error(ctx, FATAL, "Error running SQL BEGIN"); | |
424 uw_get_app(ctx)->expunger(ctx, cli); | 461 uw_get_app(ctx)->expunger(ctx, cli); |
425 uw_commit(ctx); | 462 |
463 if (uw_commit(ctx)) | |
464 uw_error(ctx, UNLIMITED_RETRY, "Rerunning expunge transaction"); | |
426 } | 465 } |
427 | 466 |
428 void uw_post_expunge(uw_context ctx, void *data) { | 467 void uw_post_expunge(uw_context ctx, void *data) { |
429 } | 468 } |
430 | 469 |