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->daemon->
00292                                           notify_completed_cls, connection,
00293                                           &connection->client_context,
00294                                           termination_code);
00295 }
00296 
00301 static void
00302 connection_close_error (struct MHD_Connection *connection)
00303 {
00304   MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR);
00305 }
00306 
00316 static int
00317 try_ready_normal_body (struct MHD_Connection *connection)
00318 {
00319   int ret;
00320   struct MHD_Response *response;
00321 
00322   response = connection->response;
00323   if (response->crc == NULL)
00324     return MHD_YES;
00325   ret = response->crc (response->crc_cls,
00326                        connection->response_write_position,
00327                        response->data,
00328                        MHD_MIN (response->data_buffer_size,
00329                                 response->total_size -
00330                                 connection->response_write_position));
00331   if ((ret == 0) &&
00332       (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY)))
00333     abort ();                   /* serious client API violation */
00334   if (ret == -1)
00335     {
00336       /* either error or http 1.0 transfer, close
00337          socket! */
00338 #if DEBUG_CLOSE
00339 #if HAVE_MESSAGES
00340       MHD_DLOG (connection->daemon, "Closing connection (end of response)\n");
00341 #endif
00342 #endif
00343       response->total_size = connection->response_write_position;
00344       connection_close_error (connection);
00345       return MHD_NO;
00346     }
00347   response->data_start = connection->response_write_position;
00348   response->data_size = ret;
00349   if (ret == 0)
00350     return MHD_NO;
00351   return MHD_YES;
00352 }
00353 
00363 static int
00364 try_ready_chunked_body (struct MHD_Connection *connection)
00365 {
00366   int ret;
00367   char *buf;
00368   struct MHD_Response *response;
00369   size_t size;
00370   char cbuf[10];                /* 10: max strlen of "%x\r\n" */
00371   int cblen;
00372 
00373   response = connection->response;
00374   if (connection->write_buffer_size == 0)
00375     {
00376       size = connection->daemon->pool_size;
00377       do
00378         {
00379           size /= 2;
00380           if (size < 128)
00381             {
00382               /* not enough memory */
00383 #if DEBUG_CLOSE
00384 #if HAVE_MESSAGES
00385               MHD_DLOG (connection->daemon,
00386                         "Closing connection (out of memory)\n");
00387 #endif
00388 #endif
00389               connection_close_error (connection);
00390               return MHD_NO;
00391             }
00392           buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
00393         }
00394       while (buf == NULL);
00395       connection->write_buffer_size = size;
00396       connection->write_buffer = buf;
00397     }
00398 
00399   ret = response->crc (response->crc_cls,
00400                        connection->response_write_position,
00401                        &connection->write_buffer[sizeof (cbuf)],
00402                        connection->write_buffer_size - sizeof (cbuf) - 2);
00403   if (ret == -1)
00404     {
00405       /* end of message, signal other side! */
00406       strcpy (connection->write_buffer, "0\r\n");
00407       connection->write_buffer_append_offset = 3;
00408       connection->write_buffer_send_offset = 0;
00409       response->total_size = connection->response_write_position;
00410       return MHD_YES;
00411     }
00412   if (ret == 0)
00413     {
00414       connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
00415       return MHD_NO;
00416     }
00417   if (ret > 0xFFFFFF)
00418     ret = 0xFFFFFF;
00419   SPRINTF (cbuf, "%X\r\n", ret);
00420   cblen = strlen (cbuf);
00421   EXTRA_CHECK (cblen <= sizeof (cbuf));
00422   memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
00423   memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
00424   connection->response_write_position += ret;
00425   connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
00426   connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
00427   return MHD_YES;
00428 }
00429 
00434 static void
00435 add_extra_headers (struct MHD_Connection *connection)
00436 {
00437   const char *have;
00438   char buf[128];
00439 
00440   connection->have_chunked_upload = MHD_NO;
00441   if (connection->response->total_size == -1)
00442     {
00443       have = MHD_get_response_header (connection->response,
00444                                       MHD_HTTP_HEADER_CONNECTION);
00445       if ((have == NULL) || (0 != strcasecmp (have, "close")))
00446         {
00447           if ((connection->version != NULL) &&
00448               (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00449             {
00450               connection->have_chunked_upload = MHD_YES;
00451               have = MHD_get_response_header (connection->response,
00452                                               MHD_HTTP_HEADER_TRANSFER_ENCODING);
00453               if (have == NULL)
00454                 MHD_add_response_header (connection->response,
00455                                          MHD_HTTP_HEADER_TRANSFER_ENCODING,
00456                                          "chunked");
00457             }
00458           else
00459             {
00460               MHD_add_response_header (connection->response,
00461                                        MHD_HTTP_HEADER_CONNECTION, "close");
00462             }
00463         }
00464     }
00465   else if (NULL == MHD_get_response_header (connection->response,
00466                                             MHD_HTTP_HEADER_CONTENT_LENGTH))
00467     {
00468       SPRINTF (buf,
00469                "%llu", 
00470                connection->response->total_size);
00471       MHD_add_response_header (connection->response,
00472                                MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
00473     }
00474 }
00475 
00482 static void
00483 get_date_string (char *date)
00484 {
00485   static const char *days[] =
00486     { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00487   static const char *mons[] =
00488     { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
00489     "Nov", "Dec"
00490   };
00491   struct tm now;
00492   time_t t;
00493 
00494   time (&t);
00495   gmtime_r (&t, &now);
00496   SPRINTF (date,
00497            "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
00498            days[now.tm_wday % 7],
00499            now.tm_mday,
00500            mons[now.tm_mon % 12],
00501            1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec);
00502 }
00503 
00509 static int
00510 try_grow_read_buffer (struct MHD_Connection *connection)
00511 {
00512   void *buf;
00513 
00514   buf = MHD_pool_reallocate (connection->pool,
00515                              connection->read_buffer,
00516                              connection->read_buffer_size,
00517                              connection->read_buffer_size * 2 +
00518                              MHD_BUF_INC_SIZE + 1);
00519   if (buf == NULL)
00520     return MHD_NO;
00521   /* we can actually grow the buffer, do it! */
00522   connection->read_buffer = buf;
00523   connection->read_buffer_size =
00524     connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00525   return MHD_YES;
00526 }
00527 
00534 static int
00535 build_header_response (struct MHD_Connection *connection)
00536 {
00537   size_t size;
00538   size_t off;
00539   struct MHD_HTTP_Header *pos;
00540   char code[256];
00541   char date[128];
00542   char *data;
00543   enum MHD_ValueKind kind;
00544   const char *reason_phrase;
00545 
00546   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00547     {
00548       add_extra_headers (connection);
00549       reason_phrase = MHD_get_reason_phrase_for (connection->responseCode);
00550       SPRINTF (code,
00551                "%s %u %s\r\n",
00552                MHD_HTTP_VERSION_1_1, connection->responseCode, reason_phrase);
00553       off = strlen (code);
00554       /* estimate size */
00555       size = off + 2;           /* extra \r\n at the end */
00556       kind = MHD_HEADER_KIND;
00557       if (NULL == MHD_get_response_header (connection->response,
00558                                            MHD_HTTP_HEADER_DATE))
00559         get_date_string (date);
00560       else
00561         date[0] = '\0';
00562       size += strlen (date);
00563     }
00564   else
00565     {
00566       size = 2;
00567       kind = MHD_FOOTER_KIND;
00568       off = 0;
00569     }
00570   pos = connection->response->first_header;
00571   while (pos != NULL)
00572     {
00573       if (pos->kind == kind)
00574         size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */
00575       pos = pos->next;
00576     }
00577   /* produce data */
00578   data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
00579   if (data == NULL)
00580     {
00581 #if HAVE_MESSAGES
00582       MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
00583 #endif
00584       return MHD_NO;
00585     }
00586   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00587     {
00588       memcpy (data, code, off);
00589     }
00590   pos = connection->response->first_header;
00591   while (pos != NULL)
00592     {
00593       if (pos->kind == kind)
00594         off += SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value);
00595       pos = pos->next;
00596     }
00597   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00598     {
00599       strcpy (&data[off], date);
00600       off += strlen (date);
00601     }
00602   memcpy (&data[off], "\r\n", 2);
00603   off += 2;
00604   if (off != size)
00605     abort ();
00606   connection->write_buffer = data;
00607   connection->write_buffer_append_offset = size;
00608   connection->write_buffer_send_offset = 0;
00609   connection->write_buffer_size = size + 1;
00610   return MHD_YES;
00611 }
00612 
00620 static void
00621 transmit_error_response (struct MHD_Connection *connection,
00622                          unsigned int status_code, const char *message)
00623 {
00624   struct MHD_Response *response;
00625 
00626   /* die, header far too long to be reasonable */
00627   connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00628   connection->read_closed = MHD_YES;
00629 #if HAVE_MESSAGES
00630   MHD_DLOG (connection->daemon,
00631             "Error %u (`%s') processing request, closing connection.\n",
00632             status_code, message);
00633 #endif
00634   response = MHD_create_response_from_data (strlen (message),
00635                                             (void *) message, MHD_NO, MHD_NO);
00636   MHD_queue_response (connection, status_code, response);
00637   EXTRA_CHECK (connection->response != NULL);
00638   MHD_destroy_response (response);
00639   if (MHD_NO == build_header_response (connection))
00640     {
00641       /* oops - close! */
00642 #if HAVE_MESSAGES
00643       MHD_DLOG (connection->daemon,
00644                 "Closing connection (failed to create response header)\n");
00645 #endif
00646       connection->state = MHD_CONNECTION_CLOSED;
00647     }
00648   else
00649     {
00650       connection->state = MHD_CONNECTION_HEADERS_SENDING;
00651     }
00652 }
00653 
00658 static void
00659 do_fd_set (int fd, fd_set * set, int *max_fd)
00660 {
00661   FD_SET (fd, set);
00662   if (fd > *max_fd)
00663     *max_fd = fd;
00664 }
00665 
00671 int
00672 MHD_connection_get_fdset (struct MHD_Connection *connection,
00673                           fd_set * read_fd_set,
00674                           fd_set * write_fd_set,
00675                           fd_set * except_fd_set, int *max_fd)
00676 {
00677   int fd;
00678 
00679   if (connection->pool == NULL)
00680     connection->pool = MHD_pool_create (connection->daemon->pool_size);
00681   if (connection->pool == NULL)
00682     {
00683 #if HAVE_MESSAGES
00684       MHD_DLOG (connection->daemon, "Failed to create memory pool!\n");
00685 #endif
00686       connection_close_error (connection);
00687       return MHD_NO;
00688     }
00689   fd = connection->socket_fd;
00690   if (fd == -1)
00691     return MHD_YES;
00692   while (1)
00693     {
00694 #if DEBUG_STATES
00695       MHD_DLOG (connection->daemon, "%s: state: %s\n",
00696                 __FUNCTION__, MHD_state_to_string (connection->state));
00697 #endif
00698       switch (connection->state)
00699         {
00700         case MHD_CONNECTION_INIT:
00701         case MHD_CONNECTION_URL_RECEIVED:
00702         case MHD_CONNECTION_HEADER_PART_RECEIVED:
00703 #if HTTPS_SUPPORT
00704         case MHD_TLS_CONNECTION_INIT:
00705 #endif
00706           /* while reading headers, we always grow the
00707              read buffer if needed, no size-check required */
00708           if ((connection->read_closed) &&
00709               (connection->read_buffer_offset == 0))
00710             {
00711               connection->state = MHD_CONNECTION_CLOSED;
00712               continue;
00713             }
00714           if ((connection->read_buffer_offset == connection->read_buffer_size)
00715               && (MHD_NO == try_grow_read_buffer (connection)))
00716             {
00717               transmit_error_response (connection,
00718                                        (connection->url != NULL)
00719                                        ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00720                                        : MHD_HTTP_REQUEST_URI_TOO_LONG,
00721                                        REQUEST_TOO_BIG);
00722               continue;
00723             }
00724           if (MHD_NO == connection->read_closed)
00725             do_fd_set (fd, read_fd_set, max_fd);
00726           break;
00727         case MHD_CONNECTION_HEADERS_RECEIVED:
00728           /* we should never get here */
00729           EXTRA_CHECK (0);
00730           break;
00731         case MHD_CONNECTION_HEADERS_PROCESSED:
00732           EXTRA_CHECK (0);
00733           break;
00734         case MHD_CONNECTION_CONTINUE_SENDING:
00735           do_fd_set (fd, write_fd_set, max_fd);
00736           break;
00737         case MHD_CONNECTION_CONTINUE_SENT:
00738           if (connection->read_buffer_offset == connection->read_buffer_size)
00739             {
00740               if ((MHD_YES != try_grow_read_buffer (connection)) &&
00741                   (0 != (connection->daemon->options &
00742                          (MHD_USE_SELECT_INTERNALLY |
00743                           MHD_USE_THREAD_PER_CONNECTION))))
00744                 {
00745                   /* failed to grow the read buffer, and the
00746                      client which is supposed to handle the
00747                      received data in a *blocking* fashion
00748                      (in this mode) did not handle the data as
00749                      it was supposed to!
00750                      => we would either have to do busy-waiting
00751                      (on the client, which would likely fail),
00752                      or if we do nothing, we would just timeout
00753                      on the connection (if a timeout is even
00754                      set!).
00755                      Solution: we kill the connection with an error */
00756                   transmit_error_response (connection,
00757                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
00758                                            INTERNAL_ERROR);
00759                   continue;
00760                 }
00761             }
00762           if ((connection->read_buffer_offset < connection->read_buffer_size)
00763               && (MHD_NO == connection->read_closed))
00764             do_fd_set (fd, read_fd_set, max_fd);
00765           break;
00766         case MHD_CONNECTION_BODY_RECEIVED:
00767         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
00768           /* while reading footers, we always grow the
00769              read buffer if needed, no size-check required */
00770           if (MHD_YES == connection->read_closed)
00771             {
00772               connection->state = MHD_CONNECTION_CLOSED;
00773               continue;
00774             }
00775           do_fd_set (fd, read_fd_set, max_fd);
00776           /* transition to FOOTERS_RECEIVED
00777              happens in read handler */
00778           break;
00779         case MHD_CONNECTION_FOOTERS_RECEIVED:
00780           /* no socket action, wait for client
00781              to provide response */
00782           break;
00783         case MHD_CONNECTION_HEADERS_SENDING:
00784           /* headers in buffer, keep writing */
00785           do_fd_set (fd, write_fd_set, max_fd);
00786           break;
00787         case MHD_CONNECTION_HEADERS_SENT:
00788           EXTRA_CHECK (0);
00789           break;
00790         case MHD_CONNECTION_NORMAL_BODY_READY:
00791           do_fd_set (fd, write_fd_set, max_fd);
00792           break;
00793         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
00794           /* not ready, no socket action */
00795           break;
00796         case MHD_CONNECTION_CHUNKED_BODY_READY:
00797           do_fd_set (fd, write_fd_set, max_fd);
00798           break;
00799         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
00800           /* not ready, no socket action */
00801           break;
00802         case MHD_CONNECTION_BODY_SENT:
00803           EXTRA_CHECK (0);
00804           break;
00805         case MHD_CONNECTION_FOOTERS_SENDING:
00806           do_fd_set (fd, write_fd_set, max_fd);
00807           break;
00808         case MHD_CONNECTION_FOOTERS_SENT:
00809           EXTRA_CHECK (0);
00810           break;
00811         case MHD_CONNECTION_CLOSED:
00812           if (connection->socket_fd != -1)
00813             connection_close_error (connection);
00814           return MHD_YES;       /* do nothing, not even reading */
00815 
00816         default:
00817           EXTRA_CHECK (0);
00818         }
00819       break;
00820     }
00821   return MHD_YES;
00822 }
00823 
00832 static char *
00833 get_next_header_line (struct MHD_Connection *connection)
00834 {
00835   char *rbuf;
00836   size_t pos;
00837 
00838   if (connection->read_buffer_offset == 0)
00839     return NULL;
00840   pos = 0;
00841   rbuf = connection->read_buffer;
00842   while ((pos < connection->read_buffer_offset - 1) &&
00843          (rbuf[pos] != '\r') && (rbuf[pos] != '\n'))
00844     pos++;
00845   if (pos == connection->read_buffer_offset - 1)
00846     {
00847       /* not found, consider growing... */
00848       if (connection->read_buffer_offset == connection->read_buffer_size)
00849         {
00850           rbuf = MHD_pool_reallocate (connection->pool,
00851                                       connection->read_buffer,
00852                                       connection->read_buffer_size,
00853                                       connection->read_buffer_size * 2 +
00854                                       MHD_BUF_INC_SIZE);
00855           if (rbuf == NULL)
00856             {
00857               transmit_error_response (connection,
00858                                        (connection->url != NULL)
00859                                        ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00860                                        : MHD_HTTP_REQUEST_URI_TOO_LONG,
00861                                        REQUEST_TOO_BIG);
00862             }
00863           else
00864             {
00865               connection->read_buffer_size =
00866                 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00867               connection->read_buffer = rbuf;
00868             }
00869         }
00870       return NULL;
00871     }
00872   /* found, check if we have proper CRLF */
00873   if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n'))
00874     rbuf[pos++] = '\0';         /* skip both r and n */
00875   rbuf[pos++] = '\0';
00876   connection->read_buffer += pos;
00877   connection->read_buffer_size -= pos;
00878   connection->read_buffer_offset -= pos;
00879   return rbuf;
00880 }
00881 
00885 static int
00886 connection_add_header (struct MHD_Connection *connection,
00887                        char *key, char *value, enum MHD_ValueKind kind)
00888 {
00889   struct MHD_HTTP_Header *hdr;
00890 
00891   hdr = MHD_pool_allocate (connection->pool,
00892                            sizeof (struct MHD_HTTP_Header), MHD_YES);
00893   if (hdr == NULL)
00894     {
00895 #if HAVE_MESSAGES
00896       MHD_DLOG (connection->daemon,
00897                 "Not enough memory to allocate header record!\n");
00898 #endif
00899       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00900                                REQUEST_TOO_BIG);
00901       return MHD_NO;
00902     }
00903   hdr->next = connection->headers_received;
00904   hdr->header = key;
00905   hdr->value = value;
00906   hdr->kind = kind;
00907   connection->headers_received = hdr;
00908   return MHD_YES;
00909 }
00910 
00914 static int
00915 parse_arguments (enum MHD_ValueKind kind,
00916                  struct MHD_Connection *connection, char *args)
00917 {
00918   char *equals;
00919   char *amper;
00920 
00921   while (args != NULL)
00922     {
00923       equals = strstr (args, "=");
00924       if (equals == NULL)
00925         return MHD_NO;          /* invalid, ignore */
00926       equals[0] = '\0';
00927       equals++;
00928       amper = strstr (equals, "&");
00929       if (amper != NULL)
00930         {
00931           amper[0] = '\0';
00932           amper++;
00933         }
00934       MHD_http_unescape (args);
00935       MHD_http_unescape (equals);
00936       if (MHD_NO == connection_add_header (connection, args, equals, kind))
00937         return MHD_NO;
00938       args = amper;
00939     }
00940   return MHD_YES;
00941 }
00942 
00948 static int
00949 parse_cookie_header (struct MHD_Connection *connection)
00950 {
00951   const char *hdr;
00952   char *cpy;
00953   char *pos;
00954   char *sce;
00955   char *semicolon;
00956   char *equals;
00957   char *ekill;
00958   char old;
00959   int quotes;
00960 
00961   hdr = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "Cookie");
00962   if (hdr == NULL)
00963     return MHD_YES;
00964   cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
00965   if (cpy == NULL)
00966     {
00967 #if HAVE_MESSAGES
00968       MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
00969 #endif
00970       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00971                                REQUEST_TOO_BIG);
00972       return MHD_NO;
00973     }
00974   memcpy (cpy, hdr, strlen (hdr) + 1);
00975   pos = cpy;
00976   while (pos != NULL)
00977     {
00978       while (*pos == ' ')
00979         pos++;                  /* skip spaces */
00980 
00981       sce = pos;
00982       while (((*sce) != '\0') &&
00983              ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
00984         sce++;
00985       /* remove tailing whitespace (if any) from key */
00986       ekill = sce - 1;
00987       while ((*ekill == ' ') && (ekill >= pos))
00988         *(ekill--) = '\0';
00989       old = *sce;
00990       *sce = '\0';
00991       if (old != '=')
00992         {
00993           /* value part omitted, use empty string... */
00994           if (MHD_NO ==
00995               connection_add_header (connection, pos, "", MHD_COOKIE_KIND))
00996             return MHD_NO;
00997           if (old == '\0')
00998             break;
00999           pos = sce + 1;
01000           continue;
01001         }
01002       equals = sce + 1;
01003       quotes = 0;
01004       semicolon = equals;
01005       while ((semicolon[0] != '\0') &&
01006              ((quotes != 0) ||
01007               ((semicolon[0] != ';') && (semicolon[0] != ','))))
01008         {
01009           if (semicolon[0] == '"')
01010             quotes = (quotes + 1) & 1;
01011           semicolon++;
01012         }
01013       if (semicolon[0] == '\0')
01014         semicolon = NULL;
01015       if (semicolon != NULL)
01016         {
01017           semicolon[0] = '\0';
01018           semicolon++;
01019         }
01020       /* remove quotes */
01021       if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
01022         {
01023           equals[strlen (equals) - 1] = '\0';
01024           equals++;
01025         }
01026       if (MHD_NO == connection_add_header (connection,
01027                                            pos, equals, MHD_COOKIE_KIND))
01028         return MHD_NO;
01029       pos = semicolon;
01030     }
01031   return MHD_YES;
01032 }
01033 
01041 static int
01042 parse_initial_message_line (struct MHD_Connection *connection, char *line)
01043 {
01044   char *uri;
01045   char *httpVersion;
01046   char *args;
01047 
01048   uri = strstr (line, " ");
01049   if (uri == NULL)
01050     return MHD_NO;              /* serious error */
01051   uri[0] = '\0';
01052   connection->method = line;
01053   uri++;
01054   while (uri[0] == ' ')
01055     uri++;
01056   httpVersion = strstr (uri, " ");
01057   if (httpVersion != NULL)
01058     {
01059       httpVersion[0] = '\0';
01060       httpVersion++;
01061     }
01062   if (connection->daemon->uri_log_callback != NULL)
01063     connection->client_context
01064       =
01065       connection->daemon->uri_log_callback (connection->daemon->
01066                                             uri_log_callback_cls, uri);
01067   args = strstr (uri, "?");
01068   if (args != NULL)
01069     {
01070       args[0] = '\0';
01071       args++;
01072       parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
01073     }
01074   MHD_http_unescape (uri);
01075   connection->url = uri;
01076   if (httpVersion == NULL)
01077     connection->version = "";
01078   else
01079     connection->version = httpVersion;
01080   return MHD_YES;
01081 }
01082 
01088 static void
01089 call_connection_handler (struct MHD_Connection *connection)
01090 {
01091   size_t processed;
01092   size_t available;
01093   size_t used;
01094   size_t i;
01095   int instant_retry;
01096   int malformed;
01097   char *buffer_head;
01098 
01099   if (connection->response != NULL)
01100     return;                     /* already queued a response */
01101 
01102   buffer_head = connection->read_buffer;
01103   available = connection->read_buffer_offset;
01104   do
01105     {
01106       instant_retry = MHD_NO;
01107       if ((connection->have_chunked_upload == MHD_YES) &&
01108           (connection->remaining_upload_size == -1))
01109         {
01110           if ((connection->current_chunk_offset ==
01111                connection->current_chunk_size)
01112               && (connection->current_chunk_offset != 0) && (available >= 2))
01113             {
01114               /* skip new line at the *end* of a chunk */
01115               i = 0;
01116               if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01117                 i++;            /* skip 1st part of line feed */
01118               if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01119                 i++;            /* skip 2nd part of line feed */
01120               if (i == 0)
01121                 {
01122                   /* malformed encoding */
01123 #if HAVE_MESSAGES
01124                   MHD_DLOG (connection->daemon,
01125                             "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01126 #endif
01127                   connection_close_error (connection);
01128                   return;
01129                 }
01130               available -= i;
01131               buffer_head += i;
01132               connection->current_chunk_offset = 0;
01133               connection->current_chunk_size = 0;
01134             }
01135           if (connection->current_chunk_offset <
01136               connection->current_chunk_size)
01137             {
01138               /* we are in the middle of a chunk, give
01139                  as much as possible to the client (without
01140                  crossing chunk boundaries) */
01141               processed =
01142                 connection->current_chunk_size -
01143                 connection->current_chunk_offset;
01144               if (processed > available)
01145                 processed = available;
01146               if (available > processed)
01147                 instant_retry = MHD_YES;
01148             }
01149           else
01150             {
01151               /* we need to read chunk boundaries */
01152               i = 0;
01153               while (i < available)
01154                 {
01155                   if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01156                     break;
01157                   i++;
01158                   if (i >= 6)
01159                     break;
01160                 }
01161               /* take '\n' into account; if '\n'
01162                  is the unavailable character, we
01163                  will need to wait until we have it
01164                  before going further */
01165               if ((i + 1 >= available) &&
01166                   !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
01167                 break;          /* need more data... */
01168               malformed = (i >= 6);
01169               if (!malformed)
01170                 {
01171                   buffer_head[i] = '\0';
01172                   malformed =
01173                     (1 != SSCANF (buffer_head, "%X",
01174                                   &connection->current_chunk_size)) &&
01175                     (1 != SSCANF (buffer_head, "%x",
01176                                   &connection->current_chunk_size));
01177                 }
01178               if (malformed)
01179                 {
01180                   /* malformed encoding */
01181 #if HAVE_MESSAGES
01182                   MHD_DLOG (connection->daemon,
01183                             "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01184 #endif
01185                   connection_close_error (connection);
01186                   return;
01187                 }
01188               i++;
01189               if ((i < available) &&
01190                   ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
01191                 i++;            /* skip 2nd part of line feed */
01192 
01193               buffer_head += i;
01194               available -= i;
01195               connection->current_chunk_offset = 0;
01196 
01197               if (available > 0)
01198                 instant_retry = MHD_YES;
01199               if (connection->current_chunk_size == 0)
01200                 {
01201                   connection->remaining_upload_size = 0;
01202                   break;
01203                 }
01204               continue;
01205             }
01206         }
01207       else
01208         {
01209           /* no chunked encoding, give all to the client */
01210           processed = available;
01211         }
01212       used = processed;
01213       if (MHD_NO ==
01214           connection->daemon->default_handler (connection->daemon->
01215                                                default_handler_cls,
01216                                                connection, connection->url,
01217                                                connection->method,
01218                                                connection->version,
01219                                                buffer_head, &processed,
01220                                                &connection->client_context))
01221         {
01222           /* serious internal error, close connection */
01223 #if HAVE_MESSAGES
01224           MHD_DLOG (connection->daemon,
01225                     "Internal application error, closing connection.\n");
01226 #endif
01227           connection_close_error (connection);
01228           return;
01229         }
01230       if (processed > used)
01231         abort ();               /* fatal client API violation! */
01232       if (processed != 0)
01233         instant_retry = MHD_NO; /* client did not process everything */
01234       used -= processed;
01235       if (connection->have_chunked_upload == MHD_YES)
01236         connection->current_chunk_offset += used;
01237       /* dh left "processed" bytes in buffer for next time... */
01238       buffer_head += used;
01239       available -= used;
01240       if (connection->remaining_upload_size != -1)
01241         connection->remaining_upload_size -= used;
01242     }
01243   while (instant_retry == MHD_YES);
01244   if (available > 0)
01245     memmove (connection->read_buffer, buffer_head, available);
01246   connection->read_buffer_offset = available;
01247 }
01248 
01257 static int
01258 do_read (struct MHD_Connection *connection)
01259 {
01260   int bytes_read;
01261 
01262   if (connection->read_buffer_size == connection->read_buffer_offset)
01263     return MHD_NO;
01264 
01265   bytes_read = connection->recv_cls (connection,
01266                                      &connection->read_buffer
01267                                      [connection->read_buffer_offset],
01268                                      connection->read_buffer_size -
01269                                      connection->read_buffer_offset);
01270   if (bytes_read < 0)
01271     {
01272       if (errno == EINTR)
01273         return MHD_NO;
01274 #if HAVE_MESSAGES
01275       MHD_DLOG (connection->daemon,
01276                 "Failed to receive data: %s\n", STRERROR (errno));
01277 #endif
01278       connection_close_error (connection);
01279       return MHD_YES;
01280     }
01281   if (bytes_read == 0)
01282     {
01283       /* other side closed connection */
01284       connection->read_closed = MHD_YES;
01285       SHUTDOWN (connection->socket_fd, SHUT_RD);
01286       return MHD_NO;
01287     }
01288   connection->read_buffer_offset += bytes_read;
01289   return MHD_YES;
01290 }
01291 
01299 static int
01300 do_write (struct MHD_Connection *connection)
01301 {
01302   int ret;
01303 
01304   ret = connection->send_cls (connection,
01305                               &connection->write_buffer
01306                               [connection->write_buffer_send_offset],
01307                               connection->write_buffer_append_offset
01308                               - connection->write_buffer_send_offset);
01309 
01310   if (ret < 0)
01311     {
01312       if (errno == EINTR)
01313         return MHD_NO;
01314 #if HAVE_MESSAGES
01315       MHD_DLOG (connection->daemon,
01316                 "Failed to send data: %s\n", STRERROR (errno));
01317 #endif
01318       connection_close_error (connection);
01319       return MHD_YES;
01320     }
01321 #if DEBUG_SEND_DATA
01322   FPRINTF (stderr,
01323            "Sent response: `%.*s'\n",
01324            ret,
01325            &connection->write_buffer[connection->write_buffer_send_offset]);
01326 #endif
01327   connection->write_buffer_send_offset += ret;
01328   return MHD_YES;
01329 }
01330 
01336 static int
01337 check_write_done (struct MHD_Connection *connection,
01338                   enum MHD_CONNECTION_STATE next_state)
01339 {
01340   if (connection->write_buffer_append_offset !=
01341       connection->write_buffer_send_offset)
01342     return MHD_NO;
01343   connection->write_buffer_append_offset = 0;
01344   connection->write_buffer_send_offset = 0;
01345   connection->state = next_state;
01346   MHD_pool_reallocate (connection->pool, connection->write_buffer,
01347                        connection->write_buffer_size, 0);
01348   connection->write_buffer = NULL;
01349   connection->write_buffer_size = 0;
01350   return MHD_YES;
01351 }
01352 
01358 static int
01359 process_header_line (struct MHD_Connection *connection, char *line)
01360 {
01361   char *colon;
01362 
01363   /* line should be normal header line, find colon */
01364   colon = strstr (line, ":");
01365   if (colon == NULL)
01366     {
01367       /* error in header line, die hard */
01368 #if HAVE_MESSAGES
01369       MHD_DLOG (connection->daemon,
01370                 "Received malformed line (no colon), closing connection.\n");
01371 #endif
01372       connection->state = MHD_CONNECTION_CLOSED;
01373       return MHD_NO;
01374     }
01375   /* zero-terminate header */
01376   colon[0] = '\0';
01377   colon++;                      /* advance to value */
01378   while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
01379     colon++;
01380   /* we do the actual adding of the connection
01381      header at the beginning of the while
01382      loop since we need to be able to inspect
01383      the *next* header line (in case it starts
01384      with a space...) */
01385   connection->last = line;
01386   connection->colon = colon;
01387   return MHD_YES;
01388 }
01389 
01399 static int
01400 process_broken_line (struct MHD_Connection *connection,
01401                      char *line, enum MHD_ValueKind kind)
01402 {
01403   char *last;
01404   char *tmp;
01405 
01406   last = connection->last;
01407   if ((line[0] == ' ') || (line[0] == '\t'))
01408     {
01409       /* value was continued on the next line, see
01410          http://www.jmarshall.com/easy/http/ */
01411       last = MHD_pool_reallocate (connection->pool,
01412                                   last,
01413                                   strlen (last) + 1,
01414                                   strlen (line) + strlen (last) + 1);
01415       if (last == NULL)
01416         {
01417           transmit_error_response (connection,
01418                                    MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01419                                    REQUEST_TOO_BIG);
01420           return MHD_NO;
01421         }
01422       tmp = line;
01423       while ((tmp[0] == ' ') || (tmp[0] == '\t'))
01424         tmp++;                  /* skip whitespace at start of 2nd line */
01425       strcat (last, tmp);
01426       connection->last = last;
01427       return MHD_YES;           /* possibly more than 2 lines... */
01428     }
01429   EXTRA_CHECK ((last != NULL) && (connection->colon != NULL));
01430   if ((MHD_NO == connection_add_header (connection,
01431                                         last, connection->colon, kind)))
01432     {
01433       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01434                                REQUEST_TOO_BIG);
01435       return MHD_NO;
01436     }
01437   /* we still have the current line to deal with... */
01438   if (strlen (line) != 0)
01439     {
01440       if (MHD_NO == process_header_line (connection, line))
01441         {
01442           transmit_error_response (connection,
01443                                    MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED);
01444           return MHD_NO;
01445         }
01446     }
01447   return MHD_YES;
01448 }
01449 
01455 static void
01456 parse_connection_headers (struct MHD_Connection *connection)
01457 {
01458   const char *clen;
01459   unsigned long long cval;
01460   struct MHD_Response *response;
01461 
01462   parse_cookie_header (connection);
01463   if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
01464       && (NULL != connection->version)
01465       && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
01466       && (NULL ==
01467           MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
01468                                        MHD_HTTP_HEADER_HOST)))
01469     {
01470       /* die, http 1.1 request without host and we are pedantic */
01471       connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01472       connection->read_closed = MHD_YES;
01473 #if HAVE_MESSAGES
01474       MHD_DLOG (connection->daemon,
01475                 "Received `%s' request without `%s' header.\n",
01476                 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
01477 #endif
01478       response =
01479         MHD_create_response_from_data (strlen (REQUEST_LACKS_HOST),
01480                                        REQUEST_LACKS_HOST, MHD_NO, MHD_NO);
01481       MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
01482       MHD_destroy_response (response);
01483       return;
01484     }
01485 
01486   clen = MHD_lookup_connection_value (connection,
01487                                       MHD_HEADER_KIND,
01488                                       MHD_HTTP_HEADER_CONTENT_LENGTH);
01489   if (clen != NULL)
01490     {
01491       if (1 != SSCANF (clen, "%llu", &cval))
01492         {
01493 #if HAVE_MESSAGES
01494           MHD_DLOG (connection->daemon,
01495                     "Failed to parse `%s' header `%s', closing connection.\n",
01496                     MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
01497 #endif
01498           connection->state = MHD_CONNECTION_CLOSED;
01499           return;
01500         }
01501       connection->remaining_upload_size = cval;
01502     }
01503   else
01504     {
01505       if (NULL == MHD_lookup_connection_value (connection,
01506                                                MHD_HEADER_KIND,
01507                                                MHD_HTTP_HEADER_TRANSFER_ENCODING))
01508         {
01509           /* this request does not have a body */
01510           connection->remaining_upload_size = 0;
01511         }
01512       else
01513         {
01514           connection->remaining_upload_size = -1;       /* unknown size */
01515           if (0 ==
01516               strcasecmp (MHD_lookup_connection_value
01517                           (connection, MHD_HEADER_KIND,
01518                            MHD_HTTP_HEADER_TRANSFER_ENCODING), "chunked"))
01519             connection->have_chunked_upload = MHD_YES;
01520         }
01521     }
01522 }
01523 
01533 int
01534 MHD_connection_handle_read (struct MHD_Connection *connection)
01535 {
01536   connection->last_activity = time (NULL);
01537   if (connection->state == MHD_CONNECTION_CLOSED)
01538     return MHD_NO;
01539   if (MHD_NO == do_read (connection))
01540     return MHD_YES;
01541   while (1)
01542     {
01543 #if DEBUG_STATES
01544       MHD_DLOG (connection->daemon, "%s: state: %s\n",
01545                 __FUNCTION__, MHD_state_to_string (connection->state));
01546 #endif
01547       switch (connection->state)
01548         {
01549         case MHD_CONNECTION_INIT:
01550         case MHD_CONNECTION_URL_RECEIVED:
01551         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01552         case MHD_CONNECTION_HEADERS_RECEIVED:
01553         case MHD_CONNECTION_HEADERS_PROCESSED:
01554         case MHD_CONNECTION_CONTINUE_SENDING:
01555         case MHD_CONNECTION_CONTINUE_SENT:
01556         case MHD_CONNECTION_BODY_RECEIVED:
01557         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01558           /* nothing to do but default action */
01559           if (MHD_YES == connection->read_closed)
01560             {
01561               connection->state = MHD_CONNECTION_CLOSED;
01562               continue;
01563             }
01564           break;
01565         case MHD_CONNECTION_CLOSED:
01566           if (connection->socket_fd != -1)
01567             connection_close_error (connection);
01568           return MHD_NO;
01569         default:
01570           /* shrink read buffer to how much is actually used */
01571           MHD_pool_reallocate (connection->pool,
01572                                connection->read_buffer,
01573                                connection->read_buffer_size + 1,
01574                                connection->read_buffer_offset);
01575           break;
01576         }
01577       break;
01578     }
01579   return MHD_YES;
01580 }
01581 
01591 int
01592 MHD_connection_handle_write (struct MHD_Connection *connection)
01593 {
01594   struct MHD_Response *response;
01595   int ret;
01596   connection->last_activity = time (NULL);
01597   while (1)
01598     {
01599 #if DEBUG_STATES
01600       MHD_DLOG (connection->daemon, "%s: state: %s\n",
01601                 __FUNCTION__, MHD_state_to_string (connection->state));
01602 #endif
01603       switch (connection->state)
01604         {
01605         case MHD_CONNECTION_INIT:
01606         case MHD_CONNECTION_URL_RECEIVED:
01607         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01608         case MHD_CONNECTION_HEADERS_RECEIVED:
01609           EXTRA_CHECK (0);
01610           break;
01611         case MHD_CONNECTION_HEADERS_PROCESSED:
01612           break;
01613         case MHD_CONNECTION_CONTINUE_SENDING:
01614           ret = connection->send_cls (connection,
01615                                       &HTTP_100_CONTINUE
01616                                       [connection->continue_message_write_offset],
01617                                       strlen (HTTP_100_CONTINUE) -
01618                                       connection->continue_message_write_offset);
01619           if (ret < 0)
01620             {
01621               if (errno == EINTR)
01622                 break;
01623 #if HAVE_MESSAGES
01624               MHD_DLOG (connection->daemon,
01625                         "Failed to send data: %s\n", STRERROR (errno));
01626 #endif
01627               connection_close_error (connection);
01628               return MHD_NO;
01629             }
01630 #if DEBUG_SEND_DATA
01631           FPRINTF (stderr,
01632                    "Sent 100 continue response: `%.*s'\n",
01633                    ret,
01634                    &HTTP_100_CONTINUE
01635                    [connection->continue_message_write_offset]);
01636 #endif
01637           connection->continue_message_write_offset += ret;
01638           break;
01639         case MHD_CONNECTION_CONTINUE_SENT:
01640         case MHD_CONNECTION_BODY_RECEIVED:
01641         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01642         case MHD_CONNECTION_FOOTERS_RECEIVED:
01643           EXTRA_CHECK (0);
01644           break;
01645         case MHD_CONNECTION_HEADERS_SENDING:
01646           do_write (connection);
01647           check_write_done (connection, MHD_CONNECTION_HEADERS_SENT);
01648           break;
01649         case MHD_CONNECTION_HEADERS_SENT:
01650           EXTRA_CHECK (0);
01651           break;
01652         case MHD_CONNECTION_NORMAL_BODY_READY:
01653           response = connection->response;
01654           if (response->crc != NULL)
01655             pthread_mutex_lock (&response->mutex);
01656           if (MHD_YES != try_ready_normal_body (connection))
01657             {
01658               if (response->crc != NULL)
01659                 pthread_mutex_unlock (&response->mutex);
01660               connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
01661               break;
01662             }
01663 #if HTTPS_SUPPORT
01664           if (connection->daemon->options & MHD_USE_SSL)
01665             {
01666               ret = MHD__gnutls_record_send (connection->tls_session,
01667                                              &connection->response->data
01668                                              [connection->
01669                                               response_write_position -
01670                                               response->data_start],
01671                                              response->data_size -
01672                                              (connection->response_write_position
01673                                               - response->data_start));
01674             }
01675           else
01676 #endif
01677             {
01678               ret = connection->send_cls (connection,
01679                                           &response->data
01680                                           [connection->response_write_position
01681                                            - response->data_start],
01682                                           response->data_size -
01683                                           (connection->response_write_position
01684                                            - response->data_start));
01685             }
01686 #if DEBUG_SEND_DATA
01687           if (ret > 0)
01688             FPRINTF (stderr,
01689                      "Sent DATA response: `%.*s'\n",
01690                      ret,
01691                      &response->data[connection->response_write_position -
01692                                      response->data_start]);
01693 #endif
01694           if (response->crc != NULL)
01695             pthread_mutex_unlock (&response->mutex);
01696           if (ret < 0)
01697             {
01698               if (errno == EINTR)
01699                 return MHD_YES;
01700 #if HAVE_MESSAGES
01701               MHD_DLOG (connection->daemon,
01702                         "Failed to send data: %s\n", STRERROR (errno));
01703 #endif
01704               connection_close_error (connection);
01705               return MHD_NO;
01706             }
01707           connection->response_write_position += ret;
01708           if (connection->response_write_position ==
01709               connection->response->total_size)
01710             connection->state = MHD_CONNECTION_FOOTERS_SENT;    /* have no footers... */
01711           break;
01712         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01713           EXTRA_CHECK (0);
01714           break;
01715         case MHD_CONNECTION_CHUNKED_BODY_READY:
01716           do_write (connection);
01717           check_write_done (connection,
01718                             (connection->response->total_size ==
01719                              connection->response_write_position) ?
01720                             MHD_CONNECTION_BODY_SENT :
01721                             MHD_CONNECTION_CHUNKED_BODY_UNREADY);
01722           break;
01723         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
01724         case MHD_CONNECTION_BODY_SENT:
01725           EXTRA_CHECK (0);
01726           break;
01727         case MHD_CONNECTION_FOOTERS_SENDING:
01728           do_write (connection);
01729           check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT);
01730           break;
01731         case MHD_CONNECTION_FOOTERS_SENT:
01732           EXTRA_CHECK (0);
01733           break;
01734         case MHD_CONNECTION_CLOSED:
01735           if (connection->socket_fd != -1)
01736             connection_close_error (connection);
01737           return MHD_NO;
01738         case MHD_TLS_CONNECTION_INIT:
01739         case MHD_TLS_HELLO_REQUEST:
01740         case MHD_TLS_HANDSHAKE_FAILED:
01741           EXTRA_CHECK (0);
01742           break;
01743         default:
01744           EXTRA_CHECK (0);
01745           connection_close_error (connection);
01746           return MHD_NO;
01747         }
01748       break;
01749     }
01750   return MHD_YES;
01751 }
01752 
01762 int
01763 MHD_connection_handle_idle (struct MHD_Connection *connection)
01764 {
01765   unsigned int timeout;
01766   const char *end;
01767   char *line;
01768 
01769   while (1)
01770     {
01771 #if DEBUG_STATES
01772       MHD_DLOG (connection->daemon, "%s: state: %s\n",
01773                 __FUNCTION__, MHD_state_to_string (connection->state));
01774 #endif
01775       switch (connection->state)
01776         {
01777         case MHD_CONNECTION_INIT:
01778           line = get_next_header_line (connection);
01779           if (line == NULL)
01780             {
01781               if (connection->state != MHD_CONNECTION_INIT)
01782                 continue;
01783               if (connection->read_closed)
01784                 {
01785                   connection->state = MHD_CONNECTION_CLOSED;
01786                   continue;
01787                 }
01788               break;
01789             }
01790           if (MHD_NO == parse_initial_message_line (connection, line))
01791             connection->state = MHD_CONNECTION_CLOSED;
01792           else
01793             connection->state = MHD_CONNECTION_URL_RECEIVED;
01794           continue;
01795         case MHD_CONNECTION_URL_RECEIVED:
01796           line = get_next_header_line (connection);
01797           if (line == NULL)
01798             {
01799               if (connection->state != MHD_CONNECTION_URL_RECEIVED)
01800                 continue;
01801               if (connection->read_closed)
01802                 {
01803                   connection->state = MHD_CONNECTION_CLOSED;
01804                   continue;
01805                 }
01806               break;
01807             }
01808           if (strlen (line) == 0)
01809             {
01810               connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01811               continue;
01812             }
01813           if (MHD_NO == process_header_line (connection, line))
01814             {
01815               transmit_error_response (connection,
01816                                        MHD_HTTP_BAD_REQUEST,
01817                                        REQUEST_MALFORMED);
01818               break;
01819             }
01820           connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
01821           continue;
01822         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01823           line = get_next_header_line (connection);
01824           if (line == NULL)
01825             {
01826               if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
01827                 continue;
01828               if (connection->read_closed)
01829                 {
01830                   connection->state = MHD_CONNECTION_CLOSED;
01831                   continue;
01832                 }
01833               break;
01834             }
01835           if (MHD_NO ==
01836               process_broken_line (connection, line, MHD_HEADER_KIND))
01837             continue;
01838           if (strlen (line) == 0)
01839             {
01840               connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01841               continue;
01842             }
01843           continue;
01844         case MHD_CONNECTION_HEADERS_RECEIVED:
01845           parse_connection_headers (connection);
01846           if (connection->state == MHD_CONNECTION_CLOSED)
01847             continue;
01848           connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
01849           continue;
01850         case MHD_CONNECTION_HEADERS_PROCESSED:
01851           call_connection_handler (connection); /* first call */
01852           if (connection->state == MHD_CONNECTION_CLOSED)
01853             continue;
01854           if (need_100_continue (connection))
01855             {
01856               connection->state = MHD_CONNECTION_CONTINUE_SENDING;
01857               break;
01858             }
01859           if (connection->response != NULL)
01860             {
01861               /* we refused (no upload allowed!) */
01862               connection->remaining_upload_size = 0;
01863               /* force close, in case client still tries to upload... */
01864               connection->read_closed = MHD_YES;
01865             }
01866           connection->state = (connection->remaining_upload_size == 0)
01867             ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
01868           continue;
01869         case MHD_CONNECTION_CONTINUE_SENDING:
01870           if (connection->continue_message_write_offset ==
01871               strlen (HTTP_100_CONTINUE))
01872             {
01873               connection->state = MHD_CONNECTION_CONTINUE_SENT;
01874               continue;
01875             }
01876           break;
01877         case MHD_CONNECTION_CONTINUE_SENT:
01878           if (connection->read_buffer_offset != 0)
01879             {
01880               call_connection_handler (connection);     /* loop call */
01881               if (connection->state == MHD_CONNECTION_CLOSED)
01882                 continue;
01883             }
01884           if ((connection->remaining_upload_size == 0) ||
01885               ((connection->remaining_upload_size == -1) &&
01886                (connection->read_buffer_offset == 0) &&
01887                (MHD_YES == connection->read_closed)))
01888             {
01889               if ((MHD_YES == connection->have_chunked_upload) &&
01890                   (MHD_NO == connection->read_closed))
01891                 connection->state = MHD_CONNECTION_BODY_RECEIVED;
01892               else
01893                 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01894               continue;
01895             }
01896           break;
01897         case MHD_CONNECTION_BODY_RECEIVED:
01898           line = get_next_header_line (connection);
01899           if (line == NULL)
01900             {
01901               if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
01902                 continue;
01903               if (connection->read_closed)
01904                 {
01905                   connection->state = MHD_CONNECTION_CLOSED;
01906                   continue;
01907                 }
01908               break;
01909             }
01910           if (strlen (line) == 0)
01911             {
01912               connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01913               continue;
01914             }
01915           if (MHD_NO == process_header_line (connection, line))
01916             {
01917               transmit_error_response (connection,
01918                                        MHD_HTTP_BAD_REQUEST,
01919                                        REQUEST_MALFORMED);
01920               break;
01921             }
01922           connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
01923           continue;
01924         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01925           line = get_next_header_line (connection);
01926           if (line == NULL)
01927             {
01928               if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
01929                 continue;
01930               if (connection->read_closed)
01931                 {
01932                   connection->state = MHD_CONNECTION_CLOSED;
01933                   continue;
01934                 }
01935               break;
01936             }
01937           if (MHD_NO ==
01938               process_broken_line (connection, line, MHD_FOOTER_KIND))
01939             continue;
01940           if (strlen (line) == 0)
01941             {
01942               connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01943               continue;
01944             }
01945           continue;
01946         case MHD_CONNECTION_FOOTERS_RECEIVED:
01947           call_connection_handler (connection); /* "final" call */
01948           if (connection->state == MHD_CONNECTION_CLOSED)
01949             continue;
01950           if (connection->response == NULL)
01951             break;              /* try again next time */
01952           if (MHD_NO == build_header_response (connection))
01953             {
01954               /* oops - close! */
01955 #if HAVE_MESSAGES
01956               MHD_DLOG (connection->daemon,
01957                         "Closing connection (failed to create response header)\n");
01958 #endif
01959               connection->state = MHD_CONNECTION_CLOSED;
01960               continue;
01961             }
01962           connection->state = MHD_CONNECTION_HEADERS_SENDING;
01963 
01964 #if HAVE_TCP_CORK
01965           /* starting header send, set TCP cork */
01966           {
01967             const int val = 1;
01968             setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
01969                         sizeof (val));
01970           }
01971 #endif
01972           break;
01973         case MHD_CONNECTION_HEADERS_SENDING:
01974           /* no default action */
01975           break;
01976         case MHD_CONNECTION_HEADERS_SENT:
01977           if (connection->have_chunked_upload)
01978             connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
01979           else
01980             connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
01981           continue;
01982         case MHD_CONNECTION_NORMAL_BODY_READY:
01983           /* nothing to do here */
01984           break;
01985         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01986           if (connection->response->crc != NULL)
01987             pthread_mutex_lock (&connection->response->mutex);
01988           if (MHD_YES == try_ready_normal_body (connection))
01989             {
01990               if (connection->response->crc != NULL)
01991                 pthread_mutex_unlock (&connection->response->mutex);
01992               connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
01993               break;
01994             }
01995           if (connection->response->crc != NULL)
01996             pthread_mutex_unlock (&connection->response->mutex);
01997           /* not ready, no socket action */
01998           break;
01999         case MHD_CONNECTION_CHUNKED_BODY_READY:
02000           /* nothing to do here */
02001           break;
02002         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
02003           if (connection->response->crc != NULL)
02004             pthread_mutex_lock (&connection->response->mutex);
02005           if (MHD_YES == try_ready_chunked_body (connection))
02006             {
02007               if (connection->response->crc != NULL)
02008                 pthread_mutex_unlock (&connection->response->mutex);
02009               connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
02010               continue;
02011             }
02012           if (connection->response->crc != NULL)
02013             pthread_mutex_unlock (&connection->response->mutex);
02014           break;
02015         case MHD_CONNECTION_BODY_SENT:
02016           build_header_response (connection);
02017           if (connection->write_buffer_send_offset ==
02018               connection->write_buffer_append_offset)
02019             connection->state = MHD_CONNECTION_FOOTERS_SENT;
02020           else
02021             connection->state = MHD_CONNECTION_FOOTERS_SENDING;
02022           continue;
02023         case MHD_CONNECTION_FOOTERS_SENDING:
02024           /* no default action */
02025           break;
02026         case MHD_CONNECTION_FOOTERS_SENT:
02027 #if HAVE_TCP_CORK
02028           /* done sending, uncork */
02029           {
02030             const int val = 0;
02031             setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02032                         sizeof (val));
02033           }
02034 #endif
02035           MHD_destroy_response (connection->response);
02036           if (connection->daemon->notify_completed != NULL)
02037             connection->daemon->notify_completed (connection->daemon->
02038                                                   notify_completed_cls,
02039                                                   connection,
02040                                                   &connection->client_context,
02041                                                   MHD_REQUEST_TERMINATED_COMPLETED_OK);
02042           end =
02043             MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
02044                                          MHD_HTTP_HEADER_CONNECTION);
02045           connection->client_context = NULL;
02046           connection->continue_message_write_offset = 0;
02047           connection->responseCode = 0;
02048           connection->response = NULL;
02049           connection->headers_received = NULL;
02050           connection->response_write_position = 0;
02051           connection->have_chunked_upload = MHD_NO;
02052           connection->method = NULL;
02053           connection->url = NULL;
02054           connection->write_buffer = NULL;
02055           connection->write_buffer_size = 0;
02056           connection->write_buffer_send_offset = 0;
02057           connection->write_buffer_append_offset = 0;
02058           if ((end != NULL) && (0 == strcasecmp (end, "close")))
02059             {
02060               connection->read_closed = MHD_YES;
02061               connection->read_buffer_offset = 0;
02062             }
02063           if (((MHD_YES == connection->read_closed) &&
02064                (0 == connection->read_buffer_offset)) ||
02065               (connection->version == NULL) ||
02066               (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
02067             {
02068               /* http 1.0, version-less requests cannot be pipelined */
02069               connection->state = MHD_CONNECTION_CLOSED;
02070               MHD_pool_destroy (connection->pool);
02071               connection->pool = NULL;
02072               connection->read_buffer = NULL;
02073               connection->read_buffer_size = 0;
02074               connection->read_buffer_offset = 0;
02075             }
02076           else
02077             {
02078               connection->version = NULL;
02079               connection->state = MHD_CONNECTION_INIT;
02080               connection->read_buffer
02081                 = MHD_pool_reset (connection->pool,
02082                                   connection->read_buffer,
02083                                   connection->read_buffer_size);
02084             }
02085           continue;
02086         case MHD_CONNECTION_CLOSED:
02087           if (connection->socket_fd != -1)
02088             connection_close_error (connection);
02089           break;
02090         default:
02091           EXTRA_CHECK (0);
02092           break;
02093         }
02094       break;
02095     }
02096   timeout = connection->daemon->connection_timeout;
02097   if ((connection->socket_fd != -1) &&
02098       (timeout != 0) && (time (NULL) - timeout > connection->last_activity))
02099     {
02100       connection_close_error (connection);
02101       return MHD_NO;
02102     }
02103   return MHD_YES;
02104 
02105 }
02106 
02107 void
02108 MHD_set_http_calbacks (struct MHD_Connection *connection)
02109 {
02110   connection->read_handler = &MHD_connection_handle_read;
02111   connection->write_handler = &MHD_connection_handle_write;
02112   connection->idle_handler = &MHD_connection_handle_idle;
02113 }
02114 
02115 #if HTTPS_SUPPORT
02116 #include "gnutls_int.h"
02117 #include "gnutls_record.h"
02118 #endif
02119 
02129 const union MHD_ConnectionInfo *
02130 MHD_get_connection_info (struct MHD_Connection *connection,
02131                          enum MHD_ConnectionInfoType infoType, ...)
02132 {
02133   switch (infoType)
02134     {
02135 #if HTTPS_SUPPORT
02136     case MHD_CONNECTION_INFO_CIPHER_ALGO:
02137       if (connection->tls_session == NULL)
02138         return NULL;
02139       return (const union MHD_ConnectionInfo *) &connection->
02140         tls_session->security_parameters.read_bulk_cipher_algorithm;
02141     case MHD_CONNECTION_INFO_PROTOCOL:
02142       if (connection->tls_session == NULL)
02143         return NULL;
02144       return (const union MHD_ConnectionInfo *) &connection->
02145         tls_session->security_parameters.version;
02146 #endif
02147     case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
02148       return (const union MHD_ConnectionInfo *) &connection->addr;
02149     default:
02150       return NULL;
02151     };
02152 }
02153 
02154 
02155 /* end of connection.c */

Generated on Fri Feb 27 18:18:39 2009 for GNU libmicrohttpd by  doxygen 1.5.8