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.c831
1 files changed, 831 insertions, 0 deletions
diff --git a/src/daemon/connection.c b/src/daemon/connection.c
new file mode 100644
index 00000000..6b82f9e7
--- /dev/null
+++ b/src/daemon/connection.c
@@ -0,0 +1,831 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007 Daniel Pittman
4
5 libmicrohttpd is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 libmicrohttpd is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with libmicrohttpd; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file connection.c
23 * @brief Methods for managing connections
24 * @author Daniel Pittman
25 * @author Christian Grothoff
26 */
27
28#include "internal.h"
29#include "connection.h"
30#include "response.h"
31
32
33/**
34 * Get all of the headers from the request.
35 *
36 * @param iterator callback to call on each header;
37 * maybe NULL (then just count headers)
38 * @param iterator_cls extra argument to iterator
39 * @return number of entries iterated over
40 */
41int
42MHD_get_connection_values(struct MHD_Connection * connection,
43 enum MHD_ValueKind kind,
44 MHD_KeyValueIterator iterator,
45 void * iterator_cls) {
46 int ret;
47 struct MHD_HTTP_Header * pos;
48
49 if (connection == NULL)
50 return -1;
51 ret = 0;
52 pos = connection->headers_received;
53 while (pos != NULL) {
54 if (0 != (pos->kind & kind)) {
55 ret++;
56 if ( (iterator != NULL) &&
57 (MHD_YES != iterator(iterator_cls,
58 kind,
59 pos->header,
60 pos->value)) )
61 return ret;
62 }
63 pos = pos->next;
64 }
65 return ret;
66}
67
68
69/**
70 * Get a particular header value. If multiple
71 * values match the kind, return any one of them.
72 *
73 * @param key the header to look for
74 * @return NULL if no such item was found
75 */
76const char *
77MHD_lookup_connection_value(struct MHD_Connection * connection,
78 enum MHD_ValueKind kind,
79 const char * key) {
80 struct MHD_HTTP_Header * pos;
81
82 if (connection == NULL)
83 return NULL;
84 pos = connection->headers_received;
85 while (pos != NULL) {
86 if ( (0 != (pos->kind & kind)) &&
87 (0 == strcasecmp(key,
88 pos->header)) )
89 return pos->value;
90 pos = pos->next;
91 }
92 return NULL;
93}
94
95/**
96 * Queue a response to be transmitted to the client (as soon as
97 * possible).
98 *
99 * @param connection the connection identifying the client
100 * @param status_code HTTP status code (i.e. 200 for OK)
101 * @param response response to transmit
102 * @return MHD_NO on error (i.e. reply already sent),
103 * MHD_YES on success or if message has been queued
104 */
105int
106MHD_queue_response(struct MHD_Connection * connection,
107 unsigned int status_code,
108 struct MHD_Response * response) {
109 if ( (connection == NULL) ||
110 (response == NULL) ||
111 (connection->response != NULL) ||
112 (connection->bodyReceived == 0) ||
113 (connection->headersReceived == 0) )
114 return MHD_NO;
115 MHD_increment_response_rc(response);
116 connection->response = response;
117 connection->responseCode = status_code;
118 return MHD_YES;
119}
120
121
122/**
123 * Obtain the select sets for this connection
124 *
125 * @return MHD_YES on success
126 */
127int
128MHD_connection_get_fdset(struct MHD_Connection * connection,
129 fd_set * read_fd_set,
130 fd_set * write_fd_set,
131 fd_set * except_fd_set,
132 int * max_fd) {
133 int fd;
134
135 fd = connection->socket_fd;
136 if (fd == -1)
137 return MHD_YES;
138 if ( (connection->read_close == 0) &&
139 ( (connection->headersReceived == 0) ||
140 (connection->readLoc < connection->read_buffer_size) ) )
141 FD_SET(fd, read_fd_set);
142 if (connection->response != NULL)
143 FD_SET(fd, write_fd_set);
144 if ( (fd > *max_fd) &&
145 ( (connection->headersReceived == 0) ||
146 (connection->readLoc < connection->read_buffer_size) ||
147 (connection->response != NULL) ) )
148 *max_fd = fd;
149 return MHD_YES;
150}
151
152/**
153 * Parse a single line of the HTTP header. Remove it
154 * from the read buffer. If the current line does not
155 * fit, consider growing the buffer. If the line is
156 * far too long, close the connection. If no line is
157 * found (incomplete, buffer too small, line too long),
158 * return NULL. Otherwise return a copy of the line.
159 */
160static char *
161MHD_get_next_header_line(struct MHD_Connection * connection) {
162 char * rbuf;
163 size_t pos;
164 size_t start;
165
166 if (connection->readLoc == 0)
167 return NULL;
168 start = 0;
169 pos = 0;
170 rbuf = connection->read_buffer;
171 while ( (pos < connection->readLoc - 1) &&
172 (rbuf[pos] != '\r') &&
173 (rbuf[pos] != '\n') )
174 pos++;
175 if (pos == connection->readLoc - 1) {
176 /* not found, consider growing... */
177 if (connection->readLoc == connection->read_buffer_size) {
178 /* grow buffer to read larger header or die... */
179 if (connection->read_buffer_size < 4 * MHD_MAX_BUF_SIZE) {
180 rbuf = malloc(connection->read_buffer_size * 2);
181 memcpy(rbuf,
182 connection->read_buffer,
183 connection->readLoc);
184 free(connection->read_buffer);
185 connection->read_buffer = rbuf;
186 connection->read_buffer_size *= 2;
187 } else {
188 /* die, header far too long to be reasonable */
189 MHD_DLOG(connection->daemon,
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 }
195 }
196 return NULL;
197 }
198 /* found, check if we have proper CRLF */
199 rbuf = malloc(pos + 1);
200 memcpy(rbuf,
201 connection->read_buffer,
202 pos);
203 rbuf[pos] = '\0';
204 if ( (connection->read_buffer[pos] == '\r') &&
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;
212 return rbuf;
213}
214
215static void
216MHD_connection_add_header(struct MHD_Connection * connection,
217 const char * key,
218 const char * value,
219 enum MHD_ValueKind kind) {
220 struct MHD_HTTP_Header * hdr;
221
222 hdr = malloc(sizeof(struct MHD_HTTP_Header));
223 hdr->next = connection->headers_received;
224 hdr->header = strdup(key);
225 hdr->value = strdup(value);
226 hdr->kind = kind;
227 connection->headers_received = hdr;
228}
229
230/**
231 * Process escape sequences ('+'=space, %HH)
232 */
233static void
234MHD_http_unescape(char * val) {
235 char * esc;
236 unsigned int num;
237
238 while (NULL != (esc = strstr(val, "+")))
239 *esc = ' ';
240 while (NULL != (esc = strstr(val, "%"))) {
241 if ( (1 == sscanf(&esc[1],
242 "%2x",
243 &num)) ||
244 (1 == sscanf(&esc[1],
245 "%2X",
246 &num)) ) {
247 esc[0] = (unsigned char) num;
248 memmove(&esc[1],
249 &esc[3],
250 strlen(&esc[3]));
251 }
252 val = esc+1;
253 }
254}
255
256static void
257MHD_parse_arguments(struct MHD_Connection * connection,
258 char * args) {
259 char * equals;
260 char * amper;
261
262 while (args != NULL) {
263 equals = strstr(args, "=");
264 if (equals == NULL)
265 return; /* invalid, ignore */
266 equals[0] = '\0';
267 equals++;
268 amper = strstr(equals, "&");
269 if (amper != NULL) {
270 amper[0] = '\0';
271 amper++;
272 }
273 MHD_http_unescape(args);
274 MHD_http_unescape(equals);
275 MHD_connection_add_header(connection,
276 args,
277 equals,
278 MHD_GET_ARGUMENT_KIND);
279 args = amper;
280 }
281}
282
283/**
284 * Parse the cookie header (see RFC 2109).
285 */
286static void
287MHD_parse_cookie_header(struct MHD_Connection * connection) {
288 const char * hdr;
289 char * cpy;
290 char * pos;
291 char * semicolon;
292 char * equals;
293 int quotes;
294
295 hdr = MHD_lookup_connection_value(connection,
296 MHD_HEADER_KIND,
297 "Cookie");
298 if (hdr == NULL)
299 return;
300 cpy = strdup(hdr);
301 pos = cpy;
302 while (pos != NULL) {
303 equals = strstr(pos, "=");
304 if (equals == NULL)
305 break;
306 equals[0] = '\0';
307 equals++;
308 quotes = 0;
309 semicolon = equals;
310 while ( (semicolon[0] != '\0') &&
311 ( (quotes != 0) ||
312 ( (semicolon[0] != ';') &&
313 (semicolon[0] != ',') ) ) ) {
314 if (semicolon[0] == '"')
315 quotes = (quotes + 1) & 1;
316 semicolon++;
317 }
318 if (semicolon[0] == '\0')
319 semicolon = NULL;
320 if (semicolon != NULL) {
321 semicolon[0] = '\0';
322 semicolon++;
323 }
324 /* remove quotes */
325 if ( (equals[0] == '"') &&
326 (equals[strlen(equals)-1] == '"') ) {
327 equals[strlen(equals)-1] = '\0';
328 equals++;
329 }
330 MHD_connection_add_header(connection,
331 pos,
332 equals,
333 MHD_COOKIE_KIND);
334 pos = semicolon;
335 }
336 free(cpy);
337}
338
339
340/**
341 * This function is designed to parse the input buffer of a given connection.
342 *
343 * Once the header is complete, it should have set the
344 * headers_received, url and method values and set
345 * headersReceived to 1. If no body is expected, it should
346 * also set "bodyReceived" to 1. Otherwise, it should
347 * set "uploadSize" to the expected size of the body. If the
348 * size of the body is unknown, it should be set to -1.
349 */
350static void
351MHD_parse_connection_headers(struct MHD_Connection * connection) {
352 char * last;
353 char * line;
354 char * colon;
355 char * uri;
356 char * httpType;
357 char * args;
358 char * tmp;
359 const char * clen;
360 unsigned long long cval;
361
362 if (connection->bodyReceived == 1)
363 abort();
364 last = NULL;
365 while (NULL != (line = MHD_get_next_header_line(connection))) {
366 if (last != NULL) {
367 if ( (line[0] == ' ') ||
368 (line[0] == '\t') ) {
369 /* value was continued on the next line, see
370 http://www.jmarshall.com/easy/http/ */
371 if ( (strlen(line) + strlen(last) >
372 4 * MHD_MAX_BUF_SIZE) ) {
373 free(line);
374 free(last);
375 last = NULL;
376 MHD_DLOG(connection->daemon,
377 "Received excessively long header line (>%u), closing connection.\n",
378 4 * MHD_MAX_BUF_SIZE);
379 CLOSE(connection->socket_fd);
380 connection->socket_fd = -1;
381 break;
382 }
383 tmp = malloc(strlen(line) + strlen(last) + 1);
384 strcpy(tmp, last);
385 free(last);
386 last = tmp;
387 tmp = line;
388 while ( (tmp[0] == ' ') ||
389 (tmp[0] == '\t') )
390 tmp++; /* skip whitespace at start of 2nd line */
391 strcat(last, tmp);
392 free(line);
393 continue; /* possibly more than 2 lines... */
394 } else {
395 MHD_connection_add_header(connection,
396 last,
397 colon,
398 MHD_HEADER_KIND);
399 free(last);
400 last = NULL;
401 }
402 }
403 if (connection->url == NULL) {
404 /* line must be request line */
405 uri = strstr(line, " ");
406 if (uri == NULL)
407 goto DIE;
408 uri[0] = '\0';
409 connection->method = strdup(line);
410 uri++;
411 httpType = strstr(uri, " ");
412 if (httpType != NULL) {
413 httpType[0] = '\0';
414 httpType++;
415 }
416 args = strstr(uri, "?");
417 if (args != NULL) {
418 args[0] = '\0';
419 args++;
420 MHD_parse_arguments(connection,
421 args);
422 }
423 connection->url = strdup(uri);
424 if (httpType == NULL)
425 connection->version = strdup("");
426 else
427 connection->version = strdup(httpType);
428 free(line);
429 continue;
430 }
431 /* check if this is the end of the header */
432 if (strlen(line) == 0) {
433 free(line);
434 /* end of header */
435 connection->headersReceived = 1;
436 clen = MHD_lookup_connection_value(connection,
437 MHD_HEADER_KIND,
438 "Content-Length");
439 if (clen != NULL) {
440 if (1 != sscanf(clen,
441 "%llu",
442 &cval)) {
443 MHD_DLOG(connection->daemon,
444 "Failed to parse Content-Length header `%s', closing connection.\n",
445 clen);
446 goto DIE;
447 }
448 connection->uploadSize = cval;
449 connection->bodyReceived = cval == 0 ? 1 : 0;
450 } else {
451 if (NULL == MHD_lookup_connection_value(connection,
452 MHD_HEADER_KIND,
453 "Transfer-Encoding")) {
454 /* this request does not have a body */
455 connection->uploadSize = 0;
456 connection->bodyReceived = 1;
457 } else {
458 connection->uploadSize = -1; /* unknown size */
459 connection->bodyReceived = 0;
460 }
461 }
462 break;
463 }
464 /* line should be normal header line, find colon */
465 colon = strstr(line, ":");
466 if (colon == NULL) {
467 /* error in header line, die hard */
468 MHD_DLOG(connection->daemon,
469 "Received malformed line (no colon), closing connection.\n");
470 goto DIE;
471 }
472 /* zero-terminate header */
473 colon[0] = '\0';
474 colon++; /* advance to value */
475 while ( (colon[0] != '\0') &&
476 ( (colon[0] == ' ') ||
477 (colon[0] == '\t') ) )
478 colon++;
479 /* we do the actual adding of the connection
480 header at the beginning of the while
481 loop since we need to be able to inspect
482 the *next* header line (in case it starts
483 with a space...) */
484 }
485 if (last != NULL) {
486 MHD_connection_add_header(connection,
487 last,
488 colon,
489 MHD_HEADER_KIND);
490 free(last);
491 }
492 MHD_parse_cookie_header(connection);
493 return;
494 DIE:
495 CLOSE(connection->socket_fd);
496 connection->socket_fd = -1;
497}
498
499
500/**
501 * Find the handler responsible for this request.
502 */
503static struct MHD_Access_Handler *
504MHD_find_access_handler(struct MHD_Connection * connection) {
505 struct MHD_Access_Handler * pos;
506
507 pos = connection->daemon->handlers;
508 while (pos != NULL) {
509 if (0 == strcmp(connection->url,
510 pos->uri_prefix))
511 return pos;
512 pos = pos->next;
513 }
514 return &connection->daemon->default_handler;
515}
516
517/**
518 * Call the handler of the application for this
519 * connection.
520 */
521void
522MHD_call_connection_handler(struct MHD_Connection * connection) {
523 struct MHD_Access_Handler * ah;
524 unsigned int processed;
525
526 if (connection->headersReceived == 0)
527 abort(); /* bad timing... */
528 ah = MHD_find_access_handler(connection);
529 processed = connection->readLoc;
530 if (MHD_NO == ah->dh(ah->dh_cls,
531 connection,
532 connection->url,
533 connection->method,
534 connection->read_buffer,
535 &processed)) {
536 /* serios internal error, close connection */
537 MHD_DLOG(connection->daemon,
538 "Internal application error, closing connection.");
539 CLOSE(connection->socket_fd);
540 connection->socket_fd = -1;
541 return;
542 }
543 /* dh left "processed" bytes in buffer for next time... */
544 memmove(connection->read_buffer,
545 &connection->read_buffer[connection->readLoc - processed],
546 processed);
547 if (connection->uploadSize != -1)
548 connection->uploadSize -= (connection->readLoc - processed);
549 connection->readLoc = processed;
550 if ( (connection->uploadSize == 0) ||
551 ( (connection->readLoc == 0) &&
552 (connection->uploadSize == -1) &&
553 (connection->socket_fd == -1) ) ) {
554 connection->bodyReceived = 1;
555 connection->readLoc = 0;
556 connection->read_buffer_size = 0;
557 free(connection->read_buffer);
558 connection->read_buffer = NULL;
559 }
560}
561
562
563/**
564 * This function handles a particular connection when it has been
565 * determined that there is data to be read off a socket. All implementations
566 * (multithreaded, external select, internal select) call this function
567 * to handle reads.
568 */
569int
570MHD_connection_handle_read(struct MHD_Connection * connection) {
571 int bytes_read;
572 void * tmp;
573
574 if ( (connection->readLoc >= connection->read_buffer_size) &&
575 (connection->headersReceived == 0) ) {
576 /* need to grow read buffer */
577 tmp = malloc(connection->read_buffer_size * 2 + MHD_MAX_BUF_SIZE);
578 memcpy(tmp,
579 connection->read_buffer,
580 connection->read_buffer_size);
581 connection->read_buffer_size = connection->read_buffer_size * 2 + MHD_MAX_BUF_SIZE;
582 if (connection->read_buffer != NULL)
583 free(connection->read_buffer);
584 connection->read_buffer = tmp;
585 }
586 if (connection->readLoc >= connection->read_buffer_size) {
587 MHD_DLOG(connection->daemon,
588 "Unexpected call to %s.\n",
589 __FUNCTION__);
590 return MHD_NO;
591 }
592 bytes_read = RECV(connection->socket_fd,
593 &connection->read_buffer[connection->readLoc],
594 connection->read_buffer_size - connection->readLoc,
595 0);
596 if (bytes_read < 0) {
597 if (errno == EINTR)
598 return MHD_NO;
599 MHD_DLOG(connection->daemon,
600 "Failed to receive data: %s\n",
601 STRERROR(errno));
602 CLOSE(connection->socket_fd);
603 connection->socket_fd = -1;
604 return MHD_YES;
605 }
606 if (bytes_read == 0) {
607 /* other side closed connection */
608 if (connection->readLoc > 0)
609 MHD_call_connection_handler(connection);
610 shutdown(connection->socket_fd, SHUT_RD);
611 return MHD_YES;
612 }
613 connection->readLoc += bytes_read;
614 if (connection->headersReceived == 0)
615 MHD_parse_connection_headers(connection);
616 if (connection->headersReceived == 1)
617 MHD_call_connection_handler(connection);
618 return MHD_YES;
619}
620
621/**
622 * Check if we need to set some additional headers
623 * for http-compiliance.
624 */
625static void
626MHD_add_extra_headers(struct MHD_Connection * connection) {
627 const char * have;
628 char buf[128];
629
630 if (connection->response->total_size == -1) {
631 have = MHD_get_response_header(connection->response,
632 "Connection");
633 if (have == NULL)
634 MHD_add_response_header(connection->response,
635 "Connection",
636 "close");
637 } else if (NULL == MHD_get_response_header(connection->response,
638 "Content-Length")) {
639 _REAL_SNPRINTF(buf,
640 128,
641 "%llu",
642 (unsigned long long) connection->response->total_size);
643 MHD_add_response_header(connection->response,
644 "Content-Length",
645 buf);
646 }
647}
648
649/**
650 * Allocate the connection's write buffer and
651 * fill it with all of the headers from the
652 * HTTPd's response.
653 */
654static void
655MHD_build_header_response(struct MHD_Connection * connection) {
656 size_t size;
657 size_t off;
658 struct MHD_HTTP_Header * pos;
659 char code[32];
660 char * data;
661
662 MHD_add_extra_headers(connection);
663 SPRINTF(code,
664 "HTTP/1.1 %u\r\n",
665 connection->responseCode);
666 off = strlen(code);
667 /* estimate size */
668 size = off + 2; /* extra \r\n at the end */
669 pos = connection->response->first_header;
670 while (pos != NULL) {
671 size += strlen(pos->header) + strlen(pos->value) + 4; /* colon, space, linefeeds */
672 pos = pos->next;
673 }
674 /* produce data */
675 data = malloc(size + 1);
676 memcpy(data,
677 code,
678 off);
679 pos = connection->response->first_header;
680 while (pos != NULL) {
681 SPRINTF(&data[off],
682 "%s: %s\r\n",
683 pos->header,
684 pos->value);
685 off += strlen(pos->header) + strlen(pos->value) + 4;
686 pos = pos->next;
687 }
688 sprintf(&data[off],
689 "\r\n");
690 off += 2;
691 if (off != size)
692 abort();
693 connection->write_buffer = data;
694 connection->write_buffer_size = size;
695}
696
697/**
698 * This function was created to handle writes to sockets when it has
699 * been determined that the socket can be written to. All
700 * implementations (multithreaded, external select, internal select)
701 * call this function
702 */
703int
704MHD_connection_handle_write(struct MHD_Connection * connection) {
705 struct MHD_Response * response;
706 int ret;
707
708 response = connection->response;
709 if(response == NULL) {
710 MHD_DLOG(connection->daemon,
711 "Unexpected call to %s.\n",
712 __FUNCTION__);
713 return MHD_NO;
714 }
715 if (! connection->headersSent) {
716 if (connection->write_buffer == NULL)
717 MHD_build_header_response(connection);
718 ret = SEND(connection->socket_fd,
719 &connection->write_buffer[connection->writeLoc],
720 connection->write_buffer_size - connection->writeLoc,
721 0);
722 if (ret < 0) {
723 if (errno == EINTR)
724 return MHD_YES;
725 MHD_DLOG(connection->daemon,
726 "Failed to send data: %s\n",
727 STRERROR(errno));
728 CLOSE(connection->socket_fd);
729 connection->socket_fd = -1;
730 return MHD_YES;
731 }
732 connection->writeLoc += ret;
733 if (connection->writeLoc == connection->write_buffer_size) {
734 connection->writeLoc = 0;
735 free(connection->write_buffer);
736 connection->write_buffer = NULL;
737 connection->write_buffer_size = 0;
738 connection->headersSent = 1;
739 }
740 return MHD_YES;
741 }
742 if (response->total_size <= connection->messagePos)
743 abort(); /* internal error */
744 if (response->crc != NULL)
745 pthread_mutex_lock(&response->mutex);
746
747 /* prepare send buffer */
748 if ( (response->data == NULL) ||
749 (response->data_start > connection->messagePos) ||
750 (response->data_start + response->data_size < connection->messagePos) ) {
751 if (response->data_size == 0) {
752 if (response->data != NULL)
753 free(response->data);
754 response->data = malloc(MHD_MAX_BUF_SIZE);
755 response->data_size = MHD_MAX_BUF_SIZE;
756 }
757 ret = response->crc(response->crc_cls,
758 connection->messagePos,
759 response->data,
760 MAX(MHD_MAX_BUF_SIZE,
761 response->data_size - connection->messagePos));
762 if (ret == -1) {
763 /* end of message, signal other side by closing! */
764 response->data_size = connection->messagePos;
765 CLOSE(connection->socket_fd);
766 connection->socket_fd = -1;
767 if (response->crc != NULL)
768 pthread_mutex_unlock(&response->mutex);
769 return MHD_YES;
770 }
771 response->data_start = connection->messagePos;
772 response->data_size = ret;
773 if (ret == 0) {
774 if (response->crc != NULL)
775 pthread_mutex_unlock(&response->mutex);
776 return MHD_YES;
777 }
778 }
779
780 /* transmit */
781 ret = SEND(connection->socket_fd,
782 &response->data[connection->messagePos - response->data_start],
783 response->data_size - (connection->messagePos - response->data_start),
784 0);
785 if (response->crc != NULL)
786 pthread_mutex_unlock(&response->mutex);
787 if (ret < 0) {
788 if (errno == EINTR)
789 return MHD_YES;
790 MHD_DLOG(connection->daemon,
791 "Failed to send data: %s\n",
792 STRERROR(errno));
793 CLOSE(connection->socket_fd);
794 connection->socket_fd = -1;
795 return MHD_YES;
796 }
797 connection->messagePos += ret;
798 if (connection->messagePos > response->data_size)
799 abort(); /* internal error */
800 if (connection->messagePos == response->data_size) {
801 if ( (connection->bodyReceived == 0) ||
802 (connection->headersReceived == 0) )
803 abort(); /* internal error */
804 MHD_destroy_response(response);
805 connection->responseCode = 0;
806 connection->response = NULL;
807 connection->headersReceived = 0;
808 connection->headersSent = 0;
809 connection->bodyReceived = 0;
810 connection->messagePos = 0;
811 free(connection->method);
812 connection->method = NULL;
813 free(connection->url);
814 connection->url = NULL;
815 free(connection->version);
816 connection->version = NULL;
817 free(connection->write_buffer);
818 connection->write_buffer = NULL;
819 connection->write_buffer_size = 0;
820 if (connection->read_close != 0) {
821 /* closed for reading => close for good! */
822 CLOSE(connection->socket_fd);
823 connection->socket_fd = -1;
824 }
825 }
826 return MHD_YES;
827}
828
829/* end of connection.c */
830
831