diff options
author | Christian Grothoff <christian@grothoff.org> | 2007-06-16 05:28:11 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2007-06-16 05:28:11 +0000 |
commit | b99e151779ca734c1f8e3e2ee66453b3a2b67120 (patch) | |
tree | be8644346ebcfafa6c04eb1f9ecd91653a96bcfd | |
parent | 23eb4a13d8a7418bcb86757c607e40f42336f608 (diff) | |
download | libmicrohttpd-b99e151779ca734c1f8e3e2ee66453b3a2b67120.tar.gz libmicrohttpd-b99e151779ca734c1f8e3e2ee66453b3a2b67120.zip |
cookie and upload end handling
-rw-r--r-- | README | 10 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | src/daemon/daemon.c | 3 | ||||
-rw-r--r-- | src/daemon/internal.h | 8 | ||||
-rw-r--r-- | src/daemon/session.c | 125 |
5 files changed, 118 insertions, 31 deletions
@@ -7,14 +7,7 @@ before certain features can be used at all: | |||
7 | 7 | ||
8 | For PUT/POST: | 8 | For PUT/POST: |
9 | ============= | 9 | ============= |
10 | session.c: | 10 | testing! |
11 | - MHD_parse_session_headers (determine upload size) | ||
12 | - MHD_session_handle_read (proper handling of upload end) | ||
13 | |||
14 | For COOKIES: | ||
15 | ============ | ||
16 | session.c: | ||
17 | - MHD_parse_session_headers: take cookie header apart | ||
18 | 11 | ||
19 | For http-compliance: | 12 | For http-compliance: |
20 | ==================== | 13 | ==================== |
@@ -47,4 +40,3 @@ Other: | |||
47 | buffers | 40 | buffers |
48 | 41 | ||
49 | 42 | ||
50 | |||
diff --git a/configure.ac b/configure.ac index eb6591a7..de88f861 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -21,7 +21,7 @@ | |||
21 | # | 21 | # |
22 | # | 22 | # |
23 | AC_PREREQ(2.57) | 23 | AC_PREREQ(2.57) |
24 | AC_INIT([libmicrohttpd], [0.0.0],[libmicrohttpd@cs.du.edu]) | 24 | AC_INIT([libmicrohttpd], [0.0.0],[libmicrohttpd@gnunet.org]) |
25 | AM_INIT_AUTOMAKE([libmicrohttpd], [0.0.0]) | 25 | AM_INIT_AUTOMAKE([libmicrohttpd], [0.0.0]) |
26 | AM_CONFIG_HEADER([config.h]) | 26 | AM_CONFIG_HEADER([config.h]) |
27 | 27 | ||
@@ -37,7 +37,6 @@ AC_CANONICAL_HOST | |||
37 | AM_PROG_LIBTOOL | 37 | AM_PROG_LIBTOOL |
38 | 38 | ||
39 | # set GCC options | 39 | # set GCC options |
40 | CFLAGS="-Wall -Werror $CFLAGS" | ||
41 | # use '-fno-strict-aliasing', but only if the compiler can take it | 40 | # use '-fno-strict-aliasing', but only if the compiler can take it |
42 | if gcc -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; | 41 | if gcc -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; |
43 | then | 42 | then |
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c index 70d5075f..18bfa30f 100644 --- a/src/daemon/daemon.c +++ b/src/daemon/daemon.c | |||
@@ -317,10 +317,9 @@ MHD_cleanup_sessions(struct MHD_Daemon * daemon) { | |||
317 | } | 317 | } |
318 | 318 | ||
319 | if ( (pos->headersReceived == 1) && | 319 | if ( (pos->headersReceived == 1) && |
320 | (pos->read_buffer_size == pos->readLoc) && | ||
321 | (pos->readLoc > 0) ) | 320 | (pos->readLoc > 0) ) |
322 | MHD_call_session_handler(pos); | 321 | MHD_call_session_handler(pos); |
323 | 322 | ||
324 | prev = pos; | 323 | prev = pos; |
325 | pos = pos->next; | 324 | pos = pos->next; |
326 | } | 325 | } |
diff --git a/src/daemon/internal.h b/src/daemon/internal.h index 154021ed..fad568d8 100644 --- a/src/daemon/internal.h +++ b/src/daemon/internal.h | |||
@@ -230,6 +230,14 @@ struct MHD_Session { | |||
230 | * up in that case). | 230 | * up in that case). |
231 | */ | 231 | */ |
232 | int socket_fd; | 232 | int socket_fd; |
233 | |||
234 | /** | ||
235 | * Has this socket been closed for reading (i.e. | ||
236 | * other side closed the connection)? If so, | ||
237 | * we must completely close the connection once | ||
238 | * we are done sending our response. | ||
239 | */ | ||
240 | int read_close; | ||
233 | 241 | ||
234 | /** | 242 | /** |
235 | * Have we finished receiving all of the headers yet? | 243 | * Have we finished receiving all of the headers yet? |
diff --git a/src/daemon/session.c b/src/daemon/session.c index 29222968..e5335c83 100644 --- a/src/daemon/session.c +++ b/src/daemon/session.c | |||
@@ -131,8 +131,9 @@ MHD_session_get_fdset(struct MHD_Session * session, | |||
131 | fd_set * write_fd_set, | 131 | fd_set * write_fd_set, |
132 | fd_set * except_fd_set, | 132 | fd_set * except_fd_set, |
133 | int * max_fd) { | 133 | int * max_fd) { |
134 | if ( (session->headersReceived == 0) || | 134 | if ( (session->read_close == 0) && |
135 | (session->readLoc < session->read_buffer_size) ) | 135 | ( (session->headersReceived == 0) || |
136 | (session->readLoc < session->read_buffer_size) ) ) | ||
136 | FD_SET(session->socket_fd, read_fd_set); | 137 | FD_SET(session->socket_fd, read_fd_set); |
137 | if (session->response != NULL) | 138 | if (session->response != NULL) |
138 | FD_SET(session->socket_fd, write_fd_set); | 139 | FD_SET(session->socket_fd, write_fd_set); |
@@ -271,6 +272,63 @@ MHD_parse_arguments(struct MHD_Session * session, | |||
271 | } | 272 | } |
272 | 273 | ||
273 | /** | 274 | /** |
275 | * Parse the cookie header (see RFC 2109). | ||
276 | */ | ||
277 | static void | ||
278 | MHD_parse_cookie_header(struct MHD_Session * session) { | ||
279 | const char * hdr; | ||
280 | char * cpy; | ||
281 | char * pos; | ||
282 | char * semicolon; | ||
283 | char * equals; | ||
284 | int quotes; | ||
285 | |||
286 | hdr = MHD_lookup_session_value(session, | ||
287 | MHD_HEADER_KIND, | ||
288 | "Cookie"); | ||
289 | if (hdr == NULL) | ||
290 | return; | ||
291 | cpy = strdup(hdr); | ||
292 | pos = cpy; | ||
293 | while (pos != NULL) { | ||
294 | equals = strstr(pos, "="); | ||
295 | if (equals == NULL) | ||
296 | break; | ||
297 | equals[0] = '\0'; | ||
298 | equals++; | ||
299 | quotes = 0; | ||
300 | semicolon = equals; | ||
301 | while ( (semicolon[0] != '\0') && | ||
302 | ( (quotes != 0) || | ||
303 | ( (semicolon[0] != ';') && | ||
304 | (semicolon[0] != ',') ) ) ) { | ||
305 | if (semicolon[0] == '"') | ||
306 | quotes = (quotes + 1) & 1; | ||
307 | semicolon++; | ||
308 | } | ||
309 | if (semicolon[0] == '\0') | ||
310 | semicolon = NULL; | ||
311 | if (semicolon != NULL) { | ||
312 | semicolon[0] = '\0'; | ||
313 | semicolon++; | ||
314 | } | ||
315 | /* remove quotes */ | ||
316 | if ( (equals[0] == '"') && | ||
317 | (equals[strlen(equals)-1] == '"') ) { | ||
318 | equals[strlen(equals)-1] = '\0'; | ||
319 | equals++; | ||
320 | } | ||
321 | MHD_session_add_header(session, | ||
322 | pos, | ||
323 | equals, | ||
324 | MHD_COOKIE_KIND); | ||
325 | pos = semicolon; | ||
326 | } | ||
327 | free(cpy); | ||
328 | } | ||
329 | |||
330 | |||
331 | /** | ||
274 | * This function is designed to parse the input buffer of a given session. | 332 | * This function is designed to parse the input buffer of a given session. |
275 | * | 333 | * |
276 | * Once the header is complete, it should have set the | 334 | * Once the header is complete, it should have set the |
@@ -287,6 +345,8 @@ MHD_parse_session_headers(struct MHD_Session * session) { | |||
287 | char * uri; | 345 | char * uri; |
288 | char * httpType; | 346 | char * httpType; |
289 | char * args; | 347 | char * args; |
348 | const char * clen; | ||
349 | unsigned long long cval; | ||
290 | 350 | ||
291 | if (session->bodyReceived == 1) | 351 | if (session->bodyReceived == 1) |
292 | abort(); | 352 | abort(); |
@@ -316,16 +376,38 @@ MHD_parse_session_headers(struct MHD_Session * session) { | |||
316 | } | 376 | } |
317 | /* check if this is the end of the header */ | 377 | /* check if this is the end of the header */ |
318 | if (strlen(line) == 0) { | 378 | if (strlen(line) == 0) { |
379 | free(line); | ||
319 | /* end of header */ | 380 | /* end of header */ |
320 | session->headersReceived = 1; | 381 | session->headersReceived = 1; |
321 | /* FIXME: check which methods may have a body, | 382 | clen = MHD_lookup_session_value(session, |
322 | check headers to find out upload size */ | 383 | MHD_HEADER_KIND, |
323 | session->uploadSize = 0; | 384 | "Content-Length"); |
324 | session->bodyReceived = 1; | 385 | if (clen != NULL) { |
325 | free(line); | 386 | if (1 != sscanf(clen, |
387 | "%llu", | ||
388 | &cval)) { | ||
389 | MHD_DLOG(session->daemon, | ||
390 | "Failed to parse Content-Length header `%s', closing connection.\n", | ||
391 | clen); | ||
392 | goto DIE; | ||
393 | } | ||
394 | session->uploadSize = cval; | ||
395 | session->bodyReceived = cval == 0 ? 1 : 0; | ||
396 | } else { | ||
397 | if (NULL == MHD_lookup_session_value(session, | ||
398 | MHD_HEADER_KIND, | ||
399 | "Transfer-Encoding")) { | ||
400 | /* this request does not have a body */ | ||
401 | session->uploadSize = 0; | ||
402 | session->bodyReceived = 1; | ||
403 | } else { | ||
404 | session->uploadSize = -1; /* unknown size */ | ||
405 | session->bodyReceived = 0; | ||
406 | } | ||
407 | } | ||
326 | break; | 408 | break; |
327 | } | 409 | } |
328 | /* ok, line should be normal header line, find colon */ | 410 | /* line should be normal header line, find colon */ |
329 | colon = strstr(line, ": "); | 411 | colon = strstr(line, ": "); |
330 | if (colon == NULL) { | 412 | if (colon == NULL) { |
331 | /* error in header line, die hard */ | 413 | /* error in header line, die hard */ |
@@ -342,7 +424,7 @@ MHD_parse_session_headers(struct MHD_Session * session) { | |||
342 | MHD_HEADER_KIND); | 424 | MHD_HEADER_KIND); |
343 | free(line); | 425 | free(line); |
344 | } | 426 | } |
345 | /* FIXME: here: find cookie header and parse that! */ | 427 | MHD_parse_cookie_header(session); |
346 | return; | 428 | return; |
347 | DIE: | 429 | DIE: |
348 | CLOSE(session->socket_fd); | 430 | CLOSE(session->socket_fd); |
@@ -398,8 +480,12 @@ MHD_call_session_handler(struct MHD_Session * session) { | |||
398 | &session->read_buffer[session->readLoc - processed], | 480 | &session->read_buffer[session->readLoc - processed], |
399 | processed); | 481 | processed); |
400 | session->readLoc = processed; | 482 | session->readLoc = processed; |
401 | session->uploadSize -= processed; | 483 | if (session->uploadSize != -1) |
402 | if (session->uploadSize == 0) { | 484 | session->uploadSize -= processed; |
485 | if ( (session->uploadSize == 0) || | ||
486 | ( (session->readLoc == 0) && | ||
487 | (session->uploadSize == -1) && | ||
488 | (session->socket_fd == -1) ) ) { | ||
403 | session->bodyReceived = 1; | 489 | session->bodyReceived = 1; |
404 | session->readLoc = 0; | 490 | session->readLoc = 0; |
405 | session->read_buffer_size = 0; | 491 | session->read_buffer_size = 0; |
@@ -455,11 +541,9 @@ MHD_session_handle_read(struct MHD_Session * session) { | |||
455 | } | 541 | } |
456 | if (bytes_read == 0) { | 542 | if (bytes_read == 0) { |
457 | /* other side closed connection */ | 543 | /* other side closed connection */ |
458 | /* FIXME: proper handling of end of upload! | 544 | if (session->readLoc > 0) |
459 | If we were receiving an unbounded upload, | 545 | MHD_call_session_handler(session); |
460 | we should finish up nicely now! */ | 546 | shutdown(session->socket_fd, SHUT_RD); |
461 | CLOSE(session->socket_fd); | ||
462 | session->socket_fd = -1; | ||
463 | return MHD_YES; | 547 | return MHD_YES; |
464 | } | 548 | } |
465 | session->readLoc += bytes_read; | 549 | session->readLoc += bytes_read; |
@@ -487,13 +571,13 @@ MHD_add_extra_headers(struct MHD_Session * session) { | |||
487 | "Connection", | 571 | "Connection", |
488 | "close"); | 572 | "close"); |
489 | } else if (NULL == MHD_get_response_header(session->response, | 573 | } else if (NULL == MHD_get_response_header(session->response, |
490 | "Content-length")) { | 574 | "Content-Length")) { |
491 | _REAL_SNPRINTF(buf, | 575 | _REAL_SNPRINTF(buf, |
492 | 128, | 576 | 128, |
493 | "%llu", | 577 | "%llu", |
494 | (unsigned long long) session->response->total_size); | 578 | (unsigned long long) session->response->total_size); |
495 | MHD_add_response_header(session->response, | 579 | MHD_add_response_header(session->response, |
496 | "Content-length", | 580 | "Content-Length", |
497 | buf); | 581 | buf); |
498 | } | 582 | } |
499 | } | 583 | } |
@@ -662,6 +746,11 @@ MHD_session_handle_write(struct MHD_Session * session) { | |||
662 | free(session->write_buffer); | 746 | free(session->write_buffer); |
663 | session->write_buffer = NULL; | 747 | session->write_buffer = NULL; |
664 | session->write_buffer_size = 0; | 748 | session->write_buffer_size = 0; |
749 | if (session->read_close != 0) { | ||
750 | /* closed for reading => close for good! */ | ||
751 | CLOSE(session->socket_fd); | ||
752 | session->socket_fd = -1; | ||
753 | } | ||
665 | } | 754 | } |
666 | return MHD_YES; | 755 | return MHD_YES; |
667 | } | 756 | } |