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