connection.c

Go to the documentation of this file.
00001 /*
00002      This file is part of libmicrohttpd
00003      (C) 2007, 2008 Daniel Pittman and Christian Grothoff
00004 
00005      This library is free software; you can redistribute it and/or
00006      modify it under the terms of the GNU Lesser General Public
00007      License as published by the Free Software Foundation; either
00008      version 2.1 of the License, or (at your option) any later version.
00009 
00010      This library is distributed in the hope that it will be useful,
00011      but WITHOUT ANY WARRANTY; without even the implied warranty of
00012      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013      Lesser General Public License for more details.
00014 
00015      You should have received a copy of the GNU Lesser General Public
00016      License along with this library; if not, write to the Free Software
00017      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019 */
00020 
00028 #include "internal.h"
00029 #include "connection.h"
00030 #include "memorypool.h"
00031 #include "response.h"
00032 #include "reason_phrase.h"
00033 
00034 #ifndef LINUX
00035 #ifndef MSG_NOSIGNAL
00036 #define MSG_NOSIGNAL 0
00037 #endif
00038 #endif
00039 
00040 
00044 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
00045 
00053 #if HAVE_MESSAGES
00054 #define REQUEST_TOO_BIG "<html><head><title>Request too big</title></head><body>Your HTTP header was too big for the memory constraints of this webserver.</body></html>"
00055 #else
00056 #define REQUEST_TOO_BIG ""
00057 #endif
00058 
00066 #if HAVE_MESSAGES
00067 #define REQUEST_LACKS_HOST "<html><head><title>&quot;Host:&quot; header required</title></head><body>In HTTP 1.1, requests must include a &quot;Host:&quot; header, and your HTTP 1.1 request lacked such a header.</body></html>"
00068 #else
00069 #define REQUEST_LACKS_HOST ""
00070 #endif
00071 
00079 #if HAVE_MESSAGES
00080 #define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
00081 #else
00082 #define REQUEST_MALFORMED ""
00083 #endif
00084 
00091 #if HAVE_MESSAGES
00092 #define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Some programmer needs to study the manual more carefully.</body></html>"
00093 #else
00094 #define INTERNAL_ERROR ""
00095 #endif
00096 
00097 #define EXTRA_CHECKS MHD_YES
00098 
00099 #if EXTRA_CHECKS
00100 #define EXTRA_CHECK(a) if (!(a)) abort();
00101 #else
00102 #define EXTRA_CHECK(a)
00103 #endif
00104 
00109 #define DEBUG_CLOSE MHD_NO
00110 
00114 #define DEBUG_SEND_DATA MHD_NO
00115 
00119 #define DEBUG_STATES MHD_NO
00120 
00129 int
00130 MHD_get_connection_values (struct MHD_Connection *connection,
00131                            enum MHD_ValueKind kind,
00132                            MHD_KeyValueIterator iterator, void *iterator_cls)
00133 {
00134   int ret;
00135   struct MHD_HTTP_Header *pos;
00136 
00137   if (connection == NULL)
00138     return -1;
00139   ret = 0;
00140   pos = connection->headers_received;
00141   while (pos != NULL)
00142     {
00143       if (0 != (pos->kind & kind))
00144         {
00145           ret++;
00146           if ((iterator != NULL) &&
00147               (MHD_YES != iterator (iterator_cls,
00148                                     kind, pos->header, pos->value)))
00149             return ret;
00150         }
00151       pos = pos->next;
00152     }
00153   return ret;
00154 }
00155 
00163 const char *
00164 MHD_lookup_connection_value (struct MHD_Connection *connection,
00165                              enum MHD_ValueKind kind, const char *key)
00166 {
00167   struct MHD_HTTP_Header *pos;
00168 
00169   if (connection == NULL)
00170     return NULL;
00171   pos = connection->headers_received;
00172   while (pos != NULL)
00173     {
00174       if ((0 != (pos->kind & kind)) && (0 == strcasecmp (key, pos->header)))
00175         return pos->value;
00176       pos = pos->next;
00177     }
00178   return NULL;
00179 }
00180 
00191 int
00192 MHD_queue_response (struct MHD_Connection *connection,
00193                     unsigned int status_code, struct MHD_Response *response)
00194 {
00195   if ((connection == NULL) ||
00196       (response == NULL) ||
00197       (connection->response != NULL) ||
00198       ((connection->state != MHD_CONNECTION_HEADERS_PROCESSED) &&
00199        (connection->state != MHD_CONNECTION_FOOTERS_RECEIVED)))
00200     return MHD_NO;
00201   MHD_increment_response_rc (response);
00202   connection->response = response;
00203   connection->responseCode = status_code;
00204   if ((connection->method != NULL) &&
00205       (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD)))
00206     {
00207       /* if this is a "HEAD" request, pretend that we
00208          have already sent the full message body */
00209       connection->response_write_position = response->total_size;
00210     }
00211   if ((response->total_size == -1) &&
00212       (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00213     connection->have_chunked_response = MHD_YES;
00214   else
00215     connection->have_chunked_response = MHD_NO;
00216   if (connection->state == MHD_CONNECTION_HEADERS_PROCESSED)
00217     {
00218       /* response was queued "early",
00219          refuse to read body / footers or further
00220          requests! */
00221       SHUTDOWN (connection->socket_fd, SHUT_RD);
00222       connection->read_closed = MHD_YES;
00223       connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00224     }
00225   return MHD_YES;
00226 }
00227 
00232 static int
00233 need_100_continue (struct MHD_Connection *connection)
00234 {
00235   const char *expect;
00236 
00237   return ((connection->response == NULL) &&
00238           (connection->version != NULL) &&
00239           (0 == strcasecmp (connection->version,
00240                             MHD_HTTP_VERSION_1_1)) &&
00241           (NULL != (expect = MHD_lookup_connection_value (connection,
00242                                                           MHD_HEADER_KIND,
00243                                                           MHD_HTTP_HEADER_EXPECT)))
00244           && (0 == strcasecmp (expect, "100-continue"))
00245           && (connection->continue_message_write_offset <
00246               strlen (HTTP_100_CONTINUE)));
00247 }
00248 
00253 static void
00254 connection_close_error (struct MHD_Connection *connection)
00255 {
00256   SHUTDOWN (connection->socket_fd, SHUT_RDWR);
00257   CLOSE (connection->socket_fd);
00258   connection->socket_fd = -1;
00259   connection->state = MHD_CONNECTION_CLOSED;
00260   if (connection->daemon->notify_completed != NULL)
00261     connection->daemon->notify_completed (connection->daemon->
00262                                           notify_completed_cls, connection,
00263                                           &connection->client_context,
00264                                           MHD_REQUEST_TERMINATED_WITH_ERROR);
00265 }
00266 
00276 static int
00277 try_ready_normal_body (struct MHD_Connection *connection)
00278 {
00279   int ret;
00280   struct MHD_Response *response;
00281 
00282   response = connection->response;
00283   if (response->crc == NULL)
00284     return MHD_YES;
00285   ret = response->crc (response->crc_cls,
00286                        connection->response_write_position,
00287                        response->data,
00288                        MIN (response->data_buffer_size,
00289                             response->total_size -
00290                             connection->response_write_position));
00291   if (ret == -1)
00292     {
00293       /* either error or http 1.0 transfer, close
00294          socket! */
00295 #if DEBUG_CLOSE
00296 #if HAVE_MESSAGES
00297       MHD_DLOG (connection->daemon, "Closing connection (end of response)\n");
00298 #endif
00299 #endif
00300       response->total_size = connection->response_write_position;
00301       connection_close_error (connection);
00302       return MHD_NO;
00303     }
00304   response->data_start = connection->response_write_position;
00305   response->data_size = ret;
00306   if (ret == 0)
00307     return MHD_NO;
00308   return MHD_YES;
00309 }
00310 
00320 static int
00321 try_ready_chunked_body (struct MHD_Connection *connection)
00322 {
00323   int ret;
00324   char *buf;
00325   struct MHD_Response *response;
00326   unsigned int size;
00327   char cbuf[9];
00328 
00329   response = connection->response;
00330   if (connection->write_buffer_size == 0)
00331     {
00332       size = connection->daemon->pool_size;
00333       do
00334         {
00335           size /= 2;
00336           if (size < 128)
00337             {
00338               /* not enough memory */
00339 #if DEBUG_CLOSE
00340 #if HAVE_MESSAGES
00341               MHD_DLOG (connection->daemon,
00342                         "Closing connection (out of memory)\n");
00343 #endif
00344 #endif
00345               connection_close_error (connection);
00346               return MHD_NO;
00347             }
00348           buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
00349         }
00350       while (buf == NULL);
00351       connection->write_buffer_size = size;
00352       connection->write_buffer = buf;
00353     }
00354 
00355   ret = response->crc (response->crc_cls,
00356                        connection->response_write_position,
00357                        &connection->write_buffer[8],
00358                        connection->write_buffer_size - 8 - 2);
00359   if (ret == -1)
00360     {
00361       /* end of message, signal other side! */
00362       strcpy (connection->write_buffer, "0\r\n");
00363       connection->write_buffer_append_offset = 3;
00364       connection->write_buffer_send_offset = 0;
00365       response->total_size = connection->response_write_position;
00366       return MHD_YES;
00367     }
00368   if (ret == 0)
00369     {
00370       connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
00371       return MHD_NO;
00372     }
00373   if (ret > 0xFFFFFF)
00374     ret = 0xFFFFFF;
00375   snprintf (cbuf, 8, "%X\r\n", ret);
00376   memcpy (&connection->write_buffer[8 - strlen (cbuf)], cbuf, strlen (cbuf));
00377   memcpy (&connection->write_buffer[8 + ret], "\r\n", 2);
00378   connection->response_write_position += ret;
00379   connection->write_buffer_send_offset = 8 - strlen (cbuf);
00380   connection->write_buffer_append_offset = 8 + ret + 2;
00381   return MHD_YES;
00382 }
00383 
00388 static void
00389 add_extra_headers (struct MHD_Connection *connection)
00390 {
00391   const char *have;
00392   char buf[128];
00393 
00394   connection->have_chunked_upload = MHD_NO;
00395   if (connection->response->total_size == -1)
00396     {
00397       have = MHD_get_response_header (connection->response,
00398                                       MHD_HTTP_HEADER_CONNECTION);
00399       if ((have == NULL) || (0 != strcasecmp (have, "close")))
00400         {
00401           if ((connection->version != NULL) &&
00402               (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00403             {
00404               connection->have_chunked_upload = MHD_YES;
00405               have = MHD_get_response_header (connection->response,
00406                                               MHD_HTTP_HEADER_TRANSFER_ENCODING);
00407               if (have == NULL)
00408                 MHD_add_response_header (connection->response,
00409                                          MHD_HTTP_HEADER_TRANSFER_ENCODING,
00410                                          "chunked");
00411             }
00412           else
00413             {
00414               MHD_add_response_header (connection->response,
00415                                        MHD_HTTP_HEADER_CONNECTION, "close");
00416             }
00417         }
00418     }
00419   else if (NULL == MHD_get_response_header (connection->response,
00420                                             MHD_HTTP_HEADER_CONTENT_LENGTH))
00421     {
00422       _REAL_SNPRINTF (buf,
00423                       128,
00424                       "%llu",
00425                       (unsigned long long) connection->response->total_size);
00426       MHD_add_response_header (connection->response,
00427                                MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
00428     }
00429 }
00430 
00436 static void
00437 get_date_string (char *date, unsigned int max)
00438 {
00439   static const char *days[] =
00440     { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00441   static const char *mons[] =
00442     { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
00443     "Nov", "Dec"
00444   };
00445   struct tm now;
00446   time_t t;
00447 
00448   time (&t);
00449   gmtime_r (&t, &now);
00450   snprintf (date,
00451             max - 1,
00452             "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
00453             days[now.tm_wday % 7],
00454             now.tm_mday,
00455             mons[now.tm_mon % 12],
00456             1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec);
00457 }
00458 
00463 static int
00464 try_grow_read_buffer (struct MHD_Connection *connection)
00465 {
00466   void *buf;
00467 
00468   buf = MHD_pool_reallocate (connection->pool,
00469                              connection->read_buffer,
00470                              connection->read_buffer_size,
00471                              connection->read_buffer_size * 2 +
00472                              MHD_BUF_INC_SIZE + 1);
00473   if (buf == NULL)
00474     return MHD_NO;
00475   /* we can actually grow the buffer, do it! */
00476   connection->read_buffer = buf;
00477   connection->read_buffer_size =
00478     connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00479   return MHD_YES;
00480 }
00481 
00488 static int
00489 build_header_response (struct MHD_Connection *connection)
00490 {
00491   size_t size;
00492   size_t off;
00493   struct MHD_HTTP_Header *pos;
00494   char code[128];
00495   char date[128];
00496   char *data;
00497   enum MHD_ValueKind kind;
00498   const char *reason_phrase;
00499 
00500   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00501     {
00502       add_extra_headers (connection);
00503       reason_phrase = MHD_get_reason_phrase_for (connection->responseCode);
00504       _REAL_SNPRINTF (code, 128, "%s %u %s\r\n", MHD_HTTP_VERSION_1_1,
00505                       connection->responseCode, reason_phrase);
00506       off = strlen (code);
00507       /* estimate size */
00508       size = off + 2;           /* extra \r\n at the end */
00509       kind = MHD_HEADER_KIND;
00510       if (NULL == MHD_get_response_header (connection->response,
00511                                            MHD_HTTP_HEADER_DATE))
00512         get_date_string (date, sizeof (date));
00513       else
00514         date[0] = '\0';
00515       size += strlen (date);
00516     }
00517   else
00518     {
00519       size = 2;
00520       kind = MHD_FOOTER_KIND;
00521       off = 0;
00522     }
00523   pos = connection->response->first_header;
00524   while (pos != NULL)
00525     {
00526       if (pos->kind == kind)
00527         size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */
00528       pos = pos->next;
00529     }
00530   /* produce data */
00531   data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
00532   if (data == NULL)
00533     {
00534 #if HAVE_MESSAGES
00535       MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
00536 #endif
00537       return MHD_NO;
00538     }
00539   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00540     {
00541       memcpy (data, code, off);
00542     }
00543   pos = connection->response->first_header;
00544   while (pos != NULL)
00545     {
00546       if (pos->kind == kind)
00547         {
00548           SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value);
00549           off += strlen (pos->header) + strlen (pos->value) + 4;
00550         }
00551       pos = pos->next;
00552     }
00553   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00554     {
00555       strcpy (&data[off], date);
00556       off += strlen (date);
00557     }
00558   sprintf (&data[off], "\r\n");
00559   off += 2;
00560   if (off != size)
00561     abort ();
00562   connection->write_buffer = data;
00563   connection->write_buffer_append_offset = size;
00564   connection->write_buffer_send_offset = 0;
00565   connection->write_buffer_size = size + 1;
00566   return MHD_YES;
00567 }
00568 
00576 static void
00577 transmit_error_response (struct MHD_Connection *connection,
00578                          unsigned int status_code, const char *message)
00579 {
00580   struct MHD_Response *response;
00581 
00582   /* die, header far too long to be reasonable */
00583   connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00584   connection->read_closed = MHD_YES;
00585 #if HAVE_MESSAGES
00586   MHD_DLOG (connection->daemon,
00587             "Error %u (`%s') processing request, closing connection.\n",
00588             status_code, message);
00589 #endif
00590   response = MHD_create_response_from_data (strlen (message),
00591                                             (void *) message, MHD_NO, MHD_NO);
00592   MHD_queue_response (connection, status_code, response);
00593   EXTRA_CHECK (connection->response != NULL);
00594   MHD_destroy_response (response);
00595   if (MHD_NO == build_header_response (connection))
00596     {
00597       /* oops - close! */
00598 #if HAVE_MESSAGES
00599       MHD_DLOG (connection->daemon,
00600                 "Closing connection (failed to create response header)\n");
00601 #endif
00602       connection->state = MHD_CONNECTION_CLOSED;
00603     }
00604   else
00605     {
00606       connection->state = MHD_CONNECTION_HEADERS_SENDING;
00607     }
00608 }
00609 
00614 static void
00615 do_fd_set (int fd, fd_set * set, int *max_fd)
00616 {
00617   FD_SET (fd, set);
00618   if (fd > *max_fd)
00619     *max_fd = fd;
00620 }
00621 
00627 int
00628 MHD_connection_get_fdset (struct MHD_Connection *connection,
00629                           fd_set * read_fd_set,
00630                           fd_set * write_fd_set,
00631                           fd_set * except_fd_set, int *max_fd)
00632 {
00633   int fd;
00634 
00635   if (connection->pool == NULL)
00636     connection->pool = MHD_pool_create (connection->daemon->pool_size);
00637   if (connection->pool == NULL)
00638     {
00639 #if HAVE_MESSAGES
00640       MHD_DLOG (connection->daemon, "Failed to create memory pool!\n");
00641 #endif
00642       connection_close_error (connection);
00643       return MHD_NO;
00644     }
00645   fd = connection->socket_fd;
00646   if (fd == -1)
00647     return MHD_YES;
00648   while (1)
00649     {
00650 #if DEBUG_STATES
00651       fprintf (stderr, "`%s' in state %u\n", __FUNCTION__, connection->state);
00652 #endif
00653       switch (connection->state)
00654         {
00655         case MHD_CONNECTION_INIT:
00656         case MHD_CONNECTION_URL_RECEIVED:
00657         case MHD_CONNECTION_HEADER_PART_RECEIVED:
00658           /* while reading headers, we always grow the
00659              read buffer if needed, no size-check required */
00660           if ((connection->read_closed) &&
00661               (connection->read_buffer_offset == 0))
00662             {
00663               connection->state = MHD_CONNECTION_CLOSED;
00664               continue;
00665             }
00666           if ((connection->read_buffer_offset == connection->read_buffer_size)
00667               && (MHD_NO == try_grow_read_buffer (connection)))
00668             {
00669               transmit_error_response (connection,
00670                                        (connection->url != NULL)
00671                                        ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00672                                        : MHD_HTTP_REQUEST_URI_TOO_LONG,
00673                                        REQUEST_TOO_BIG);
00674               continue;
00675             }
00676           if (MHD_NO == connection->read_closed)
00677             do_fd_set (fd, read_fd_set, max_fd);
00678           break;
00679         case MHD_CONNECTION_HEADERS_RECEIVED:
00680           /* we should never get here */
00681           EXTRA_CHECK (0);
00682           break;
00683         case MHD_CONNECTION_HEADERS_PROCESSED:
00684           EXTRA_CHECK (0);
00685           break;
00686         case MHD_CONNECTION_CONTINUE_SENDING:
00687           do_fd_set (fd, write_fd_set, max_fd);
00688           break;
00689         case MHD_CONNECTION_CONTINUE_SENT:
00690           if (connection->read_buffer_offset == connection->read_buffer_size)
00691             {
00692               if ((MHD_YES != try_grow_read_buffer (connection)) &&
00693                   (0 != (connection->daemon->options &
00694                          (MHD_USE_SELECT_INTERNALLY |
00695                           MHD_USE_THREAD_PER_CONNECTION))))
00696                 {
00697                   /* failed to grow the read buffer, and the
00698                      client which is supposed to handle the
00699                      received data in a *blocking* fashion
00700                      (in this mode) did not handle the data as
00701                      it was supposed to!
00702                      => we would either have to do busy-waiting
00703                      (on the client, which would likely fail),
00704                      or if we do nothing, we would just timeout
00705                      on the connection (if a timeout is even
00706                      set!).
00707                      Solution: we kill the connection with an error */
00708                   transmit_error_response (connection,
00709                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
00710                                            INTERNAL_ERROR);
00711                   continue;
00712                 }
00713             }
00714           if ((connection->read_buffer_offset < connection->read_buffer_size)
00715               && (MHD_NO == connection->read_closed))
00716             do_fd_set (fd, read_fd_set, max_fd);
00717           break;
00718         case MHD_CONNECTION_BODY_RECEIVED:
00719         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
00720           /* while reading footers, we always grow the
00721              read buffer if needed, no size-check required */
00722           if (MHD_YES == connection->read_closed)
00723             {
00724               connection->state = MHD_CONNECTION_CLOSED;
00725               continue;
00726             }
00727           do_fd_set (fd, read_fd_set, max_fd);
00728           /* transition to FOOTERS_RECEIVED
00729              happens in read handler */
00730           break;
00731         case MHD_CONNECTION_FOOTERS_RECEIVED:
00732           /* no socket action, wait for client
00733              to provide response */
00734           break;
00735         case MHD_CONNECTION_HEADERS_SENDING:
00736           /* headers in buffer, keep writing */
00737           do_fd_set (fd, write_fd_set, max_fd);
00738           break;
00739         case MHD_CONNECTION_HEADERS_SENT:
00740           EXTRA_CHECK (0);
00741           break;
00742         case MHD_CONNECTION_NORMAL_BODY_READY:
00743           do_fd_set (fd, write_fd_set, max_fd);
00744           break;
00745         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
00746           /* not ready, no socket action */
00747           break;
00748         case MHD_CONNECTION_CHUNKED_BODY_READY:
00749           do_fd_set (fd, write_fd_set, max_fd);
00750           break;
00751         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
00752           /* not ready, no socket action */
00753           break;
00754         case MHD_CONNECTION_BODY_SENT:
00755           EXTRA_CHECK (0);
00756           break;
00757         case MHD_CONNECTION_FOOTERS_SENDING:
00758           do_fd_set (fd, write_fd_set, max_fd);
00759           break;
00760         case MHD_CONNECTION_FOOTERS_SENT:
00761           EXTRA_CHECK (0);
00762           break;
00763         case MHD_CONNECTION_CLOSED:
00764           if (connection->socket_fd != -1)
00765             connection_close_error (connection);
00766           return MHD_YES;       /* do nothing, not even reading */
00767         default:
00768           EXTRA_CHECK (0);
00769         }
00770       break;
00771     }
00772   return MHD_YES;
00773 }
00774 
00783 static char *
00784 get_next_header_line (struct MHD_Connection *connection)
00785 {
00786   char *rbuf;
00787   size_t pos;
00788 
00789   if (connection->read_buffer_offset == 0)
00790     return NULL;
00791   pos = 0;
00792   rbuf = connection->read_buffer;
00793   while ((pos < connection->read_buffer_offset - 1) &&
00794          (rbuf[pos] != '\r') && (rbuf[pos] != '\n'))
00795     pos++;
00796   if (pos == connection->read_buffer_offset - 1)
00797     {
00798       /* not found, consider growing... */
00799       if (connection->read_buffer_offset == connection->read_buffer_size)
00800         {
00801           rbuf = MHD_pool_reallocate (connection->pool,
00802                                       connection->read_buffer,
00803                                       connection->read_buffer_size,
00804                                       connection->read_buffer_size * 2 +
00805                                       MHD_BUF_INC_SIZE);
00806           if (rbuf == NULL)
00807             {
00808               transmit_error_response (connection,
00809                                        (connection->url != NULL)
00810                                        ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00811                                        : MHD_HTTP_REQUEST_URI_TOO_LONG,
00812                                        REQUEST_TOO_BIG);
00813             }
00814           else
00815             {
00816               connection->read_buffer_size =
00817                 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00818               connection->read_buffer = rbuf;
00819             }
00820         }
00821       return NULL;
00822     }
00823   /* found, check if we have proper CRLF */
00824   if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n'))
00825     rbuf[pos++] = '\0';         /* skip both r and n */
00826   rbuf[pos++] = '\0';
00827   connection->read_buffer += pos;
00828   connection->read_buffer_size -= pos;
00829   connection->read_buffer_offset -= pos;
00830   return rbuf;
00831 }
00832 
00836 static int
00837 connection_add_header (struct MHD_Connection *connection,
00838                        char *key, char *value, enum MHD_ValueKind kind)
00839 {
00840   struct MHD_HTTP_Header *hdr;
00841 
00842   hdr = MHD_pool_allocate (connection->pool,
00843                            sizeof (struct MHD_HTTP_Header), MHD_YES);
00844   if (hdr == NULL)
00845     {
00846 #if HAVE_MESSAGES
00847       MHD_DLOG (connection->daemon,
00848                 "Not enough memory to allocate header record!\n");
00849 #endif
00850       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00851                                REQUEST_TOO_BIG);
00852       return MHD_NO;
00853     }
00854   hdr->next = connection->headers_received;
00855   hdr->header = key;
00856   hdr->value = value;
00857   hdr->kind = kind;
00858   connection->headers_received = hdr;
00859   return MHD_YES;
00860 }
00861 
00865 static int
00866 parse_arguments (enum MHD_ValueKind kind,
00867                  struct MHD_Connection *connection, char *args)
00868 {
00869   char *equals;
00870   char *amper;
00871 
00872   while (args != NULL)
00873     {
00874       equals = strstr (args, "=");
00875       if (equals == NULL)
00876         return MHD_NO;          /* invalid, ignore */
00877       equals[0] = '\0';
00878       equals++;
00879       amper = strstr (equals, "&");
00880       if (amper != NULL)
00881         {
00882           amper[0] = '\0';
00883           amper++;
00884         }
00885       MHD_http_unescape (args);
00886       MHD_http_unescape (equals);
00887       if (MHD_NO == connection_add_header (connection, args, equals, kind))
00888         return MHD_NO;
00889       args = amper;
00890     }
00891   return MHD_YES;
00892 }
00893 
00899 static int
00900 parse_cookie_header (struct MHD_Connection *connection)
00901 {
00902   const char *hdr;
00903   char *cpy;
00904   char *pos;
00905   char *semicolon;
00906   char *equals;
00907   int quotes;
00908 
00909   hdr = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "Cookie");
00910   if (hdr == NULL)
00911     return MHD_YES;
00912   cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
00913   if (cpy == NULL)
00914     {
00915 #if HAVE_MESSAGES
00916       MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
00917 #endif
00918       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00919                                REQUEST_TOO_BIG);
00920       return MHD_NO;
00921     }
00922   memcpy (cpy, hdr, strlen (hdr) + 1);
00923   pos = cpy;
00924   while (pos != NULL)
00925     {
00926       equals = strstr (pos, "=");
00927       if (equals == NULL)
00928         break;
00929       equals[0] = '\0';
00930       equals++;
00931       quotes = 0;
00932       semicolon = equals;
00933       while ((semicolon[0] != '\0') &&
00934              ((quotes != 0) ||
00935               ((semicolon[0] != ';') && (semicolon[0] != ','))))
00936         {
00937           if (semicolon[0] == '"')
00938             quotes = (quotes + 1) & 1;
00939           semicolon++;
00940         }
00941       if (semicolon[0] == '\0')
00942         semicolon = NULL;
00943       if (semicolon != NULL)
00944         {
00945           semicolon[0] = '\0';
00946           semicolon++;
00947         }
00948       /* remove quotes */
00949       if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
00950         {
00951           equals[strlen (equals) - 1] = '\0';
00952           equals++;
00953         }
00954       if (MHD_NO == connection_add_header (connection,
00955                                            pos, equals, MHD_COOKIE_KIND))
00956         return MHD_NO;
00957       pos = semicolon;
00958     }
00959   return MHD_YES;
00960 }
00961 
00969 static int
00970 parse_initial_message_line (struct MHD_Connection *connection, char *line)
00971 {
00972   char *uri;
00973   char *httpVersion;
00974   char *args;
00975 
00976   uri = strstr (line, " ");
00977   if (uri == NULL)
00978     return MHD_NO;              /* serious error */
00979   uri[0] = '\0';
00980   connection->method = line;
00981   uri++;
00982   while (uri[0] == ' ')
00983     uri++;
00984   httpVersion = strstr (uri, " ");
00985   if (httpVersion != NULL)
00986     {
00987       httpVersion[0] = '\0';
00988       httpVersion++;
00989     }
00990   args = strstr (uri, "?");
00991   if (args != NULL)
00992     {
00993       args[0] = '\0';
00994       args++;
00995       parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
00996     }
00997   connection->url = uri;
00998   if (httpVersion == NULL)
00999     connection->version = "";
01000   else
01001     connection->version = httpVersion;
01002   return MHD_YES;
01003 }
01004 
01010 static void
01011 call_connection_handler (struct MHD_Connection *connection)
01012 {
01013   unsigned int processed;
01014   unsigned int available;
01015   unsigned int used;
01016   int instant_retry;
01017   unsigned int i;
01018   int malformed;
01019 
01020   if (connection->response != NULL)
01021     return;                     /* already queued a response */
01022   do
01023     {
01024       instant_retry = MHD_NO;
01025       available = connection->read_buffer_offset;
01026       if ((connection->have_chunked_upload == MHD_YES) &&
01027           (connection->remaining_upload_size == -1))
01028         {
01029           if ((connection->current_chunk_offset ==
01030                connection->current_chunk_size)
01031               && (connection->current_chunk_offset != 0) && (available >= 2))
01032             {
01033               /* skip new line at the *end* of a chunk */
01034               i = 0;
01035               if ((connection->read_buffer[i] == '\r') ||
01036                   (connection->read_buffer[i] == '\n'))
01037                 i++;            /* skip 1st part of line feed */
01038               if ((connection->read_buffer[i] == '\r') ||
01039                   (connection->read_buffer[i] == '\n'))
01040                 i++;            /* skip 2nd part of line feed */
01041               if (i == 0)
01042                 {
01043                   /* malformed encoding */
01044 #if HAVE_MESSAGES
01045                   MHD_DLOG (connection->daemon,
01046                             "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01047 #endif
01048                   connection_close_error (connection);
01049                   return;
01050                 }
01051               connection->read_buffer_offset -= i;
01052               available -= i;
01053               memmove (connection->read_buffer,
01054                        &connection->read_buffer[i], available);
01055               connection->current_chunk_offset = 0;
01056               connection->current_chunk_size = 0;
01057             }
01058           if (connection->current_chunk_offset <
01059               connection->current_chunk_size)
01060             {
01061               /* we are in the middle of a chunk, give
01062                  as much as possible to the client (without
01063                  crossing chunk boundaries) */
01064               processed =
01065                 connection->current_chunk_size -
01066                 connection->current_chunk_offset;
01067               if (processed > available)
01068                 processed = available;
01069               available -= processed;
01070               if (available > 0)
01071                 instant_retry = MHD_YES;
01072             }
01073           else
01074             {
01075               /* we need to read chunk boundaries */
01076               i = 0;
01077               while (i < available)
01078                 {
01079                   if ((connection->read_buffer[i] == '\r') ||
01080                       (connection->read_buffer[i] == '\n'))
01081                     break;
01082                   i++;
01083                   if (i >= 6)
01084                     break;
01085                 }
01086               if (i >= available)
01087                 return;         /* need more data... */
01088               malformed = (i >= 6);
01089               if (!malformed)
01090                 {
01091                   connection->read_buffer[i] = '\0';
01092                   malformed = (1 != sscanf (connection->read_buffer,
01093                                             "%X",
01094                                             &connection->current_chunk_size))
01095                     && (1 !=
01096                         sscanf (connection->read_buffer, "%x",
01097                                 &connection->current_chunk_size));
01098                 }
01099               if (malformed)
01100                 {
01101                   /* malformed encoding */
01102 #if HAVE_MESSAGES
01103                   MHD_DLOG (connection->daemon,
01104                             "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01105 #endif
01106                   connection_close_error (connection);
01107                   return;
01108                 }
01109               i++;
01110               if ((connection->read_buffer[i] == '\r') ||
01111                   (connection->read_buffer[i] == '\n'))
01112                 i++;            /* skip 2nd part of line feed */
01113               memmove (connection->read_buffer,
01114                        &connection->read_buffer[i], available - i);
01115               connection->read_buffer_offset -= i;
01116               connection->current_chunk_offset = 0;
01117               instant_retry = MHD_YES;
01118               if (connection->current_chunk_size == 0)
01119                 {
01120                   connection->remaining_upload_size = 0;
01121                   return;
01122                 }
01123               continue;
01124             }
01125         }
01126       else
01127         {
01128           /* no chunked encoding, give all to the client */
01129           processed = available;
01130           available = 0;
01131         }
01132       used = processed;
01133       if (MHD_NO ==
01134           connection->daemon->default_handler (connection->daemon->
01135                                                default_handler_cls,
01136                                                connection, connection->url,
01137                                                connection->method,
01138                                                connection->version,
01139                                                connection->read_buffer,
01140                                                &processed,
01141                                                &connection->client_context))
01142         {
01143           /* serious internal error, close connection */
01144 #if HAVE_MESSAGES
01145           MHD_DLOG (connection->daemon,
01146                     "Internal application error, closing connection.\n");
01147 #endif
01148           connection_close_error (connection);
01149           return;
01150         }
01151       if (processed > used)
01152         abort ();               /* fatal client API violation! */
01153       if (processed != 0)
01154         instant_retry = MHD_NO; /* client did not process everything */
01155       used -= processed;
01156       if (connection->have_chunked_upload == MHD_YES)
01157         connection->current_chunk_offset += used;
01158       /* dh left "processed" bytes in buffer for next time... */
01159       if (used > 0)
01160         memmove (connection->read_buffer,
01161                  &connection->read_buffer[used], processed + available);
01162       if (connection->remaining_upload_size != -1)
01163         connection->remaining_upload_size -= used;
01164       connection->read_buffer_offset = processed + available;
01165     }
01166   while (instant_retry == MHD_YES);
01167 }
01168 
01177 static int
01178 do_read (struct MHD_Connection *connection)
01179 {
01180   int bytes_read;
01181 
01182   if (connection->read_buffer_size == connection->read_buffer_offset)
01183     return MHD_NO;
01184   bytes_read = RECV (connection->socket_fd,
01185                      &connection->read_buffer[connection->read_buffer_offset],
01186                      connection->read_buffer_size -
01187                      connection->read_buffer_offset, MSG_NOSIGNAL);
01188   if (bytes_read < 0)
01189     {
01190       if (errno == EINTR)
01191         return MHD_NO;
01192 #if HAVE_MESSAGES
01193       MHD_DLOG (connection->daemon,
01194                 "Failed to receive data: %s\n", STRERROR (errno));
01195 #endif
01196       connection_close_error (connection);
01197       return MHD_YES;
01198     }
01199   if (bytes_read == 0)
01200     {
01201       /* other side closed connection */
01202       connection->read_closed = MHD_YES;
01203       SHUTDOWN (connection->socket_fd, SHUT_RD);
01204       return MHD_NO;
01205     }
01206   connection->read_buffer_offset += bytes_read;
01207   return MHD_YES;
01208 }
01209 
01215 static int
01216 process_header_line (struct MHD_Connection *connection, char *line)
01217 {
01218   char *colon;
01219 
01220   /* line should be normal header line, find colon */
01221   colon = strstr (line, ":");
01222   if (colon == NULL)
01223     {
01224       /* error in header line, die hard */
01225 #if HAVE_MESSAGES
01226       MHD_DLOG (connection->daemon,
01227                 "Received malformed line (no colon), closing connection.\n");
01228 #endif
01229       connection->state = MHD_CONNECTION_CLOSED;
01230       return MHD_NO;
01231     }
01232   /* zero-terminate header */
01233   colon[0] = '\0';
01234   colon++;                      /* advance to value */
01235   while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
01236     colon++;
01237   /* we do the actual adding of the connection
01238      header at the beginning of the while
01239      loop since we need to be able to inspect
01240      the *next* header line (in case it starts
01241      with a space...) */
01242   connection->last = line;
01243   connection->colon = colon;
01244   return MHD_YES;
01245 }
01246 
01256 static int
01257 process_broken_line (struct MHD_Connection *connection,
01258                      char *line, enum MHD_ValueKind kind)
01259 {
01260   char *last;
01261   char *tmp;
01262 
01263   last = connection->last;
01264   if ((line[0] == ' ') || (line[0] == '\t'))
01265     {
01266       /* value was continued on the next line, see
01267          http://www.jmarshall.com/easy/http/ */
01268       last = MHD_pool_reallocate (connection->pool,
01269                                   last,
01270                                   strlen (last) + 1,
01271                                   strlen (line) + strlen (last) + 1);
01272       if (last == NULL)
01273         {
01274           transmit_error_response (connection,
01275                                    MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01276                                    REQUEST_TOO_BIG);
01277           return MHD_NO;
01278         }
01279       tmp = line;
01280       while ((tmp[0] == ' ') || (tmp[0] == '\t'))
01281         tmp++;                  /* skip whitespace at start of 2nd line */
01282       strcat (last, tmp);
01283       connection->last = last;
01284       return MHD_YES;           /* possibly more than 2 lines... */
01285     }
01286   EXTRA_CHECK ((last != NULL) && (connection->colon != NULL));
01287   if ((MHD_NO == connection_add_header (connection,
01288                                         last, connection->colon, kind)))
01289     {
01290       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01291                                REQUEST_TOO_BIG);
01292       return MHD_NO;
01293     }
01294   /* we still have the current line to deal with... */
01295   if (strlen (line) != 0)
01296     {
01297       if (MHD_NO == process_header_line (connection, line))
01298         {
01299           transmit_error_response (connection,
01300                                    MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED);
01301           return MHD_NO;
01302         }
01303     }
01304   return MHD_YES;
01305 }
01306 
01312 static void
01313 parse_connection_headers (struct MHD_Connection *connection)
01314 {
01315   const char *clen;
01316   unsigned long long cval;
01317   struct MHD_Response *response;
01318 
01319   parse_cookie_header (connection);
01320   if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
01321       && (NULL != connection->version)
01322       && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
01323       && (NULL ==
01324           MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
01325                                        MHD_HTTP_HEADER_HOST)))
01326     {
01327       /* die, http 1.1 request without host and we are pedantic */
01328       connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01329       connection->read_closed = MHD_YES;
01330 #if HAVE_MESSAGES
01331       MHD_DLOG (connection->daemon,
01332                 "Received `%s' request without `%s' header.\n",
01333                 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
01334 #endif
01335       response =
01336         MHD_create_response_from_data (strlen (REQUEST_LACKS_HOST),
01337                                        REQUEST_LACKS_HOST, MHD_NO, MHD_NO);
01338       MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
01339       MHD_destroy_response (response);
01340       return;
01341     }
01342 
01343   clen = MHD_lookup_connection_value (connection,
01344                                       MHD_HEADER_KIND,
01345                                       MHD_HTTP_HEADER_CONTENT_LENGTH);
01346   if (clen != NULL)
01347     {
01348       if (1 != sscanf (clen, "%llu", &cval))
01349         {
01350 #if HAVE_MESSAGES
01351           MHD_DLOG (connection->daemon,
01352                     "Failed to parse `%s' header `%s', closing connection.\n",
01353                     MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
01354 #endif
01355           connection->state = MHD_CONNECTION_CLOSED;
01356           return;
01357         }
01358       connection->remaining_upload_size = cval;
01359     }
01360   else
01361     {
01362       if (NULL == MHD_lookup_connection_value (connection,
01363                                                MHD_HEADER_KIND,
01364                                                MHD_HTTP_HEADER_TRANSFER_ENCODING))
01365         {
01366           /* this request does not have a body */
01367           connection->remaining_upload_size = 0;
01368         }
01369       else
01370         {
01371           connection->remaining_upload_size = -1;       /* unknown size */
01372           if (0 ==
01373               strcasecmp (MHD_lookup_connection_value
01374                           (connection, MHD_HEADER_KIND,
01375                            MHD_HTTP_HEADER_TRANSFER_ENCODING), "chunked"))
01376             connection->have_chunked_upload = MHD_YES;
01377         }
01378     }
01379 }
01380 
01390 int
01391 MHD_connection_handle_read (struct MHD_Connection *connection)
01392 {
01393   connection->last_activity = time (NULL);
01394   if (connection->state == MHD_CONNECTION_CLOSED)
01395     return MHD_NO;
01396   if (MHD_NO == do_read (connection))
01397     return MHD_YES;
01398   while (1)
01399     {
01400 #if DEBUG_STATES
01401       fprintf (stderr, "`%s' in state %u\n", __FUNCTION__, connection->state);
01402 #endif
01403       switch (connection->state)
01404         {
01405         case MHD_CONNECTION_INIT:
01406         case MHD_CONNECTION_URL_RECEIVED:
01407         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01408         case MHD_CONNECTION_HEADERS_RECEIVED:
01409         case MHD_CONNECTION_HEADERS_PROCESSED:
01410         case MHD_CONNECTION_CONTINUE_SENDING:
01411         case MHD_CONNECTION_CONTINUE_SENT:
01412         case MHD_CONNECTION_BODY_RECEIVED:
01413         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01414           /* nothing to do but default action */
01415           if (MHD_YES == connection->read_closed)
01416             {
01417               connection->state = MHD_CONNECTION_CLOSED;
01418               continue;
01419             }
01420           break;
01421         case MHD_CONNECTION_CLOSED:
01422           if (connection->socket_fd != -1)
01423             connection_close_error (connection);
01424           return MHD_NO;
01425         default:
01426           /* shrink read buffer to how much is actually used */
01427           MHD_pool_reallocate (connection->pool,
01428                                connection->read_buffer,
01429                                connection->read_buffer_size + 1,
01430                                connection->read_buffer_offset);
01431           break;
01432         }
01433       break;
01434     }
01435   return MHD_YES;
01436 }
01437 
01445 static int
01446 do_write (struct MHD_Connection *connection)
01447 {
01448   int ret;
01449 
01450   ret = SEND (connection->socket_fd,
01451               &connection->write_buffer[connection->
01452                                         write_buffer_send_offset],
01453               connection->write_buffer_append_offset -
01454               connection->write_buffer_send_offset, MSG_NOSIGNAL);
01455   if (ret < 0)
01456     {
01457       if (errno == EINTR)
01458         return MHD_NO;
01459 #if HAVE_MESSAGES
01460       MHD_DLOG (connection->daemon,
01461                 "Failed to send data: %s\n", STRERROR (errno));
01462 #endif
01463       connection_close_error (connection);
01464       return MHD_YES;
01465     }
01466 #if DEBUG_SEND_DATA
01467   fprintf (stderr,
01468            "Sent HEADER response: `%.*s'\n",
01469            ret,
01470            &connection->write_buffer[connection->write_buffer_send_offset]);
01471 #endif
01472   connection->write_buffer_send_offset += ret;
01473   return MHD_YES;
01474 }
01475 
01481 static int
01482 check_write_done (struct MHD_Connection *connection,
01483                   enum MHD_CONNECTION_STATE next_state)
01484 {
01485   if (connection->write_buffer_append_offset !=
01486       connection->write_buffer_send_offset)
01487     return MHD_NO;
01488   connection->write_buffer_append_offset = 0;
01489   connection->write_buffer_send_offset = 0;
01490   connection->state = next_state;
01491   MHD_pool_reallocate (connection->pool,
01492                        connection->write_buffer,
01493                        connection->write_buffer_size, 0);
01494   connection->write_buffer = NULL;
01495   connection->write_buffer_size = 0;
01496   return MHD_YES;
01497 }
01498 
01508 int
01509 MHD_connection_handle_write (struct MHD_Connection *connection)
01510 {
01511   struct MHD_Response *response;
01512   int ret;
01513 
01514   connection->last_activity = time (NULL);
01515   while (1)
01516     {
01517 #if DEBUG_STATES
01518       fprintf (stderr, "`%s' in state %u\n", __FUNCTION__, connection->state);
01519 #endif
01520       switch (connection->state)
01521         {
01522         case MHD_CONNECTION_INIT:
01523         case MHD_CONNECTION_URL_RECEIVED:
01524         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01525         case MHD_CONNECTION_HEADERS_RECEIVED:
01526           EXTRA_CHECK (0);
01527           break;
01528         case MHD_CONNECTION_HEADERS_PROCESSED:
01529           break;
01530         case MHD_CONNECTION_CONTINUE_SENDING:
01531           ret = SEND (connection->socket_fd,
01532                       &HTTP_100_CONTINUE[connection->
01533                                          continue_message_write_offset],
01534                       strlen (HTTP_100_CONTINUE) -
01535                       connection->continue_message_write_offset,
01536                       MSG_NOSIGNAL);
01537           if (ret < 0)
01538             {
01539               if (errno == EINTR)
01540                 break;
01541 #if HAVE_MESSAGES
01542               MHD_DLOG (connection->daemon,
01543                         "Failed to send data: %s\n", STRERROR (errno));
01544 #endif
01545               connection_close_error (connection);
01546               return MHD_NO;
01547             }
01548 #if DEBUG_SEND_DATA
01549           fprintf (stderr,
01550                    "Sent 100 continue response: `%.*s'\n",
01551                    ret,
01552                    &HTTP_100_CONTINUE[connection->
01553                                       continue_message_write_offset]);
01554 #endif
01555           connection->continue_message_write_offset += ret;
01556           break;
01557         case MHD_CONNECTION_CONTINUE_SENT:
01558         case MHD_CONNECTION_BODY_RECEIVED:
01559         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01560         case MHD_CONNECTION_FOOTERS_RECEIVED:
01561           EXTRA_CHECK (0);
01562           break;
01563         case MHD_CONNECTION_HEADERS_SENDING:
01564           do_write (connection);
01565           check_write_done (connection, MHD_CONNECTION_HEADERS_SENT);
01566           break;
01567         case MHD_CONNECTION_HEADERS_SENT:
01568           EXTRA_CHECK (0);
01569           break;
01570         case MHD_CONNECTION_NORMAL_BODY_READY:
01571           response = connection->response;
01572           if (response->crc != NULL)
01573             pthread_mutex_lock (&response->mutex);
01574           if (MHD_YES != try_ready_normal_body (connection))
01575             {
01576               if (response->crc != NULL)
01577                 pthread_mutex_unlock (&response->mutex);
01578               connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
01579               break;
01580             }
01581           ret = SEND (connection->socket_fd,
01582                       &response->data[connection->response_write_position -
01583                                       response->data_start],
01584                       response->data_size -
01585                       (connection->response_write_position -
01586                        response->data_start), MSG_NOSIGNAL);
01587 #if DEBUG_SEND_DATA
01588           if (ret > 0)
01589             fprintf (stderr,
01590                      "Sent DATA response: `%.*s'\n",
01591                      ret,
01592                      &response->data[connection->response_write_position -
01593                                      response->data_start]);
01594 #endif
01595           if (response->crc != NULL)
01596             pthread_mutex_unlock (&response->mutex);
01597           if (ret < 0)
01598             {
01599               if (errno == EINTR)
01600                 return MHD_YES;
01601 #if HAVE_MESSAGES
01602               MHD_DLOG (connection->daemon,
01603                         "Failed to send data: %s\n", STRERROR (errno));
01604 #endif
01605               connection_close_error (connection);
01606               return MHD_NO;
01607             }
01608           connection->response_write_position += ret;
01609           if (connection->response_write_position ==
01610               connection->response->total_size)
01611             connection->state = MHD_CONNECTION_FOOTERS_SENT;    /* have no footers... */
01612           break;
01613         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01614           EXTRA_CHECK (0);
01615           break;
01616         case MHD_CONNECTION_CHUNKED_BODY_READY:
01617           do_write (connection);
01618           check_write_done (connection,
01619                             (connection->response->total_size ==
01620                              connection->
01621                              response_write_position) ?
01622                             MHD_CONNECTION_BODY_SENT :
01623                             MHD_CONNECTION_CHUNKED_BODY_UNREADY);
01624           break;
01625         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
01626         case MHD_CONNECTION_BODY_SENT:
01627           EXTRA_CHECK (0);
01628           break;
01629         case MHD_CONNECTION_FOOTERS_SENDING:
01630           do_write (connection);
01631           check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT);
01632           break;
01633         case MHD_CONNECTION_FOOTERS_SENT:
01634           EXTRA_CHECK (0);
01635           break;
01636         case MHD_CONNECTION_CLOSED:
01637           if (connection->socket_fd != -1)
01638             connection_close_error (connection);
01639           return MHD_NO;
01640         }
01641       break;
01642     }
01643   return MHD_YES;
01644 }
01645 
01655 int
01656 MHD_connection_handle_idle (struct MHD_Connection *connection)
01657 {
01658   unsigned int timeout;
01659   const char *end;
01660   char *line;
01661 
01662   while (1)
01663     {
01664 #if DEBUG_STATES
01665       fprintf (stderr, "`%s' in state %u\n", __FUNCTION__, connection->state);
01666 #endif
01667       switch (connection->state)
01668         {
01669         case MHD_CONNECTION_INIT:
01670           line = get_next_header_line (connection);
01671           if (line == NULL)
01672             {
01673               if (connection->state != MHD_CONNECTION_INIT)
01674                 continue;
01675               if (connection->read_closed)
01676                 {
01677                   connection->state = MHD_CONNECTION_CLOSED;
01678                   continue;
01679                 }
01680               break;
01681             }
01682           if (MHD_NO == parse_initial_message_line (connection, line))
01683             connection->state = MHD_CONNECTION_CLOSED;
01684           else
01685             connection->state = MHD_CONNECTION_URL_RECEIVED;
01686           continue;
01687         case MHD_CONNECTION_URL_RECEIVED:
01688           line = get_next_header_line (connection);
01689           if (line == NULL)
01690             {
01691               if (connection->state != MHD_CONNECTION_URL_RECEIVED)
01692                 continue;
01693               if (connection->read_closed)
01694                 {
01695                   connection->state = MHD_CONNECTION_CLOSED;
01696                   continue;
01697                 }
01698               break;
01699             }
01700           if (strlen (line) == 0)
01701             {
01702               connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01703               continue;
01704             }
01705           if (MHD_NO == process_header_line (connection, line))
01706             {
01707               transmit_error_response (connection,
01708                                        MHD_HTTP_BAD_REQUEST,
01709                                        REQUEST_MALFORMED);
01710               break;
01711             }
01712           connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
01713           continue;
01714         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01715           line = get_next_header_line (connection);
01716           if (line == NULL)
01717             {
01718               if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
01719                 continue;
01720               if (connection->read_closed)
01721                 {
01722                   connection->state = MHD_CONNECTION_CLOSED;
01723                   continue;
01724                 }
01725               break;
01726             }
01727           if (MHD_NO ==
01728               process_broken_line (connection, line, MHD_HEADER_KIND))
01729             continue;
01730           if (strlen (line) == 0)
01731             {
01732               connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01733               continue;
01734             }
01735           continue;
01736         case MHD_CONNECTION_HEADERS_RECEIVED:
01737           parse_connection_headers (connection);
01738           if (connection->state == MHD_CONNECTION_CLOSED)
01739             continue;
01740           connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
01741           continue;
01742         case MHD_CONNECTION_HEADERS_PROCESSED:
01743           call_connection_handler (connection); /* first call */
01744           if (connection->state == MHD_CONNECTION_CLOSED)
01745             continue;
01746           if (need_100_continue (connection))
01747             {
01748               connection->state = MHD_CONNECTION_CONTINUE_SENDING;
01749               break;
01750             }
01751           connection->state = (connection->remaining_upload_size == 0)
01752             ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
01753           continue;
01754         case MHD_CONNECTION_CONTINUE_SENDING:
01755           if (connection->continue_message_write_offset ==
01756               strlen (HTTP_100_CONTINUE))
01757             {
01758               connection->state = MHD_CONNECTION_CONTINUE_SENT;
01759               continue;
01760             }
01761           break;
01762         case MHD_CONNECTION_CONTINUE_SENT:
01763           if (connection->read_buffer_offset != 0)
01764             {
01765               call_connection_handler (connection);     /* loop call */
01766               if (connection->state == MHD_CONNECTION_CLOSED)
01767                 continue;
01768             }
01769           if ((connection->remaining_upload_size == 0) ||
01770               ((connection->remaining_upload_size == -1) &&
01771                (connection->read_buffer_offset == 0) &&
01772                (MHD_YES == connection->read_closed)))
01773             {
01774               if ((MHD_YES == connection->have_chunked_upload) &&
01775                   (MHD_NO == connection->read_closed))
01776                 connection->state = MHD_CONNECTION_BODY_RECEIVED;
01777               else
01778                 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01779               continue;
01780             }
01781           break;
01782         case MHD_CONNECTION_BODY_RECEIVED:
01783           line = get_next_header_line (connection);
01784           if (line == NULL)
01785             {
01786               if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
01787                 continue;
01788               if (connection->read_closed)
01789                 {
01790                   connection->state = MHD_CONNECTION_CLOSED;
01791                   continue;
01792                 }
01793               break;
01794             }
01795           if (strlen (line) == 0)
01796             {
01797               connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01798               continue;
01799             }
01800           if (MHD_NO == process_header_line (connection, line))
01801             {
01802               transmit_error_response (connection,
01803                                        MHD_HTTP_BAD_REQUEST,
01804                                        REQUEST_MALFORMED);
01805               break;
01806             }
01807           connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
01808           continue;
01809         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01810           line = get_next_header_line (connection);
01811           if (line == NULL)
01812             {
01813               if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
01814                 continue;
01815               if (connection->read_closed)
01816                 {
01817                   connection->state = MHD_CONNECTION_CLOSED;
01818                   continue;
01819                 }
01820               break;
01821             }
01822           if (MHD_NO ==
01823               process_broken_line (connection, line, MHD_FOOTER_KIND))
01824             continue;
01825           if (strlen (line) == 0)
01826             {
01827               connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01828               continue;
01829             }
01830           continue;
01831         case MHD_CONNECTION_FOOTERS_RECEIVED:
01832           call_connection_handler (connection); /* "final" call */
01833           if (connection->state == MHD_CONNECTION_CLOSED)
01834             continue;
01835           if (connection->response == NULL)
01836             break;              /* try again next time */
01837           if (MHD_NO == build_header_response (connection))
01838             {
01839               /* oops - close! */
01840 #if HAVE_MESSAGES
01841               MHD_DLOG (connection->daemon,
01842                         "Closing connection (failed to create response header)\n");
01843 #endif
01844               connection->state = MHD_CONNECTION_CLOSED;
01845               continue;
01846             }
01847           connection->state = MHD_CONNECTION_HEADERS_SENDING;
01848           break;
01849         case MHD_CONNECTION_HEADERS_SENDING:
01850           /* no default action */
01851           break;
01852         case MHD_CONNECTION_HEADERS_SENT:
01853           if (connection->have_chunked_upload)
01854             connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
01855           else
01856             connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
01857           continue;
01858         case MHD_CONNECTION_NORMAL_BODY_READY:
01859           /* nothing to do here */
01860           break;
01861         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01862           if (connection->response->crc != NULL)
01863             pthread_mutex_lock (&connection->response->mutex);
01864           if (MHD_YES == try_ready_normal_body (connection))
01865             {
01866               if (connection->response->crc != NULL)
01867                 pthread_mutex_unlock (&connection->response->mutex);
01868               connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
01869               break;
01870             }
01871           if (connection->response->crc != NULL)
01872             pthread_mutex_unlock (&connection->response->mutex);
01873           /* not ready, no socket action */
01874           break;
01875         case MHD_CONNECTION_CHUNKED_BODY_READY:
01876           /* nothing to do here */
01877           break;
01878         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
01879           if (connection->response->crc != NULL)
01880             pthread_mutex_lock (&connection->response->mutex);
01881           if (MHD_YES == try_ready_chunked_body (connection))
01882             {
01883               if (connection->response->crc != NULL)
01884                 pthread_mutex_unlock (&connection->response->mutex);
01885               connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
01886               continue;
01887             }
01888           if (connection->response->crc != NULL)
01889             pthread_mutex_unlock (&connection->response->mutex);
01890           break;
01891         case MHD_CONNECTION_BODY_SENT:
01892           build_header_response (connection);
01893           if (connection->write_buffer_send_offset ==
01894               connection->write_buffer_append_offset)
01895             connection->state = MHD_CONNECTION_FOOTERS_SENT;
01896           else
01897             connection->state = MHD_CONNECTION_FOOTERS_SENDING;
01898           continue;
01899         case MHD_CONNECTION_FOOTERS_SENDING:
01900           /* no default action */
01901           break;
01902         case MHD_CONNECTION_FOOTERS_SENT:
01903           MHD_destroy_response (connection->response);
01904           if (connection->daemon->notify_completed != NULL)
01905             connection->daemon->notify_completed (connection->daemon->
01906                                                   notify_completed_cls,
01907                                                   connection,
01908                                                   &connection->client_context,
01909                                                   MHD_REQUEST_TERMINATED_COMPLETED_OK);
01910           end = MHD_lookup_connection_value (connection,
01911                                              MHD_HEADER_KIND,
01912                                              MHD_HTTP_HEADER_CONNECTION);
01913           connection->client_context = NULL;
01914           connection->continue_message_write_offset = 0;
01915           connection->responseCode = 0;
01916           connection->response = NULL;
01917           connection->headers_received = NULL;
01918           connection->response_write_position = 0;
01919           connection->have_chunked_upload = MHD_NO;
01920           connection->method = NULL;
01921           connection->url = NULL;
01922           connection->write_buffer = NULL;
01923           connection->write_buffer_size = 0;
01924           connection->write_buffer_send_offset = 0;
01925           connection->write_buffer_append_offset = 0;
01926           if ((end != NULL) && (0 == strcasecmp (end, "close")))
01927             {
01928               connection->read_closed = MHD_YES;
01929               connection->read_buffer_offset = 0;
01930             }
01931           if (((MHD_YES == connection->read_closed) &&
01932                (0 == connection->read_buffer_offset)) ||
01933               (connection->version == NULL) ||
01934               (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
01935             {
01936               /* http 1.0, version-less requests cannot be pipelined */
01937               connection->state = MHD_CONNECTION_CLOSED;
01938               MHD_pool_destroy (connection->pool);
01939               connection->pool = NULL;
01940               connection->read_buffer = NULL;
01941               connection->read_buffer_size = 0;
01942               connection->read_buffer_offset = 0;
01943             }
01944           else
01945             {
01946               connection->version = NULL;
01947               connection->state = MHD_CONNECTION_INIT;
01948               connection->read_buffer
01949                 = MHD_pool_reset (connection->pool,
01950                                   connection->read_buffer,
01951                                   connection->read_buffer_size);
01952             }
01953           continue;
01954         case MHD_CONNECTION_CLOSED:
01955           if (connection->socket_fd != -1)
01956             connection_close_error (connection);
01957           break;
01958         default:
01959           EXTRA_CHECK (0);
01960           break;
01961         }
01962       break;
01963     }
01964   timeout = connection->daemon->connection_timeout;
01965   if ((connection->socket_fd != -1) &&
01966       (timeout != 0) && (time (NULL) - timeout > connection->last_activity))
01967     {
01968       connection_close_error (connection);
01969       return MHD_NO;
01970     }
01971   return MHD_YES;
01972 
01973 }
01974 
01975 /* end of connection.c */

Generated on Mon Mar 30 10:40:41 2009 for GNU libmicrohttpd by  doxygen 1.5.7.1