aboutsummaryrefslogtreecommitdiff
path: root/src/daemon/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon/connection.c')
-rw-r--r--src/daemon/connection.c483
1 files changed, 341 insertions, 142 deletions
diff --git a/src/daemon/connection.c b/src/daemon/connection.c
index 21b7872c..bb3d8990 100644
--- a/src/daemon/connection.c
+++ b/src/daemon/connection.c
@@ -27,8 +27,14 @@
27 27
28#include "internal.h" 28#include "internal.h"
29#include "connection.h" 29#include "connection.h"
30#include "memorypool.h"
30#include "response.h" 31#include "response.h"
31 32
33/**
34 * Size by which MHD usually tries to increment read/write buffers.
35 */
36#define MHD_BUF_INC_SIZE 2048
37
32 38
33/** 39/**
34 * Get all of the headers from the request. 40 * Get all of the headers from the request.
@@ -40,9 +46,9 @@
40 */ 46 */
41int 47int
42MHD_get_connection_values(struct MHD_Connection * connection, 48MHD_get_connection_values(struct MHD_Connection * connection,
43 enum MHD_ValueKind kind, 49 enum MHD_ValueKind kind,
44 MHD_KeyValueIterator iterator, 50 MHD_KeyValueIterator iterator,
45 void * iterator_cls) { 51 void * iterator_cls) {
46 int ret; 52 int ret;
47 struct MHD_HTTP_Header * pos; 53 struct MHD_HTTP_Header * pos;
48 54
@@ -131,41 +137,77 @@ MHD_connection_get_fdset(struct MHD_Connection * connection,
131 fd_set * except_fd_set, 137 fd_set * except_fd_set,
132 int * max_fd) { 138 int * max_fd) {
133 int fd; 139 int fd;
140 void * buf;
134 141
135 fd = connection->socket_fd; 142 fd = connection->socket_fd;
136 if (fd == -1) 143 if (fd == -1)
137 return MHD_YES; 144 return MHD_YES;
138 if ( (connection->read_close == 0) && 145 if ( (connection->read_close == 0) &&
139 ( (connection->headersReceived == 0) || 146 ( (connection->headersReceived == 0) ||
140 (connection->readLoc < connection->read_buffer_size) ) ) 147 (connection->readLoc < connection->read_buffer_size) ) ) {
141 FD_SET(fd, read_fd_set); 148 FD_SET(fd, read_fd_set);
142 if (connection->response != NULL) 149 if (fd > *max_fd)
150 *max_fd = fd;
151 } else {
152
153
154 if ( (connection->read_close == 0) &&
155 ( (connection->headersReceived == 1) &&
156 (connection->post_processed == MHD_NO) &&
157 (connection->readLoc == connection->read_buffer_size) ) ) {
158 /* try growing the read buffer, just in case */
159 buf = MHD_pool_reallocate(connection->pool,
160 connection->read_buffer,
161 connection->read_buffer_size,
162 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE);
163 if (buf != NULL) {
164 /* we can actually grow the buffer, do it! */
165 connection->read_buffer = buf;
166 connection->read_buffer_size = connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
167 FD_SET(fd, read_fd_set);
168 if (fd > *max_fd)
169 *max_fd = fd;
170 }
171 }
172 }
173 if (connection->response != NULL) {
143 FD_SET(fd, write_fd_set); 174 FD_SET(fd, write_fd_set);
144 if ( (fd > *max_fd) && 175 if (fd > *max_fd)
145 ( (connection->headersReceived == 0) || 176 *max_fd = fd;
146 (connection->readLoc < connection->read_buffer_size) || 177 }
147 (connection->response != NULL) ) )
148 *max_fd = fd;
149 return MHD_YES; 178 return MHD_YES;
150} 179}
151 180
152/** 181/**
153 * Parse a single line of the HTTP header. Remove it 182 * We ran out of memory processing the
154 * from the read buffer. If the current line does not 183 * header. Handle it properly.
184 */
185static void
186MHD_excessive_header_handler(struct MHD_Connection * connection) {
187 /* die, header far too long to be reasonable;
188 FIXME: send proper response to client
189 (stop reading, queue proper response) */
190 MHD_DLOG(connection->daemon,
191 "Received excessively long header line, closing connection.\n");
192 CLOSE(connection->socket_fd);
193 connection->socket_fd = -1;
194}
195
196/**
197 * Parse a single line of the HTTP header. Advance
198 * read_buffer (!) appropriately. If the current line does not
155 * fit, consider growing the buffer. If the line is 199 * fit, consider growing the buffer. If the line is
156 * far too long, close the connection. If no line is 200 * far too long, close the connection. If no line is
157 * found (incomplete, buffer too small, line too long), 201 * found (incomplete, buffer too small, line too long),
158 * return NULL. Otherwise return a copy of the line. 202 * return NULL. Otherwise return a pointer to the line.
159 */ 203 */
160static char * 204static char *
161MHD_get_next_header_line(struct MHD_Connection * connection) { 205MHD_get_next_header_line(struct MHD_Connection * connection) {
162 char * rbuf; 206 char * rbuf;
163 size_t pos; 207 size_t pos;
164 size_t start;
165 208
166 if (connection->readLoc == 0) 209 if (connection->readLoc == 0)
167 return NULL; 210 return NULL;
168 start = 0;
169 pos = 0; 211 pos = 0;
170 rbuf = connection->read_buffer; 212 rbuf = connection->read_buffer;
171 while ( (pos < connection->readLoc - 1) && 213 while ( (pos < connection->readLoc - 1) &&
@@ -175,56 +217,55 @@ MHD_get_next_header_line(struct MHD_Connection * connection) {
175 if (pos == connection->readLoc - 1) { 217 if (pos == connection->readLoc - 1) {
176 /* not found, consider growing... */ 218 /* not found, consider growing... */
177 if (connection->readLoc == connection->read_buffer_size) { 219 if (connection->readLoc == connection->read_buffer_size) {
178 /* grow buffer to read larger header or die... */ 220 rbuf = MHD_pool_reallocate(connection->pool,
179 if (connection->read_buffer_size < 4 * MHD_MAX_BUF_SIZE) { 221 connection->read_buffer,
180 rbuf = malloc(connection->read_buffer_size * 2); 222 connection->read_buffer_size,
181 memcpy(rbuf, 223 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE);
182 connection->read_buffer, 224 if (rbuf == NULL) {
183 connection->readLoc); 225 MHD_excessive_header_handler(connection);
184 free(connection->read_buffer);
185 connection->read_buffer = rbuf;
186 connection->read_buffer_size *= 2;
187 } else { 226 } else {
188 /* die, header far too long to be reasonable */ 227 connection->read_buffer_size = connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
189 MHD_DLOG(connection->daemon, 228 connection->read_buffer = rbuf;
190 "Received excessively long header line (>%u), closing connection.\n",
191 4 * MHD_MAX_BUF_SIZE);
192 CLOSE(connection->socket_fd);
193 connection->socket_fd = -1;
194 } 229 }
195 } 230 }
196 return NULL; 231 return NULL;
197 } 232 }
198 /* found, check if we have proper CRLF */ 233 /* found, check if we have proper CRLF */
199 rbuf = malloc(pos + 1); 234 if ( (rbuf[pos] == '\r') &&
200 memcpy(rbuf, 235 (rbuf[pos+1] == '\n') )
201 connection->read_buffer, 236 rbuf[pos++] = '\0'; /* skip both r and n */
202 pos); 237 rbuf[pos++] = '\0';
203 rbuf[pos] = '\0'; 238 connection->read_buffer += pos;
204 if ( (connection->read_buffer[pos] == '\r') && 239 connection->read_buffer_size -= pos;
205 (connection->read_buffer[pos+1] == '\n') )
206 pos++; /* skip both r and n */
207 pos++;
208 memmove(connection->read_buffer,
209 &connection->read_buffer[pos],
210 connection->readLoc - pos);
211 connection->readLoc -= pos; 240 connection->readLoc -= pos;
212 return rbuf; 241 return rbuf;
213} 242}
214 243
215static void 244/**
245 * @return MHD_NO on failure (out of memory), MHD_YES for success
246 */
247static int
216MHD_connection_add_header(struct MHD_Connection * connection, 248MHD_connection_add_header(struct MHD_Connection * connection,
217 const char * key, 249 char * key,
218 const char * value, 250 char * value,
219 enum MHD_ValueKind kind) { 251 enum MHD_ValueKind kind) {
220 struct MHD_HTTP_Header * hdr; 252 struct MHD_HTTP_Header * hdr;
221 253
222 hdr = malloc(sizeof(struct MHD_HTTP_Header)); 254 hdr = MHD_pool_allocate(connection->pool,
255 sizeof(struct MHD_HTTP_Header),
256 MHD_YES);
257 if (hdr == NULL) {
258 MHD_DLOG(connection->daemon,
259 "Not enough memory to allocate header record!\n");
260 MHD_excessive_header_handler(connection);
261 return MHD_NO;
262 }
223 hdr->next = connection->headers_received; 263 hdr->next = connection->headers_received;
224 hdr->header = strdup(key); 264 hdr->header = key;
225 hdr->value = strdup(value); 265 hdr->value = value;
226 hdr->kind = kind; 266 hdr->kind = kind;
227 connection->headers_received = hdr; 267 connection->headers_received = hdr;
268 return MHD_YES;
228} 269}
229 270
230/** 271/**
@@ -253,7 +294,10 @@ MHD_http_unescape(char * val) {
253 } 294 }
254} 295}
255 296
256static void 297/**
298 * @return MHD_NO on failure (out of memory), MHD_YES for success
299 */
300static int
257parse_arguments(enum MHD_ValueKind kind, 301parse_arguments(enum MHD_ValueKind kind,
258 struct MHD_Connection * connection, 302 struct MHD_Connection * connection,
259 char * args) { 303 char * args) {
@@ -263,7 +307,7 @@ parse_arguments(enum MHD_ValueKind kind,
263 while (args != NULL) { 307 while (args != NULL) {
264 equals = strstr(args, "="); 308 equals = strstr(args, "=");
265 if (equals == NULL) 309 if (equals == NULL)
266 return; /* invalid, ignore */ 310 return MHD_NO; /* invalid, ignore */
267 equals[0] = '\0'; 311 equals[0] = '\0';
268 equals++; 312 equals++;
269 amper = strstr(equals, "&"); 313 amper = strstr(equals, "&");
@@ -273,18 +317,22 @@ parse_arguments(enum MHD_ValueKind kind,
273 } 317 }
274 MHD_http_unescape(args); 318 MHD_http_unescape(args);
275 MHD_http_unescape(equals); 319 MHD_http_unescape(equals);
276 MHD_connection_add_header(connection, 320 if (MHD_NO == MHD_connection_add_header(connection,
277 args, 321 args,
278 equals, 322 equals,
279 kind); 323 kind))
324 return MHD_NO;
280 args = amper; 325 args = amper;
281 } 326 }
327 return MHD_YES;
282} 328}
283 329
284/** 330/**
285 * Parse the cookie header (see RFC 2109). 331 * Parse the cookie header (see RFC 2109).
332 *
333 * @return MHD_YES for success, MHD_NO for failure (malformed, out of memory)
286 */ 334 */
287static void 335static int
288MHD_parse_cookie_header(struct MHD_Connection * connection) { 336MHD_parse_cookie_header(struct MHD_Connection * connection) {
289 const char * hdr; 337 const char * hdr;
290 char * cpy; 338 char * cpy;
@@ -294,11 +342,22 @@ MHD_parse_cookie_header(struct MHD_Connection * connection) {
294 int quotes; 342 int quotes;
295 343
296 hdr = MHD_lookup_connection_value(connection, 344 hdr = MHD_lookup_connection_value(connection,
297 MHD_HEADER_KIND, 345 MHD_HEADER_KIND,
298 "Cookie"); 346 "Cookie");
299 if (hdr == NULL) 347 if (hdr == NULL)
300 return; 348 return MHD_YES;
301 cpy = strdup(hdr); 349 cpy = MHD_pool_allocate(connection->pool,
350 strlen(hdr)+1,
351 MHD_YES);
352 if (cpy == NULL) {
353 MHD_DLOG(connection->daemon,
354 "Not enough memory to parse cookies!\n");
355 MHD_excessive_header_handler(connection);
356 return MHD_NO;
357 }
358 memcpy(cpy,
359 hdr,
360 strlen(hdr)+1);
302 pos = cpy; 361 pos = cpy;
303 while (pos != NULL) { 362 while (pos != NULL) {
304 equals = strstr(pos, "="); 363 equals = strstr(pos, "=");
@@ -328,13 +387,14 @@ MHD_parse_cookie_header(struct MHD_Connection * connection) {
328 equals[strlen(equals)-1] = '\0'; 387 equals[strlen(equals)-1] = '\0';
329 equals++; 388 equals++;
330 } 389 }
331 MHD_connection_add_header(connection, 390 if (MHD_NO == MHD_connection_add_header(connection,
332 pos, 391 pos,
333 equals, 392 equals,
334 MHD_COOKIE_KIND); 393 MHD_COOKIE_KIND))
394 return MHD_NO;
335 pos = semicolon; 395 pos = semicolon;
336 } 396 }
337 free(cpy); 397 return MHD_YES;
338} 398}
339 399
340/** 400/**
@@ -355,7 +415,7 @@ parse_initial_message_line(struct MHD_Connection * connection,
355 if (uri == NULL) 415 if (uri == NULL)
356 return MHD_NO; /* serious error */ 416 return MHD_NO; /* serious error */
357 uri[0] = '\0'; 417 uri[0] = '\0';
358 connection->method = strdup(line); 418 connection->method = line;
359 uri++; 419 uri++;
360 while (uri[0] == ' ') 420 while (uri[0] == ' ')
361 uri++; 421 uri++;
@@ -372,11 +432,11 @@ parse_initial_message_line(struct MHD_Connection * connection,
372 connection, 432 connection,
373 args); 433 args);
374 } 434 }
375 connection->url = strdup(uri); 435 connection->url = uri;
376 if (httpVersion == NULL) 436 if (httpVersion == NULL)
377 connection->version = strdup(""); 437 connection->version = "";
378 else 438 else
379 connection->version = strdup(httpVersion); 439 connection->version = httpVersion;
380 return MHD_YES; 440 return MHD_YES;
381} 441}
382 442
@@ -398,6 +458,7 @@ MHD_parse_connection_headers(struct MHD_Connection * connection) {
398 char * colon; 458 char * colon;
399 char * tmp; 459 char * tmp;
400 const char * clen; 460 const char * clen;
461 const char * end;
401 unsigned long long cval; 462 unsigned long long cval;
402 463
403 if (connection->bodyReceived == 1) 464 if (connection->bodyReceived == 1)
@@ -409,51 +470,38 @@ MHD_parse_connection_headers(struct MHD_Connection * connection) {
409 (line[0] == '\t') ) { 470 (line[0] == '\t') ) {
410 /* value was continued on the next line, see 471 /* value was continued on the next line, see
411 http://www.jmarshall.com/easy/http/ */ 472 http://www.jmarshall.com/easy/http/ */
412 if ( (strlen(line) + strlen(last) > 473 last = MHD_pool_reallocate(connection->pool,
413 4 * MHD_MAX_BUF_SIZE) ) { 474 last,
414 free(line); 475 strlen(last)+1,
415 free(last); 476 strlen(line) + strlen(last) + 1);
416 last = NULL; 477 if (last == NULL) {
417 MHD_DLOG(connection->daemon, 478 MHD_excessive_header_handler(connection);
418 "Received excessively long header line (>%u), closing connection.\n",
419 4 * MHD_MAX_BUF_SIZE);
420 CLOSE(connection->socket_fd);
421 connection->socket_fd = -1;
422 break; 479 break;
423 } 480 }
424 tmp = malloc(strlen(line) + strlen(last) + 1);
425 strcpy(tmp, last);
426 free(last);
427 last = tmp;
428 tmp = line; 481 tmp = line;
429 while ( (tmp[0] == ' ') || 482 while ( (tmp[0] == ' ') ||
430 (tmp[0] == '\t') ) 483 (tmp[0] == '\t') )
431 tmp++; /* skip whitespace at start of 2nd line */ 484 tmp++; /* skip whitespace at start of 2nd line */
432 strcat(last, tmp); 485 strcat(last, tmp);
433 free(line);
434 continue; /* possibly more than 2 lines... */ 486 continue; /* possibly more than 2 lines... */
435 } else { 487 } else {
436 MHD_connection_add_header(connection, 488 if (MHD_NO == MHD_connection_add_header(connection,
437 last, 489 last,
438 colon, 490 colon,
439 MHD_HEADER_KIND); 491 MHD_HEADER_KIND))
440 free(last); 492 return;
441 last = NULL; 493 last = NULL;
442 } 494 }
443 } 495 }
444 if (connection->url == NULL) { 496 if (connection->url == NULL) {
445 /* line must be request line (first line of header) */ 497 /* line must be request line (first line of header) */
446 if (MHD_NO == parse_initial_message_line(connection, 498 if (MHD_NO == parse_initial_message_line(connection,
447 line)) { 499 line))
448 free(line); 500 goto DIE;
449 goto DIE;
450 }
451 free(line);
452 continue; 501 continue;
453 } 502 }
454 /* check if this is the end of the header */ 503 /* check if this is the end of the header */
455 if (strlen(line) == 0) { 504 if (strlen(line) == 0) {
456 free(line);
457 /* end of header */ 505 /* end of header */
458 connection->headersReceived = 1; 506 connection->headersReceived = 1;
459 clen = MHD_lookup_connection_value(connection, 507 clen = MHD_lookup_connection_value(connection,
@@ -483,6 +531,17 @@ MHD_parse_connection_headers(struct MHD_Connection * connection) {
483 connection->bodyReceived = 0; 531 connection->bodyReceived = 0;
484 } 532 }
485 } 533 }
534 end = MHD_lookup_connection_value(connection,
535 MHD_HEADER_KIND,
536 MHD_HTTP_HEADER_CONNECTION);
537 if ( (end != NULL) &&
538 (0 == strcasecmp(end,
539 "close")) ) {
540 /* other side explicitly requested
541 that we close the connection after
542 this request */
543 connection->read_close = MHD_YES;
544 }
486 break; 545 break;
487 } 546 }
488 /* line should be normal header line, find colon */ 547 /* line should be normal header line, find colon */
@@ -507,13 +566,12 @@ MHD_parse_connection_headers(struct MHD_Connection * connection) {
507 with a space...) */ 566 with a space...) */
508 last = line; 567 last = line;
509 } 568 }
510 if (last != NULL) { 569 if ( (last != NULL) &&
511 MHD_connection_add_header(connection, 570 (MHD_NO == MHD_connection_add_header(connection,
512 last, 571 last,
513 colon, 572 colon,
514 MHD_HEADER_KIND); 573 MHD_HEADER_KIND)) )
515 free(last); 574 return; /* error */
516 }
517 MHD_parse_cookie_header(connection); 575 MHD_parse_cookie_header(connection);
518 return; 576 return;
519 DIE: 577 DIE:
@@ -540,6 +598,103 @@ MHD_find_access_handler(struct MHD_Connection * connection) {
540} 598}
541 599
542/** 600/**
601 * Test if we are able to process the POST data.
602 * This depends on available memory (enough to load
603 * all of the POST data into the pool) and the
604 * content encoding of the POST data. And of course,
605 * this requires that the request is actually a
606 * POST request.
607 *
608 * @return MHD_YES if so
609 */
610static int
611MHD_test_post_data(struct MHD_Connection * connection) {
612 const char * encoding;
613 void * buf;
614
615 if (0 != strcasecmp(connection->method,
616 MHD_HTTP_METHOD_POST))
617 return MHD_NO;
618 encoding = MHD_lookup_connection_value(connection,
619 MHD_HEADER_KIND,
620 MHD_HTTP_HEADER_CONTENT_TYPE);
621 if (encoding == NULL)
622 return MHD_NO;
623 if ( (0 == strcasecmp(MHD_HTTP_POST_ENCODING_FORM_URLENCODED,
624 encoding)) &&
625 (connection->uploadSize != -1) ) {
626 buf = MHD_pool_reallocate(connection->pool,
627 connection->read_buffer,
628 connection->read_buffer_size,
629 connection->uploadSize + 1);
630 if (buf == NULL)
631 return MHD_NO;
632 connection->read_buffer_size = connection->uploadSize + 1;
633 connection->read_buffer = buf;
634 return MHD_YES;
635 }
636 return MHD_NO;
637}
638
639/**
640 * Process the POST data here (adding to headers).
641 *
642 * Needs to first check POST encoding and then do
643 * the right thing (TM). The POST data is in the
644 * connection's post_data buffer between the postPos
645 * and postLoc offsets. The POST message maybe
646 * incomplete. The existing buffer (allocated from
647 * the pool) can be used and modified but must then
648 * be properly removed from the struct.
649 *
650 * @return MHD_YES on success, MHD_NO on error (i.e. out of
651 * memory).
652 */
653static int
654MHD_parse_post_data(struct MHD_Connection * connection) {
655 const char * encoding;
656 int ret;
657
658 encoding = MHD_lookup_connection_value(connection,
659 MHD_HEADER_KIND,
660 MHD_HTTP_HEADER_CONTENT_TYPE);
661 if (encoding == NULL)
662 return MHD_NO;
663 if (0 == strcasecmp(MHD_HTTP_POST_ENCODING_FORM_URLENCODED,
664 encoding)) {
665 ret = parse_arguments(MHD_POSTDATA_KIND,
666 connection,
667 connection->read_buffer);
668 /* invalidate read buffer for other uses --
669 in particular, do not give it to the
670 client; if this were to be needed, we would
671 have to make a copy, which would double memory
672 requirements */
673 connection->read_buffer_size = 0;
674 connection->readLoc = 0;
675 connection->uploadSize = 0;
676 connection->read_buffer = NULL;
677 return ret;
678 }
679 if (0 == strcasecmp(MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA,
680 encoding)) {
681 /* this code should never been reached right now,
682 since the test_post_data function would already
683 return MHD_NO; code is here only for future
684 extensions... */
685 /* see http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 */
686 MHD_DLOG(connection->daemon,
687 "Unsupported multipart encoding of POST data specified, not processing POST data.\n");
688 return MHD_NO;
689 }
690 /* this should never be reached, just here for
691 error checking */
692 MHD_DLOG(connection->daemon,
693 "Unknown encoding of POST data specified, not processing POST data.\n");
694 return MHD_NO;
695}
696
697/**
543 * Call the handler of the application for this 698 * Call the handler of the application for this
544 * connection. 699 * connection.
545 */ 700 */
@@ -552,9 +707,6 @@ MHD_call_connection_handler(struct MHD_Connection * connection) {
552 abort(); /* bad timing... */ 707 abort(); /* bad timing... */
553 ah = MHD_find_access_handler(connection); 708 ah = MHD_find_access_handler(connection);
554 processed = connection->readLoc; 709 processed = connection->readLoc;
555 /* FIXME: in case of POST, we need to
556 process the POST data here as well
557 (adding to the header list! */
558 if (MHD_NO == ah->dh(ah->dh_cls, 710 if (MHD_NO == ah->dh(ah->dh_cls,
559 connection, 711 connection,
560 connection->url, 712 connection->url,
@@ -564,7 +716,7 @@ MHD_call_connection_handler(struct MHD_Connection * connection) {
564 &processed)) { 716 &processed)) {
565 /* serios internal error, close connection */ 717 /* serios internal error, close connection */
566 MHD_DLOG(connection->daemon, 718 MHD_DLOG(connection->daemon,
567 "Internal application error, closing connection."); 719 "Internal application error, closing connection.\n");
568 CLOSE(connection->socket_fd); 720 CLOSE(connection->socket_fd);
569 connection->socket_fd = -1; 721 connection->socket_fd = -1;
570 return; 722 return;
@@ -583,7 +735,6 @@ MHD_call_connection_handler(struct MHD_Connection * connection) {
583 connection->bodyReceived = 1; 735 connection->bodyReceived = 1;
584 connection->readLoc = 0; 736 connection->readLoc = 0;
585 connection->read_buffer_size = 0; 737 connection->read_buffer_size = 0;
586 free(connection->read_buffer);
587 connection->read_buffer = NULL; 738 connection->read_buffer = NULL;
588 } 739 }
589} 740}
@@ -600,17 +751,30 @@ MHD_connection_handle_read(struct MHD_Connection * connection) {
600 int bytes_read; 751 int bytes_read;
601 void * tmp; 752 void * tmp;
602 753
754 if (connection->pool == NULL)
755 connection->pool = MHD_pool_create(connection->daemon->pool_size);
756 if (connection->pool == NULL) {
757 MHD_DLOG(connection->daemon,
758 "Failed to create memory pool!\n");
759 CLOSE(connection->socket_fd);
760 connection->socket_fd = -1;
761 return MHD_NO;
762 }
603 if ( (connection->readLoc >= connection->read_buffer_size) && 763 if ( (connection->readLoc >= connection->read_buffer_size) &&
604 (connection->headersReceived == 0) ) { 764 (connection->headersReceived == 0) ) {
605 /* need to grow read buffer */ 765 /* need to grow read buffer */
606 tmp = malloc(connection->read_buffer_size * 2 + MHD_MAX_BUF_SIZE); 766 tmp = MHD_pool_reallocate(connection->pool,
607 memcpy(tmp, 767 connection->read_buffer,
608 connection->read_buffer, 768 connection->read_buffer_size,
609 connection->read_buffer_size); 769 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE);
610 connection->read_buffer_size = connection->read_buffer_size * 2 + MHD_MAX_BUF_SIZE; 770 if (tmp == NULL) {
611 if (connection->read_buffer != NULL) 771 MHD_DLOG(connection->daemon,
612 free(connection->read_buffer); 772 "Not enough memory for reading headers!\n");
773 MHD_excessive_header_handler(connection);
774 return MHD_NO;
775 }
613 connection->read_buffer = tmp; 776 connection->read_buffer = tmp;
777 connection->read_buffer_size = connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
614 } 778 }
615 if (connection->readLoc >= connection->read_buffer_size) { 779 if (connection->readLoc >= connection->read_buffer_size) {
616 MHD_DLOG(connection->daemon, 780 MHD_DLOG(connection->daemon,
@@ -634,16 +798,28 @@ MHD_connection_handle_read(struct MHD_Connection * connection) {
634 } 798 }
635 if (bytes_read == 0) { 799 if (bytes_read == 0) {
636 /* other side closed connection */ 800 /* other side closed connection */
801 connection->read_close = MHD_YES;
637 if (connection->readLoc > 0) 802 if (connection->readLoc > 0)
638 MHD_call_connection_handler(connection); 803 MHD_call_connection_handler(connection);
639 shutdown(connection->socket_fd, SHUT_RD); 804 shutdown(connection->socket_fd, SHUT_RD);
640 return MHD_YES; 805 return MHD_YES;
641 } 806 }
642 connection->readLoc += bytes_read; 807 connection->readLoc += bytes_read;
643 if (connection->headersReceived == 0) 808 if (connection->headersReceived == 0) {
644 MHD_parse_connection_headers(connection); 809 MHD_parse_connection_headers(connection);
645 if (connection->headersReceived == 1) 810 if (connection->headersReceived == 1) {
646 MHD_call_connection_handler(connection); 811 connection->post_processed = MHD_test_post_data(connection);
812 }
813 }
814 if (connection->headersReceived == 1) {
815 if ( (connection->post_processed == MHD_YES) &&
816 (connection->uploadSize == connection->readLoc) )
817 if (MHD_NO == MHD_parse_post_data(connection))
818 connection->post_processed = MHD_NO;
819 if ( (connection->post_processed == MHD_NO) ||
820 (connection->read_buffer_size == connection->readLoc) )
821 MHD_call_connection_handler(connection);
822 }
647 return MHD_YES; 823 return MHD_YES;
648} 824}
649 825
@@ -666,9 +842,9 @@ MHD_add_extra_headers(struct MHD_Connection * connection) {
666 } else if (NULL == MHD_get_response_header(connection->response, 842 } else if (NULL == MHD_get_response_header(connection->response,
667 MHD_HTTP_HEADER_CONTENT_LENGTH)) { 843 MHD_HTTP_HEADER_CONTENT_LENGTH)) {
668 _REAL_SNPRINTF(buf, 844 _REAL_SNPRINTF(buf,
669 128, 845 128,
670 "%llu", 846 "%llu",
671 (unsigned long long) connection->response->total_size); 847 (unsigned long long) connection->response->total_size);
672 MHD_add_response_header(connection->response, 848 MHD_add_response_header(connection->response,
673 MHD_HTTP_HEADER_CONTENT_LENGTH, 849 MHD_HTTP_HEADER_CONTENT_LENGTH,
674 buf); 850 buf);
@@ -680,7 +856,7 @@ MHD_add_extra_headers(struct MHD_Connection * connection) {
680 * fill it with all of the headers from the 856 * fill it with all of the headers from the
681 * HTTPd's response. 857 * HTTPd's response.
682 */ 858 */
683static void 859static int
684MHD_build_header_response(struct MHD_Connection * connection) { 860MHD_build_header_response(struct MHD_Connection * connection) {
685 size_t size; 861 size_t size;
686 size_t off; 862 size_t off;
@@ -702,7 +878,14 @@ MHD_build_header_response(struct MHD_Connection * connection) {
702 pos = pos->next; 878 pos = pos->next;
703 } 879 }
704 /* produce data */ 880 /* produce data */
705 data = malloc(size + 1); 881 data = MHD_pool_allocate(connection->pool,
882 size + 1,
883 MHD_YES);
884 if (data == NULL) {
885 MHD_DLOG(connection->daemon,
886 "Not enough memory for write!\n");
887 return MHD_NO;
888 }
706 memcpy(data, 889 memcpy(data,
707 code, 890 code,
708 off); 891 off);
@@ -721,7 +904,10 @@ MHD_build_header_response(struct MHD_Connection * connection) {
721 if (off != size) 904 if (off != size)
722 abort(); 905 abort();
723 connection->write_buffer = data; 906 connection->write_buffer = data;
724 connection->write_buffer_size = size; 907 connection->writeLoc = size;
908 connection->writePos = 0;
909 connection->write_buffer_size = size + 1;
910 return MHD_YES;
725} 911}
726 912
727/** 913/**
@@ -743,11 +929,16 @@ MHD_connection_handle_write(struct MHD_Connection * connection) {
743 return MHD_NO; 929 return MHD_NO;
744 } 930 }
745 if (! connection->headersSent) { 931 if (! connection->headersSent) {
746 if (connection->write_buffer == NULL) 932 if ( (connection->write_buffer == NULL) &&
747 MHD_build_header_response(connection); 933 (MHD_NO == MHD_build_header_response(connection)) ) {
934 /* oops - close! */
935 CLOSE(connection->socket_fd);
936 connection->socket_fd = -1;
937 return MHD_NO;
938 }
748 ret = SEND(connection->socket_fd, 939 ret = SEND(connection->socket_fd,
749 &connection->write_buffer[connection->writeLoc], 940 &connection->write_buffer[connection->writePos],
750 connection->write_buffer_size - connection->writeLoc, 941 connection->writeLoc - connection->writePos,
751 0); 942 0);
752 if (ret < 0) { 943 if (ret < 0) {
753 if (errno == EINTR) 944 if (errno == EINTR)
@@ -759,13 +950,17 @@ MHD_connection_handle_write(struct MHD_Connection * connection) {
759 connection->socket_fd = -1; 950 connection->socket_fd = -1;
760 return MHD_YES; 951 return MHD_YES;
761 } 952 }
762 connection->writeLoc += ret; 953 connection->writePos += ret;
763 if (connection->writeLoc == connection->write_buffer_size) { 954 if (connection->writeLoc == connection->writePos) {
764 connection->writeLoc = 0; 955 connection->writeLoc = 0;
765 free(connection->write_buffer); 956 connection->writePos = 0;
957 connection->headersSent = 1;
958 MHD_pool_reallocate(connection->pool,
959 connection->write_buffer,
960 connection->write_buffer_size,
961 0);
766 connection->write_buffer = NULL; 962 connection->write_buffer = NULL;
767 connection->write_buffer_size = 0; 963 connection->write_buffer_size = 0;
768 connection->headersSent = 1;
769 } 964 }
770 return MHD_YES; 965 return MHD_YES;
771 } 966 }
@@ -781,13 +976,13 @@ MHD_connection_handle_write(struct MHD_Connection * connection) {
781 if (response->data_size == 0) { 976 if (response->data_size == 0) {
782 if (response->data != NULL) 977 if (response->data != NULL)
783 free(response->data); 978 free(response->data);
784 response->data = malloc(MHD_MAX_BUF_SIZE); 979 response->data = malloc(MHD_BUF_INC_SIZE);
785 response->data_size = MHD_MAX_BUF_SIZE; 980 response->data_size = MHD_BUF_INC_SIZE;
786 } 981 }
787 ret = response->crc(response->crc_cls, 982 ret = response->crc(response->crc_cls,
788 connection->messagePos, 983 connection->messagePos,
789 response->data, 984 response->data,
790 MAX(MHD_MAX_BUF_SIZE, 985 MAX(MHD_BUF_INC_SIZE,
791 response->data_size - connection->messagePos)); 986 response->data_size - connection->messagePos));
792 if (ret == -1) { 987 if (ret == -1) {
793 /* end of message, signal other side by closing! */ 988 /* end of message, signal other side by closing! */
@@ -838,22 +1033,26 @@ MHD_connection_handle_write(struct MHD_Connection * connection) {
838 connection->headersSent = 0; 1033 connection->headersSent = 0;
839 connection->bodyReceived = 0; 1034 connection->bodyReceived = 0;
840 connection->messagePos = 0; 1035 connection->messagePos = 0;
841 free(connection->method);
842 connection->method = NULL; 1036 connection->method = NULL;
843 free(connection->url);
844 connection->url = NULL; 1037 connection->url = NULL;
845 free(connection->write_buffer);
846 connection->write_buffer = NULL;
847 connection->write_buffer_size = 0;
848 if ( (connection->read_close != 0) || 1038 if ( (connection->read_close != 0) ||
849 (0 != strcasecmp(MHD_HTTP_VERSION_1_1, 1039 (0 != strcasecmp(MHD_HTTP_VERSION_1_1,
850 connection->version)) ) { 1040 connection->version)) ) {
851 /* closed for reading => close for good! */ 1041 /* closed for reading => close for good! */
852 CLOSE(connection->socket_fd); 1042 if (connection->socket_fd != -1)
1043 CLOSE(connection->socket_fd);
853 connection->socket_fd = -1; 1044 connection->socket_fd = -1;
854 } 1045 }
855 free(connection->version);
856 connection->version = NULL; 1046 connection->version = NULL;
1047 connection->read_buffer = NULL;
1048 connection->write_buffer = NULL;
1049 connection->read_buffer_size = 0;
1050 connection->readLoc = 0;
1051 connection->write_buffer_size = 0;
1052 connection->writePos = 0;
1053 connection->writeLoc = 0;
1054 MHD_pool_destroy(connection->pool);
1055 connection->pool = NULL;
857 } 1056 }
858 return MHD_YES; 1057 return MHD_YES;
859} 1058}