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 
00037 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
00038 
00046 #if HAVE_MESSAGES
00047 #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>"
00048 #else
00049 #define REQUEST_TOO_BIG ""
00050 #endif
00051 
00059 #if HAVE_MESSAGES
00060 #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>"
00061 #else
00062 #define REQUEST_LACKS_HOST ""
00063 #endif
00064 
00072 #if HAVE_MESSAGES
00073 #define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
00074 #else
00075 #define REQUEST_MALFORMED ""
00076 #endif
00077 
00084 #if HAVE_MESSAGES
00085 #define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Some programmer needs to study the manual more carefully.</body></html>"
00086 #else
00087 #define INTERNAL_ERROR ""
00088 #endif
00089 
00094 #define DEBUG_CLOSE MHD_NO
00095 
00099 #define DEBUG_SEND_DATA MHD_NO
00100 
00109 int
00110 MHD_get_connection_values (struct MHD_Connection *connection,
00111                            enum MHD_ValueKind kind,
00112                            MHD_KeyValueIterator iterator, void *iterator_cls)
00113 {
00114   int ret;
00115   struct MHD_HTTP_Header *pos;
00116 
00117   if (connection == NULL)
00118     return -1;
00119   ret = 0;
00120   pos = connection->headers_received;
00121   while (pos != NULL)
00122     {
00123       if (0 != (pos->kind & kind))
00124         {
00125           ret++;
00126           if ((iterator != NULL) &&
00127               (MHD_YES != iterator (iterator_cls,
00128                                     kind, pos->header, pos->value)))
00129             return ret;
00130         }
00131       pos = pos->next;
00132     }
00133   return ret;
00134 }
00135 
00165 int
00166 MHD_set_connection_value (struct MHD_Connection *connection,
00167                           enum MHD_ValueKind kind,
00168                           const char *key, const char *value)
00169 {
00170   struct MHD_HTTP_Header *pos;
00171 
00172   pos = MHD_pool_allocate (connection->pool,
00173                            sizeof (struct MHD_HTTP_Header), MHD_NO);
00174   if (pos == NULL)
00175     return MHD_NO;
00176   pos->header = (char *) key;
00177   pos->value = (char *) value;
00178   pos->kind = kind;
00179   pos->next = connection->headers_received;
00180   connection->headers_received = pos;
00181   return MHD_YES;
00182 }
00183 
00191 const char *
00192 MHD_lookup_connection_value (struct MHD_Connection *connection,
00193                              enum MHD_ValueKind kind, const char *key)
00194 {
00195   struct MHD_HTTP_Header *pos;
00196 
00197   if (connection == NULL)
00198     return NULL;
00199   pos = connection->headers_received;
00200   while (pos != NULL)
00201     {
00202       if ((0 != (pos->kind & kind)) && (0 == strcasecmp (key, pos->header)))
00203         return pos->value;
00204       pos = pos->next;
00205     }
00206   return NULL;
00207 }
00208 
00219 int
00220 MHD_queue_response (struct MHD_Connection *connection,
00221                     unsigned int status_code, struct MHD_Response *response)
00222 {
00223   if ((connection == NULL) ||
00224       (response == NULL) ||
00225       (connection->response != NULL) ||
00226       ((connection->state != MHD_CONNECTION_HEADERS_PROCESSED) &&
00227        (connection->state != MHD_CONNECTION_FOOTERS_RECEIVED)))
00228     return MHD_NO;
00229   MHD_increment_response_rc (response);
00230   connection->response = response;
00231   connection->responseCode = status_code;
00232   if ((connection->method != NULL) &&
00233       (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD)))
00234     {
00235       /* if this is a "HEAD" request, pretend that we
00236          have already sent the full message body */
00237       connection->response_write_position = response->total_size;
00238     }
00239   if ((response->total_size == -1) &&
00240       (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00241     connection->have_chunked_response = MHD_YES;
00242   else
00243     connection->have_chunked_response = MHD_NO;
00244   if (connection->state == MHD_CONNECTION_HEADERS_PROCESSED)
00245     {
00246       /* response was queued "early",
00247          refuse to read body / footers or further
00248          requests! */
00249       SHUTDOWN (connection->socket_fd, SHUT_RD);
00250       connection->read_closed = MHD_YES;
00251       connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00252     }
00253   return MHD_YES;
00254 }
00255 
00260 static int
00261 need_100_continue (struct MHD_Connection *connection)
00262 {
00263   const char *expect;
00264 
00265   return ((connection->response == NULL) &&
00266           (connection->version != NULL) &&
00267           (0 == strcasecmp (connection->version,
00268                             MHD_HTTP_VERSION_1_1)) &&
00269           (NULL != (expect = MHD_lookup_connection_value (connection,
00270                                                           MHD_HEADER_KIND,
00271                                                           MHD_HTTP_HEADER_EXPECT)))
00272           && (0 == strcasecmp (expect, "100-continue"))
00273           && (connection->continue_message_write_offset <
00274               strlen (HTTP_100_CONTINUE)));
00275 }
00276 
00281 void 
00282 MHD_connection_close (struct MHD_Connection *connection,
00283                       enum MHD_RequestTerminationCode termination_code)
00284 {
00285 
00286   SHUTDOWN (connection->socket_fd, SHUT_RDWR);
00287   CLOSE (connection->socket_fd);
00288   connection->socket_fd = -1;
00289   connection->state = MHD_CONNECTION_CLOSED;
00290   if (connection->daemon->notify_completed != NULL)
00291     connection->daemon->notify_completed (connection->
00292                                           daemon->notify_completed_cls,
00293                                           connection,
00294                                           &connection->client_context,
00295                                           termination_code);
00296 }
00297 
00302 static void
00303 connection_close_error (struct MHD_Connection *connection)
00304 {
00305   MHD_connection_close(connection,
00306                        MHD_REQUEST_TERMINATED_WITH_ERROR);
00307 }
00308 
00318 static int
00319 try_ready_normal_body (struct MHD_Connection *connection)
00320 {
00321   int ret;
00322   struct MHD_Response *response;
00323 
00324   response = connection->response;
00325   if (response->crc == NULL)
00326     return MHD_YES;
00327   ret = response->crc (response->crc_cls,
00328                        connection->response_write_position,
00329                        response->data,
00330                        MHD_MIN (response->data_buffer_size,
00331                                 response->total_size -
00332                                 connection->response_write_position));
00333   if ((ret == 0) &&
00334       (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY)))
00335     abort ();                   /* serious client API violation */
00336   if (ret == -1)
00337     {
00338       /* either error or http 1.0 transfer, close
00339          socket! */
00340 #if DEBUG_CLOSE
00341 #if HAVE_MESSAGES
00342       MHD_DLOG (connection->daemon, "Closing connection (end of response)\n");
00343 #endif
00344 #endif
00345       response->total_size = connection->response_write_position;
00346       connection_close_error (connection);
00347       return MHD_NO;
00348     }
00349   response->data_start = connection->response_write_position;
00350   response->data_size = ret;
00351   if (ret == 0)
00352     return MHD_NO;
00353   return MHD_YES;
00354 }
00355 
00365 static int
00366 try_ready_chunked_body (struct MHD_Connection *connection)
00367 {
00368   int ret;
00369   char *buf;
00370   struct MHD_Response *response;
00371   unsigned int size;
00372   char cbuf[10];                /* 10: max strlen of "%x\r\n" */
00373   int cblen;
00374 
00375   response = connection->response;
00376   if (connection->write_buffer_size == 0)
00377     {
00378       size = connection->daemon->pool_size;
00379       do
00380         {
00381           size /= 2;
00382           if (size < 128)
00383             {
00384               /* not enough memory */
00385 #if DEBUG_CLOSE
00386 #if HAVE_MESSAGES
00387               MHD_DLOG (connection->daemon,
00388                         "Closing connection (out of memory)\n");
00389 #endif
00390 #endif
00391               connection_close_error (connection);
00392               return MHD_NO;
00393             }
00394           buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
00395         }
00396       while (buf == NULL);
00397       connection->write_buffer_size = size;
00398       connection->write_buffer = buf;
00399     }
00400 
00401   ret = response->crc (response->crc_cls,
00402                        connection->response_write_position,
00403                        &connection->write_buffer[sizeof (cbuf)],
00404                        connection->write_buffer_size - sizeof (cbuf) - 2);
00405   if (ret == -1)
00406     {
00407       /* end of message, signal other side! */
00408       strcpy (connection->write_buffer, "0\r\n");
00409       connection->write_buffer_append_offset = 3;
00410       connection->write_buffer_send_offset = 0;
00411       response->total_size = connection->response_write_position;
00412       return MHD_YES;
00413     }
00414   if (ret == 0)
00415     {
00416       connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
00417       return MHD_NO;
00418     }
00419   if (ret > 0xFFFFFF)
00420     ret = 0xFFFFFF;
00421   SPRINTF (cbuf, "%X\r\n", ret);
00422   cblen = strlen (cbuf);
00423   EXTRA_CHECK (cblen <= sizeof (cbuf));
00424   memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
00425   memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
00426   connection->response_write_position += ret;
00427   connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
00428   connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
00429   return MHD_YES;
00430 }
00431 
00436 static void
00437 add_extra_headers (struct MHD_Connection *connection)
00438 {
00439   const char *have;
00440   char buf[128];
00441 
00442   connection->have_chunked_upload = MHD_NO;
00443   if (connection->response->total_size == -1)
00444     {
00445       have = MHD_get_response_header (connection->response,
00446                                       MHD_HTTP_HEADER_CONNECTION);
00447       if ((have == NULL) || (0 != strcasecmp (have, "close")))
00448         {
00449           if ((connection->version != NULL) &&
00450               (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00451             {
00452               connection->have_chunked_upload = MHD_YES;
00453               have = MHD_get_response_header (connection->response,
00454                                               MHD_HTTP_HEADER_TRANSFER_ENCODING);
00455               if (have == NULL)
00456                 MHD_add_response_header (connection->response,
00457                                          MHD_HTTP_HEADER_TRANSFER_ENCODING,
00458                                          "chunked");
00459             }
00460           else
00461             {
00462               MHD_add_response_header (connection->response,
00463                                        MHD_HTTP_HEADER_CONNECTION, "close");
00464             }
00465         }
00466     }
00467   else if (NULL == MHD_get_response_header (connection->response,
00468                                             MHD_HTTP_HEADER_CONTENT_LENGTH))
00469     {
00470       SPRINTF (buf,
00471                "%llu", (unsigned long long) connection->response->total_size);
00472       MHD_add_response_header (connection->response,
00473                                MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
00474     }
00475 }
00476 
00483 static void
00484 get_date_string (char *date)
00485 {
00486   static const char *days[] =
00487     { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00488   static const char *mons[] =
00489     { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
00490     "Nov", "Dec"
00491   };
00492   struct tm now;
00493   time_t t;
00494 
00495   time (&t);
00496   gmtime_r (&t, &now);
00497   SPRINTF (date,
00498            "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
00499            days[now.tm_wday % 7],
00500            now.tm_mday,
00501            mons[now.tm_mon % 12],
00502            1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec);
00503 }
00504 
00510 static int
00511 try_grow_read_buffer (struct MHD_Connection *connection)
00512 {
00513   void *buf;
00514 
00515   buf = MHD_pool_reallocate (connection->pool,
00516                              connection->read_buffer,
00517                              connection->read_buffer_size,
00518                              connection->read_buffer_size * 2 +
00519                              MHD_BUF_INC_SIZE + 1);
00520   if (buf == NULL)
00521     return MHD_NO;
00522   /* we can actually grow the buffer, do it! */
00523   connection->read_buffer = buf;
00524   connection->read_buffer_size =
00525     connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00526   return MHD_YES;
00527 }
00528 
00535 static int
00536 build_header_response (struct MHD_Connection *connection)
00537 {
00538   size_t size;
00539   size_t off;
00540   struct MHD_HTTP_Header *pos;
00541   char code[256];
00542   char date[128];
00543   char *data;
00544   enum MHD_ValueKind kind;
00545   const char *reason_phrase;
00546 
00547   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00548     {
00549       add_extra_headers (connection);
00550       reason_phrase = MHD_get_reason_phrase_for (connection->responseCode);
00551       SPRINTF (code,
00552                "%s %u %s\r\n",
00553                MHD_HTTP_VERSION_1_1, connection->responseCode, reason_phrase);
00554       off = strlen (code);
00555       /* estimate size */
00556       size = off + 2;           /* extra \r\n at the end */
00557       kind = MHD_HEADER_KIND;
00558       if (NULL == MHD_get_response_header (connection->response,
00559                                            MHD_HTTP_HEADER_DATE))
00560         get_date_string (date);
00561       else
00562         date[0] = '\0';
00563       size += strlen (date);
00564     }
00565   else
00566     {
00567       size = 2;
00568       kind = MHD_FOOTER_KIND;
00569       off = 0;
00570     }
00571   pos = connection->response->first_header;
00572   while (pos != NULL)
00573     {
00574       if (pos->kind == kind)
00575         size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */
00576       pos = pos->next;
00577     }
00578   /* produce data */
00579   data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
00580   if (data == NULL)
00581     {
00582 #if HAVE_MESSAGES
00583       MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
00584 #endif
00585       return MHD_NO;
00586     }
00587   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00588     {
00589       memcpy (data, code, off);
00590     }
00591   pos = connection->response->first_header;
00592   while (pos != NULL)
00593     {
00594       if (pos->kind == kind)
00595         off += SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value);
00596       pos = pos->next;
00597     }
00598   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00599     {
00600       strcpy (&data[off], date);
00601       off += strlen (date);
00602     }
00603   memcpy (&data[off], "\r\n", 2);
00604   off += 2;
00605   if (off != size)
00606     abort ();
00607   connection->write_buffer = data;
00608   connection->write_buffer_append_offset = size;
00609   connection->write_buffer_send_offset = 0;
00610   connection->write_buffer_size = size + 1;
00611   return MHD_YES;
00612 }
00613 
00621 static void
00622 transmit_error_response (struct MHD_Connection *connection,
00623                          unsigned int status_code, const char *message)
00624 {
00625   struct MHD_Response *response;
00626 
00627   /* die, header far too long to be reasonable */
00628   connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00629   connection->read_closed = MHD_YES;
00630 #if HAVE_MESSAGES
00631   MHD_DLOG (connection->daemon,
00632             "Error %u (`%s') processing request, closing connection.\n",
00633             status_code, message);
00634 #endif
00635   response = MHD_create_response_from_data (strlen (message),
00636                                             (void *) message, MHD_NO, MHD_NO);
00637   MHD_queue_response (connection, status_code, response);
00638   EXTRA_CHECK (connection->response != NULL);
00639   MHD_destroy_response (response);
00640   if (MHD_NO == build_header_response (connection))
00641     {
00642       /* oops - close! */
00643 #if HAVE_MESSAGES
00644       MHD_DLOG (connection->daemon,
00645                 "Closing connection (failed to create response header)\n");
00646 #endif
00647       connection->state = MHD_CONNECTION_CLOSED;
00648     }
00649   else
00650     {
00651       connection->state = MHD_CONNECTION_HEADERS_SENDING;
00652     }
00653 }
00654 
00659 static void
00660 do_fd_set (int fd, fd_set * set, int *max_fd)
00661 {
00662   FD_SET (fd, set);
00663   if (fd > *max_fd)
00664     *max_fd = fd;
00665 }
00666 
00672 int
00673 MHD_connection_get_fdset (struct MHD_Connection *connection,
00674                           fd_set * read_fd_set,
00675                           fd_set * write_fd_set,
00676                           fd_set * except_fd_set, int *max_fd)
00677 {
00678   int fd;
00679 
00680   if (connection->pool == NULL)
00681     connection->pool = MHD_pool_create (connection->daemon->pool_size);
00682   if (connection->pool == NULL)
00683     {
00684 #if HAVE_MESSAGES
00685       MHD_DLOG (connection->daemon, "Failed to create memory pool!\n");
00686 #endif
00687       connection_close_error (connection);
00688       return MHD_NO;
00689     }
00690   fd = connection->socket_fd;
00691   if (fd == -1)
00692     return MHD_YES;
00693   while (1)
00694     {
00695 #if DEBUG_STATES
00696       MHD_DLOG (connection->daemon, "%s: state: %s\n",
00697                 __FUNCTION__, MHD_state_to_string (connection->state));
00698 #endif
00699       switch (connection->state)
00700         {
00701         case MHD_CONNECTION_INIT:
00702         case MHD_CONNECTION_URL_RECEIVED:
00703         case MHD_CONNECTION_HEADER_PART_RECEIVED:
00704 #if HTTPS_SUPPORT
00705         case MHD_TLS_CONNECTION_INIT:
00706 #endif
00707           /* while reading headers, we always grow the
00708              read buffer if needed, no size-check required */
00709           if ((connection->read_closed) &&
00710               (connection->read_buffer_offset == 0))
00711             {
00712               connection->state = MHD_CONNECTION_CLOSED;
00713               continue;
00714             }
00715           if ((connection->read_buffer_offset == connection->read_buffer_size)
00716               && (MHD_NO == try_grow_read_buffer (connection)))
00717             {
00718               transmit_error_response (connection,
00719                                        (connection->url != NULL)
00720                                        ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00721                                        : MHD_HTTP_REQUEST_URI_TOO_LONG,
00722                                        REQUEST_TOO_BIG);
00723               continue;
00724             }
00725           if (MHD_NO == connection->read_closed)
00726             do_fd_set (fd, read_fd_set, max_fd);
00727           break;
00728         case MHD_CONNECTION_HEADERS_RECEIVED:
00729           /* we should never get here */
00730           EXTRA_CHECK (0);
00731           break;
00732         case MHD_CONNECTION_HEADERS_PROCESSED:
00733           EXTRA_CHECK (0);
00734           break;
00735         case MHD_CONNECTION_CONTINUE_SENDING:
00736           do_fd_set (fd, write_fd_set, max_fd);
00737           break;
00738         case MHD_CONNECTION_CONTINUE_SENT:
00739           if (connection->read_buffer_offset == connection->read_buffer_size)
00740             {
00741               if ((MHD_YES != try_grow_read_buffer (connection)) &&
00742                   (0 != (connection->daemon->options &
00743                          (MHD_USE_SELECT_INTERNALLY |
00744                           MHD_USE_THREAD_PER_CONNECTION))))
00745                 {
00746                   /* failed to grow the read buffer, and the
00747                      client which is supposed to handle the
00748                      received data in a *blocking* fashion
00749                      (in this mode) did not handle the data as
00750                      it was supposed to!
00751                      => we would either have to do busy-waiting
00752                      (on the client, which would likely fail),
00753                      or if we do nothing, we would just timeout
00754                      on the connection (if a timeout is even
00755                      set!).
00756                      Solution: we kill the connection with an error */
00757                   transmit_error_response (connection,
00758                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
00759                                            INTERNAL_ERROR);
00760                   continue;
00761                 }
00762             }
00763           if ((connection->read_buffer_offset < connection->read_buffer_size)
00764               && (MHD_NO == connection->read_closed))
00765             do_fd_set (fd, read_fd_set, max_fd);
00766           break;
00767         case MHD_CONNECTION_BODY_RECEIVED:
00768         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
00769           /* while reading footers, we always grow the
00770              read buffer if needed, no size-check required */
00771           if (MHD_YES == connection->read_closed)
00772             {
00773               connection->state = MHD_CONNECTION_CLOSED;
00774               continue;
00775             }
00776           do_fd_set (fd, read_fd_set, max_fd);
00777           /* transition to FOOTERS_RECEIVED
00778              happens in read handler */
00779           break;
00780         case MHD_CONNECTION_FOOTERS_RECEIVED:
00781           /* no socket action, wait for client
00782              to provide response */
00783           break;
00784         case MHD_CONNECTION_HEADERS_SENDING:
00785           /* headers in buffer, keep writing */
00786           do_fd_set (fd, write_fd_set, max_fd);
00787           break;
00788         case MHD_CONNECTION_HEADERS_SENT:
00789           EXTRA_CHECK (0);
00790           break;
00791         case MHD_CONNECTION_NORMAL_BODY_READY:
00792           do_fd_set (fd, write_fd_set, max_fd);
00793           break;
00794         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
00795           /* not ready, no socket action */
00796           break;
00797         case MHD_CONNECTION_CHUNKED_BODY_READY:
00798           do_fd_set (fd, write_fd_set, max_fd);
00799           break;
00800         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
00801           /* not ready, no socket action */
00802           break;
00803         case MHD_CONNECTION_BODY_SENT:
00804           EXTRA_CHECK (0);
00805           break;
00806         case MHD_CONNECTION_FOOTERS_SENDING:
00807           do_fd_set (fd, write_fd_set, max_fd);
00808           break;
00809         case MHD_CONNECTION_FOOTERS_SENT:
00810           EXTRA_CHECK (0);
00811           break;
00812         case MHD_CONNECTION_CLOSED:
00813           if (connection->socket_fd != -1)
00814             connection_close_error (connection);
00815           return MHD_YES;       /* do nothing, not even reading */
00816 
00817         default:
00818           EXTRA_CHECK (0);
00819         }
00820       break;
00821     }
00822   return MHD_YES;
00823 }
00824 
00833 static char *
00834 get_next_header_line (struct MHD_Connection *connection)
00835 {
00836   char *rbuf;
00837   size_t pos;
00838 
00839   if (connection->read_buffer_offset == 0)
00840     return NULL;
00841   pos = 0;
00842   rbuf = connection->read_buffer;
00843   while ((pos < connection->read_buffer_offset - 1) &&
00844          (rbuf[pos] != '\r') && (rbuf[pos] != '\n'))
00845     pos++;
00846   if (pos == connection->read_buffer_offset - 1)
00847     {
00848       /* not found, consider growing... */
00849       if (connection->read_buffer_offset == connection->read_buffer_size)
00850         {
00851           rbuf = MHD_pool_reallocate (connection->pool,
00852                                       connection->read_buffer,
00853                                       connection->read_buffer_size,
00854                                       connection->read_buffer_size * 2 +
00855                                       MHD_BUF_INC_SIZE);
00856           if (rbuf == NULL)
00857             {
00858               transmit_error_response (connection,
00859                                        (connection->url != NULL)
00860                                        ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00861                                        : MHD_HTTP_REQUEST_URI_TOO_LONG,
00862                                        REQUEST_TOO_BIG);
00863             }
00864           else
00865             {
00866               connection->read_buffer_size =
00867                 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00868               connection->read_buffer = rbuf;
00869             }
00870         }
00871       return NULL;
00872     }
00873   /* found, check if we have proper CRLF */
00874   if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n'))
00875     rbuf[pos++] = '\0';         /* skip both r and n */
00876   rbuf[pos++] = '\0';
00877   connection->read_buffer += pos;
00878   connection->read_buffer_size -= pos;
00879   connection->read_buffer_offset -= pos;
00880   return rbuf;
00881 }
00882 
00886 static int
00887 connection_add_header (struct MHD_Connection *connection,
00888                        char *key, char *value, enum MHD_ValueKind kind)
00889 {
00890   struct MHD_HTTP_Header *hdr;
00891 
00892   hdr = MHD_pool_allocate (connection->pool,
00893                            sizeof (struct MHD_HTTP_Header), MHD_YES);
00894   if (hdr == NULL)
00895     {
00896 #if HAVE_MESSAGES
00897       MHD_DLOG (connection->daemon,
00898                 "Not enough memory to allocate header record!\n");
00899 #endif
00900       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00901                                REQUEST_TOO_BIG);
00902       return MHD_NO;
00903     }
00904   hdr->next = connection->headers_received;
00905   hdr->header = key;
00906   hdr->value = value;
00907   hdr->kind = kind;
00908   connection->headers_received = hdr;
00909   return MHD_YES;
00910 }
00911 
00915 static int
00916 parse_arguments (enum MHD_ValueKind kind,
00917                  struct MHD_Connection *connection, char *args)
00918 {
00919   char *equals;
00920   char *amper;
00921 
00922   while (args != NULL)
00923     {
00924       equals = strstr (args, "=");
00925       if (equals == NULL)
00926         return MHD_NO;          /* invalid, ignore */
00927       equals[0] = '\0';
00928       equals++;
00929       amper = strstr (equals, "&");
00930       if (amper != NULL)
00931         {
00932           amper[0] = '\0';
00933           amper++;
00934         }
00935       MHD_http_unescape (args);
00936       MHD_http_unescape (equals);
00937       if (MHD_NO == connection_add_header (connection, args, equals, kind))
00938         return MHD_NO;
00939       args = amper;
00940     }
00941   return MHD_YES;
00942 }
00943 
00949 static int
00950 parse_cookie_header (struct MHD_Connection *connection)
00951 {
00952   const char *hdr;
00953   char *cpy;
00954   char *pos;
00955   char *semicolon;
00956   char *equals;
00957   int quotes;
00958 
00959   hdr = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "Cookie");
00960   if (hdr == NULL)
00961     return MHD_YES;
00962   cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
00963   if (cpy == NULL)
00964     {
00965 #if HAVE_MESSAGES
00966       MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
00967 #endif
00968       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00969                                REQUEST_TOO_BIG);
00970       return MHD_NO;
00971     }
00972   memcpy (cpy, hdr, strlen (hdr) + 1);
00973   pos = cpy;
00974   while (pos != NULL)
00975     {
00976       equals = strstr (pos, "=");
00977       if (equals == NULL)
00978         break;
00979       equals[0] = '\0';
00980       equals++;
00981       quotes = 0;
00982       semicolon = equals;
00983       while ((semicolon[0] != '\0') &&
00984              ((quotes != 0) ||
00985               ((semicolon[0] != ';') && (semicolon[0] != ','))))
00986         {
00987           if (semicolon[0] == '"')
00988             quotes = (quotes + 1) & 1;
00989           semicolon++;
00990         }
00991       if (semicolon[0] == '\0')
00992         semicolon = NULL;
00993       if (semicolon != NULL)
00994         {
00995           semicolon[0] = '\0';
00996           semicolon++;
00997         }
00998       /* remove quotes */
00999       if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
01000         {
01001           equals[strlen (equals) - 1] = '\0';
01002           equals++;
01003         }
01004       if (MHD_NO == connection_add_header (connection,
01005                                            pos, equals, MHD_COOKIE_KIND))
01006         return MHD_NO;
01007       pos = semicolon;
01008     }
01009   return MHD_YES;
01010 }
01011 
01019 static int
01020 parse_initial_message_line (struct MHD_Connection *connection, char *line)
01021 {
01022   char *uri;
01023   char *httpVersion;
01024   char *args;
01025 
01026   uri = strstr (line, " ");
01027   if (uri == NULL)
01028     return MHD_NO;              /* serious error */
01029   uri[0] = '\0';
01030   connection->method = line;
01031   uri++;
01032   while (uri[0] == ' ')
01033     uri++;
01034   httpVersion = strstr (uri, " ");
01035   if (httpVersion != NULL)
01036     {
01037       httpVersion[0] = '\0';
01038       httpVersion++;
01039     }
01040   if (connection->daemon->uri_log_callback != NULL)
01041     connection->client_context 
01042       = connection->daemon->uri_log_callback(connection->daemon->uri_log_callback_cls,
01043                                              uri);
01044   args = strstr (uri, "?");
01045   if (args != NULL)
01046     {
01047       args[0] = '\0';
01048       args++;
01049       parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
01050     }
01051   MHD_http_unescape (uri);
01052   connection->url = uri;
01053   if (httpVersion == NULL)
01054     connection->version = "";
01055   else
01056     connection->version = httpVersion;
01057   return MHD_YES;
01058 }
01059 
01065 static void
01066 call_connection_handler (struct MHD_Connection *connection)
01067 {
01068   unsigned int processed;
01069   unsigned int available;
01070   unsigned int used;
01071   int instant_retry;
01072   unsigned int i;
01073   int malformed;
01074   char *buffer_head;
01075 
01076   if (connection->response != NULL)
01077     return;                     /* already queued a response */
01078 
01079   buffer_head = connection->read_buffer;
01080   available = connection->read_buffer_offset;
01081   do
01082     {
01083       instant_retry = MHD_NO;
01084       if ((connection->have_chunked_upload == MHD_YES) &&
01085           (connection->remaining_upload_size == -1))
01086         {
01087           if ((connection->current_chunk_offset ==
01088                connection->current_chunk_size)
01089               && (connection->current_chunk_offset != 0) && (available >= 2))
01090             {
01091               /* skip new line at the *end* of a chunk */
01092               i = 0;
01093               if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01094                 i++;            /* skip 1st part of line feed */
01095               if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01096                 i++;            /* skip 2nd part of line feed */
01097               if (i == 0)
01098                 {
01099                   /* malformed encoding */
01100 #if HAVE_MESSAGES
01101                   MHD_DLOG (connection->daemon,
01102                             "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01103 #endif
01104                   connection_close_error (connection);
01105                   return;
01106                 }
01107               available -= i;
01108               buffer_head += i;
01109               connection->current_chunk_offset = 0;
01110               connection->current_chunk_size = 0;
01111             }
01112           if (connection->current_chunk_offset <
01113               connection->current_chunk_size)
01114             {
01115               /* we are in the middle of a chunk, give
01116                  as much as possible to the client (without
01117                  crossing chunk boundaries) */
01118               processed =
01119                 connection->current_chunk_size -
01120                 connection->current_chunk_offset;
01121               if (processed > available)
01122                 processed = available;
01123               if (available > processed)
01124                 instant_retry = MHD_YES;
01125             }
01126           else
01127             {
01128               /* we need to read chunk boundaries */
01129               i = 0;
01130               while (i < available)
01131                 {
01132                   if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01133                     break;
01134                   i++;
01135                   if (i >= 6)
01136                     break;
01137                 }
01138               /* take '\n' into account; if '\n'
01139                  is the unavailable character, we
01140                  will need to wait until we have it
01141                  before going further */
01142               if ((i + 1 >= available) &&
01143                   !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
01144                 break;          /* need more data... */
01145               malformed = (i >= 6);
01146               if (!malformed)
01147                 {
01148                   buffer_head[i] = '\0';
01149                   malformed =
01150                     (1 != SSCANF (buffer_head, "%X",
01151                                   &connection->current_chunk_size)) &&
01152                     (1 != SSCANF (buffer_head, "%x",
01153                                   &connection->current_chunk_size));
01154                 }
01155               if (malformed)
01156                 {
01157                   /* malformed encoding */
01158 #if HAVE_MESSAGES
01159                   MHD_DLOG (connection->daemon,
01160                             "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01161 #endif
01162                   connection_close_error (connection);
01163                   return;
01164                 }
01165               i++;
01166               if ((i < available) &&
01167                   ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
01168                 i++;            /* skip 2nd part of line feed */
01169 
01170               buffer_head += i;
01171               available -= i;
01172               connection->current_chunk_offset = 0;
01173 
01174               if (available > 0)
01175                 instant_retry = MHD_YES;