connection.c

Go to the documentation of this file.
00001 /*
00002      This file is part of libmicrohttpd
00003      (C) 2007, 2008 Daniel Pittman and Christian Grothoff
00004 
00005      This library is free software; you can redistribute it and/or
00006      modify it under the terms of the GNU Lesser General Public
00007      License as published by the Free Software Foundation; either
00008      version 2.1 of the License, or (at your option) any later version.
00009 
00010      This library is distributed in the hope that it will be useful,
00011      but WITHOUT ANY WARRANTY; without even the implied warranty of
00012      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013      Lesser General Public License for more details.
00014 
00015      You should have received a copy of the GNU Lesser General Public
00016      License along with this library; if not, write to the Free Software
00017      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019 */
00020 
00028 #include "internal.h"
00029 #include "connection.h"
00030 #include "memorypool.h"
00031 #include "response.h"
00032 #include "reason_phrase.h"
00033 
00034 #if HAVE_NETINET_TCP_H
00035 /* for TCP_CORK */
00036 #include <netinet/tcp.h>
00037 #endif
00038 
00042 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
00043 
00051 #if HAVE_MESSAGES
00052 #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>"
00053 #else
00054 #define REQUEST_TOO_BIG ""
00055 #endif
00056 
00064 #if HAVE_MESSAGES
00065 #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>"
00066 #else
00067 #define REQUEST_LACKS_HOST ""
00068 #endif
00069 
00077 #if HAVE_MESSAGES
00078 #define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
00079 #else
00080 #define REQUEST_MALFORMED ""
00081 #endif
00082 
00089 #if HAVE_MESSAGES
00090 #define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Some programmer needs to study the manual more carefully.</body></html>"
00091 #else
00092 #define INTERNAL_ERROR ""
00093 #endif
00094 
00099 #define DEBUG_CLOSE MHD_NO
00100 
00104 #define DEBUG_SEND_DATA MHD_NO
00105 
00114 int
00115 MHD_get_connection_values (struct MHD_Connection *connection,
00116                            enum MHD_ValueKind kind,
00117                            MHD_KeyValueIterator iterator, void *iterator_cls)
00118 {
00119   int ret;
00120   struct MHD_HTTP_Header *pos;
00121 
00122   if (connection == NULL)
00123     return -1;
00124   ret = 0;
00125   pos = connection->headers_received;
00126   while (pos != NULL)
00127     {
00128       if (0 != (pos->kind & kind))
00129         {
00130           ret++;
00131           if ((iterator != NULL) &&
00132               (MHD_YES != iterator (iterator_cls,
00133                                     kind, pos->header, pos->value)))
00134             return ret;
00135         }
00136       pos = pos->next;
00137     }
00138   return ret;
00139 }
00140 
00170 int
00171 MHD_set_connection_value (struct MHD_Connection *connection,
00172                           enum MHD_ValueKind kind,
00173                           const char *key, const char *value)
00174 {
00175   struct MHD_HTTP_Header *pos;
00176 
00177   pos = MHD_pool_allocate (connection->pool,
00178                            sizeof (struct MHD_HTTP_Header), MHD_NO);
00179   if (pos == NULL)
00180     return MHD_NO;
00181   pos->header = (char *) key;
00182   pos->value = (char *) value;
00183   pos->kind = kind;
00184   pos->next = connection->headers_received;
00185   connection->headers_received = pos;
00186   return MHD_YES;
00187 }
00188 
00196 const char *
00197 MHD_lookup_connection_value (struct MHD_Connection *connection,
00198                              enum MHD_ValueKind kind, const char *key)
00199 {
00200   struct MHD_HTTP_Header *pos;
00201 
00202   if (connection == NULL)
00203     return NULL;
00204   pos = connection->headers_received;
00205   while (pos != NULL)
00206     {
00207       if ((0 != (pos->kind & kind)) && (0 == strcasecmp (key, pos->header)))
00208         return pos->value;
00209       pos = pos->next;
00210     }
00211   return NULL;
00212 }
00213 
00224 int
00225 MHD_queue_response (struct MHD_Connection *connection,
00226                     unsigned int status_code, struct MHD_Response *response)
00227 {
00228   if ((connection == NULL) ||
00229       (response == NULL) ||
00230       (connection->response != NULL) ||
00231       ((connection->state != MHD_CONNECTION_HEADERS_PROCESSED) &&
00232        (connection->state != MHD_CONNECTION_FOOTERS_RECEIVED)))
00233     return MHD_NO;
00234   MHD_increment_response_rc (response);
00235   connection->response = response;
00236   connection->responseCode = status_code;
00237   if ((connection->method != NULL) &&
00238       (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD)))
00239     {
00240       /* if this is a "HEAD" request, pretend that we
00241          have already sent the full message body */
00242       connection->response_write_position = response->total_size;
00243     }
00244   if ((response->total_size == MHD_SIZE_UNKNOWN) &&
00245       (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00246     connection->have_chunked_response = MHD_YES;
00247   else
00248     connection->have_chunked_response = MHD_NO;
00249   if (connection->state == MHD_CONNECTION_HEADERS_PROCESSED)
00250     {
00251       /* response was queued "early",
00252          refuse to read body / footers or further
00253          requests! */
00254       SHUTDOWN (connection->socket_fd, SHUT_RD);
00255       connection->read_closed = MHD_YES;
00256       connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00257     }
00258   return MHD_YES;
00259 }
00260 
00265 static int
00266 need_100_continue (struct MHD_Connection *connection)
00267 {
00268   const char *expect;
00269 
00270   return ((connection->response == NULL) &&
00271           (connection->version != NULL) &&
00272           (0 == strcasecmp (connection->version,
00273                             MHD_HTTP_VERSION_1_1)) &&
00274           (NULL != (expect = MHD_lookup_connection_value (connection,
00275                                                           MHD_HEADER_KIND,
00276                                                           MHD_HTTP_HEADER_EXPECT)))
00277           && (0 == strcasecmp (expect, "100-continue"))
00278           && (connection->continue_message_write_offset <
00279               strlen (HTTP_100_CONTINUE)));
00280 }
00281 
00286 void
00287 MHD_connection_close (struct MHD_Connection *connection,
00288                       enum MHD_RequestTerminationCode termination_code)
00289 {
00290   SHUTDOWN (connection->socket_fd, SHUT_RDWR);
00291   CLOSE (connection->socket_fd);
00292   connection->socket_fd = -1;
00293   connection->state = MHD_CONNECTION_CLOSED;
00294   if ( (NULL != connection->daemon->notify_completed) &&
00295        (MHD_YES == connection->client_aware) )
00296     connection->daemon->notify_completed (connection->daemon->
00297                                           notify_completed_cls, connection,
00298                                           &connection->client_context,
00299                                           termination_code);    
00300   connection->client_aware = MHD_NO;
00301 }
00302 
00307 static void
00308 connection_close_error (struct MHD_Connection *connection)
00309 {
00310   MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR);
00311 }
00312 
00322 static int
00323 try_ready_normal_body (struct MHD_Connection *connection)
00324 {
00325   int ret;
00326   struct MHD_Response *response;
00327 
00328   response = connection->response;
00329   if (response->crc == NULL)
00330     return MHD_YES;
00331   ret = response->crc (response->crc_cls,
00332                        connection->response_write_position,
00333                        response->data,
00334                        MHD_MIN (response->data_buffer_size,
00335                                 response->total_size -
00336                                 connection->response_write_position));
00337   if ((ret == 0) &&
00338       (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY)))
00339     abort ();                   /* serious client API violation */
00340   if (ret == -1)
00341     {
00342       /* either error or http 1.0 transfer, close
00343          socket! */
00344 #if DEBUG_CLOSE
00345 #if HAVE_MESSAGES
00346       MHD_DLOG (connection->daemon, "Closing connection (end of response)\n");
00347 #endif
00348 #endif
00349       response->total_size = connection->response_write_position;
00350       connection_close_error (connection);
00351       return MHD_NO;
00352     }
00353   response->data_start = connection->response_write_position;
00354   response->data_size = ret;
00355   if (ret == 0)
00356     return MHD_NO;
00357   return MHD_YES;
00358 }
00359 
00369 static int
00370 try_ready_chunked_body (struct MHD_Connection *connection)
00371 {
00372   int ret;
00373   char *buf;
00374   struct MHD_Response *response;
00375   size_t size;
00376   char cbuf[10];                /* 10: max strlen of "%x\r\n" */
00377   int cblen;
00378 
00379   response = connection->response;
00380   if (connection->write_buffer_size == 0)
00381     {
00382       size = connection->daemon->pool_size;
00383       do
00384         {
00385           size /= 2;
00386           if (size < 128)
00387             {
00388               /* not enough memory */
00389 #if DEBUG_CLOSE
00390 #if HAVE_MESSAGES
00391               MHD_DLOG (connection->daemon,
00392                         "Closing connection (out of memory)\n");
00393 #endif
00394 #endif
00395               connection_close_error (connection);
00396               return MHD_NO;
00397             }
00398           buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
00399         }
00400       while (buf == NULL);
00401       connection->write_buffer_size = size;
00402       connection->write_buffer = buf;
00403     }
00404 
00405   ret = response->crc (response->crc_cls,
00406                        connection->response_write_position,
00407                        &connection->write_buffer[sizeof (cbuf)],
00408                        connection->write_buffer_size - sizeof (cbuf) - 2);
00409   if (ret == -1)
00410     {
00411       /* end of message, signal other side! */
00412       strcpy (connection->write_buffer, "0\r\n");
00413       connection->write_buffer_append_offset = 3;
00414       connection->write_buffer_send_offset = 0;
00415       response->total_size = connection->response_write_position;
00416       return MHD_YES;
00417     }
00418   if (ret == 0)
00419     {
00420       connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
00421       return MHD_NO;
00422     }
00423   if (ret > 0xFFFFFF)
00424     ret = 0xFFFFFF;
00425   SPRINTF (cbuf, "%X\r\n", ret);
00426   cblen = strlen (cbuf);
00427   EXTRA_CHECK (cblen <= sizeof (cbuf));
00428   memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
00429   memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
00430   connection->response_write_position += ret;
00431   connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
00432   connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
00433   return MHD_YES;
00434 }
00435 
00440 static void
00441 add_extra_headers (struct MHD_Connection *connection)
00442 {
00443   const char *have;
00444   char buf[128];
00445 
00446   connection->have_chunked_upload = MHD_NO;
00447   if (connection->response->total_size == MHD_SIZE_UNKNOWN)
00448     {
00449       have = MHD_get_response_header (connection->response,
00450                                       MHD_HTTP_HEADER_CONNECTION);
00451       if ((have == NULL) || (0 != strcasecmp (have, "close")))
00452         {
00453           if ((connection->version != NULL) &&
00454               (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00455             {
00456               connection->have_chunked_upload = MHD_YES;
00457               have = MHD_get_response_header (connection->response,
00458                                               MHD_HTTP_HEADER_TRANSFER_ENCODING);
00459               if (have == NULL)
00460                 MHD_add_response_header (connection->response,
00461                                          MHD_HTTP_HEADER_TRANSFER_ENCODING,
00462                                          "chunked");
00463             }
00464           else
00465             {
00466               MHD_add_response_header (connection->response,
00467                                        MHD_HTTP_HEADER_CONNECTION, "close");
00468             }
00469         }
00470     }
00471   else if (NULL == MHD_get_response_header (connection->response,
00472                                             MHD_HTTP_HEADER_CONTENT_LENGTH))
00473     {
00474       SPRINTF (buf,
00475                "%llu", 
00476                (unsigned long long)connection->response->total_size);
00477       MHD_add_response_header (connection->response,
00478                                MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
00479     }
00480 }
00481 
00488 static void
00489 get_date_string (char *date)
00490 {
00491   static const char *days[] =
00492     { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00493   static const char *mons[] =
00494     { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
00495     "Nov", "Dec"
00496   };
00497   struct tm now;
00498   time_t t;
00499 
00500   time (&t);
00501   gmtime_r (&t, &now);
00502   SPRINTF (date,
00503            "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
00504            days[now.tm_wday % 7],
00505            now.tm_mday,
00506            mons[now.tm_mon % 12],
00507            1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec);
00508 }
00509 
00515 static int
00516 try_grow_read_buffer (struct MHD_Connection *connection)
00517 {
00518   void *buf;
00519 
00520   buf = MHD_pool_reallocate (connection->pool,
00521                              connection->read_buffer,
00522                              connection->read_buffer_size,
00523                              connection->read_buffer_size * 2 +
00524                              MHD_BUF_INC_SIZE + 1);
00525   if (buf == NULL)
00526     return MHD_NO;
00527   /* we can actually grow the buffer, do it! */
00528   connection->read_buffer = buf;
00529   connection->read_buffer_size =
00530     connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00531   return MHD_YES;
00532 }
00533 
00540 static int
00541 build_header_response (struct MHD_Connection *connection)
00542 {
00543   size_t size;
00544   size_t off;
00545   struct MHD_HTTP_Header *pos;
00546   char code[256];
00547   char date[128];
00548   char *data;
00549   enum MHD_ValueKind kind;
00550   const char *reason_phrase;
00551 
00552   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00553     {
00554       add_extra_headers (connection);
00555       reason_phrase = MHD_get_reason_phrase_for (connection->responseCode);
00556       SPRINTF (code,
00557                "%s %u %s\r\n",
00558                MHD_HTTP_VERSION_1_1, connection->responseCode, reason_phrase);
00559       off = strlen (code);
00560       /* estimate size */
00561       size = off + 2;           /* extra \r\n at the end */
00562       kind = MHD_HEADER_KIND;
00563       if (NULL == MHD_get_response_header (connection->response,
00564                                            MHD_HTTP_HEADER_DATE))
00565         get_date_string (date);
00566       else
00567         date[0] = '\0';
00568       size += strlen (date);
00569     }
00570   else
00571     {
00572       size = 2;
00573       kind = MHD_FOOTER_KIND;
00574       off = 0;
00575     }
00576   pos = connection->response->first_header;
00577   while (pos != NULL)
00578     {
00579       if (pos->kind == kind)
00580         size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */
00581       pos = pos->next;
00582     }
00583   /* produce data */
00584   data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
00585   if (data == NULL)
00586     {
00587 #if HAVE_MESSAGES
00588       MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
00589 #endif
00590       return MHD_NO;
00591     }
00592   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00593     {
00594       memcpy (data, code, off);
00595     }
00596   pos = connection->response->first_header;
00597   while (pos != NULL)
00598     {
00599       if (pos->kind == kind)
00600         off += SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value);
00601       pos = pos->next;
00602     }
00603   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00604     {
00605       strcpy (&data[off], date);
00606       off += strlen (date);
00607     }
00608   memcpy (&data[off], "\r\n", 2);
00609   off += 2;
00610   if (off != size)
00611     abort ();
00612   connection->write_buffer = data;
00613   connection->write_buffer_append_offset = size;
00614   connection->write_buffer_send_offset = 0;
00615   connection->write_buffer_size = size + 1;
00616   return MHD_YES;
00617 }
00618 
00626 static void
00627 transmit_error_response (struct MHD_Connection *connection,
00628                          unsigned int status_code, const char *message)
00629 {
00630   struct MHD_Response *response;
00631 
00632   /* die, header far too long to be reasonable */
00633   connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00634   connection->read_closed = MHD_YES;
00635 #if HAVE_MESSAGES
00636   MHD_DLOG (connection->daemon,
00637             "Error %u (`%s') processing request, closing connection.\n",
00638             status_code, message);
00639 #endif
00640   response = MHD_create_response_from_data (strlen (message),
00641                                             (void *) message, MHD_NO, MHD_NO);
00642   MHD_queue_response (connection, status_code, response);
00643   EXTRA_CHECK (connection->response != NULL);
00644   MHD_destroy_response (response);
00645   if (MHD_NO == build_header_response (connection))
00646     {
00647       /* oops - close! */
00648 #if HAVE_MESSAGES
00649       MHD_DLOG (connection->daemon,
00650                 "Closing connection (failed to create response header)\n");
00651 #endif
00652       connection->state = MHD_CONNECTION_CLOSED;
00653     }
00654   else
00655     {
00656       connection->state = MHD_CONNECTION_HEADERS_SENDING;
00657     }
00658 }
00659 
00664 static void
00665 do_fd_set (int fd, fd_set * set, int *max_fd)
00666 {
00667   FD_SET (fd, set);
00668   if (fd > *max_fd)
00669     *max_fd = fd;
00670 }
00671 
00677 int
00678 MHD_connection_get_fdset (struct MHD_Connection *connection,
00679                           fd_set * read_fd_set,
00680                           fd_set * write_fd_set,
00681                           fd_set * except_fd_set, int *max_fd)
00682 {
00683   int fd;
00684 
00685   if (connection->pool == NULL)
00686     connection->pool = MHD_pool_create (connection->daemon->pool_size);
00687   if (connection->pool == NULL)
00688     {
00689 #if HAVE_MESSAGES
00690       MHD_DLOG (connection->daemon, "Failed to create memory pool!\n");
00691 #endif
00692       connection_close_error (connection);
00693       return MHD_NO;
00694     }
00695   fd = connection->socket_fd;
00696   if (fd == -1)
00697     return MHD_YES;
00698   while (1)
00699     {
00700 #if DEBUG_STATES
00701       MHD_DLOG (connection->daemon, "%s: state: %s\n",
00702                 __FUNCTION__, MHD_state_to_string (connection->state));
00703 #endif
00704       switch (connection->state)
00705         {
00706         case MHD_CONNECTION_INIT:
00707         case MHD_CONNECTION_URL_RECEIVED:
00708         case MHD_CONNECTION_HEADER_PART_RECEIVED:
00709 #if HTTPS_SUPPORT
00710         case MHD_TLS_CONNECTION_INIT:
00711 #endif
00712           /* while reading headers, we always grow the
00713              read buffer if needed, no size-check required */
00714           if ((connection->read_closed) &&
00715               (connection->read_buffer_offset == 0))
00716             {
00717               connection->state = MHD_CONNECTION_CLOSED;
00718               continue;
00719             }
00720           if ((connection->read_buffer_offset == connection->read_buffer_size)
00721               && (MHD_NO == try_grow_read_buffer (connection)))
00722             {
00723               transmit_error_response (connection,
00724                                        (connection->url != NULL)
00725                                        ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00726                                        : MHD_HTTP_REQUEST_URI_TOO_LONG,
00727                                        REQUEST_TOO_BIG);
00728               continue;
00729             }
00730           if (MHD_NO == connection->read_closed)
00731             do_fd_set (fd, read_fd_set, max_fd);
00732           break;
00733         case MHD_CONNECTION_HEADERS_RECEIVED:
00734           /* we should never get here */
00735           EXTRA_CHECK (0);
00736           break;
00737         case MHD_CONNECTION_HEADERS_PROCESSED:
00738           EXTRA_CHECK (0);
00739           break;
00740         case MHD_CONNECTION_CONTINUE_SENDING:
00741           do_fd_set (fd, write_fd_set, max_fd);
00742           break;
00743         case MHD_CONNECTION_CONTINUE_SENT:
00744           if (connection->read_buffer_offset == connection->read_buffer_size)
00745             {
00746               if ((MHD_YES != try_grow_read_buffer (connection)) &&
00747                   (0 != (connection->daemon->options &
00748                          (MHD_USE_SELECT_INTERNALLY |
00749                           MHD_USE_THREAD_PER_CONNECTION))))
00750                 {
00751                   /* failed to grow the read buffer, and the
00752                      client which is supposed to handle the
00753                      received data in a *blocking* fashion
00754                      (in this mode) did not handle the data as
00755                      it was supposed to!
00756                      => we would either have to do busy-waiting
00757                      (on the client, which would likely fail),
00758                      or if we do nothing, we would just timeout
00759                      on the connection (if a timeout is even
00760                      set!).
00761                      Solution: we kill the connection with an error */
00762                   transmit_error_response (connection,
00763                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
00764                                            INTERNAL_ERROR);
00765                   continue;
00766                 }
00767             }
00768           if ((connection->read_buffer_offset < connection->read_buffer_size)
00769               && (MHD_NO == connection->read_closed))
00770             do_fd_set (fd, read_fd_set, max_fd);
00771           break;
00772         case MHD_CONNECTION_BODY_RECEIVED:
00773         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
00774           /* while reading footers, we always grow the
00775              read buffer if needed, no size-check required */
00776           if (MHD_YES == connection->read_closed)
00777             {
00778               connection->state = MHD_CONNECTION_CLOSED;
00779               continue;
00780             }
00781           do_fd_set (fd, read_fd_set, max_fd);
00782           /* transition to FOOTERS_RECEIVED
00783              happens in read handler */
00784           break;
00785         case MHD_CONNECTION_FOOTERS_RECEIVED:
00786           /* no socket action, wait for client
00787              to provide response */
00788           break;
00789         case MHD_CONNECTION_HEADERS_SENDING:
00790           /* headers in buffer, keep writing */
00791           do_fd_set (fd, write_fd_set, max_fd);
00792           break;
00793         case MHD_CONNECTION_HEADERS_SENT:
00794           EXTRA_CHECK (0);
00795           break;
00796         case MHD_CONNECTION_NORMAL_BODY_READY:
00797           do_fd_set (fd, write_fd_set, max_fd);
00798           break;
00799         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
00800           /* not ready, no socket action */
00801           break;
00802         case MHD_CONNECTION_CHUNKED_BODY_READY:
00803           do_fd_set (fd, write_fd_set, max_fd);
00804           break;
00805         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
00806           /* not ready, no socket action */
00807           break;
00808         case MHD_CONNECTION_BODY_SENT:
00809           EXTRA_CHECK (0);
00810           break;
00811         case MHD_CONNECTION_FOOTERS_SENDING:
00812           do_fd_set (fd, write_fd_set, max_fd);
00813           break;
00814         case MHD_CONNECTION_FOOTERS_SENT:
00815           EXTRA_CHECK (0);
00816           break;
00817         case MHD_CONNECTION_CLOSED:
00818           if (connection->socket_fd != -1)
00819             connection_close_error (connection);
00820           return MHD_YES;       /* do nothing, not even reading */
00821 
00822         default:
00823           EXTRA_CHECK (0);
00824         }
00825       break;
00826     }
00827   return MHD_YES;
00828 }
00829 
00838 static char *
00839 get_next_header_line (struct MHD_Connection *connection)
00840 {
00841   char *rbuf;
00842   size_t pos;
00843 
00844   if (connection->read_buffer_offset == 0)
00845     return NULL;
00846   pos = 0;
00847   rbuf = connection->read_buffer;
00848   while ((pos < connection->read_buffer_offset - 1) &&
00849          (rbuf[pos] != '\r') && (rbuf[pos] != '\n'))
00850     pos++;
00851   if (pos == connection->read_buffer_offset - 1)
00852     {
00853       /* not found, consider growing... */
00854       if (connection->read_buffer_offset == connection->read_buffer_size)
00855         {
00856           rbuf = MHD_pool_reallocate (connection->pool,
00857                                       connection->read_buffer,
00858                                       connection->read_buffer_size,
00859                                       connection->read_buffer_size * 2 +
00860                                       MHD_BUF_INC_SIZE);
00861           if (rbuf == NULL)
00862             {
00863               transmit_error_response (connection,
00864                                        (connection->url != NULL)
00865                                        ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00866                                        : MHD_HTTP_REQUEST_URI_TOO_LONG,
00867                                        REQUEST_TOO_BIG);
00868             }
00869           else
00870             {
00871               connection->read_buffer_size =
00872                 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00873               connection->read_buffer = rbuf;
00874             }
00875         }
00876       return NULL;
00877     }
00878   /* found, check if we have proper CRLF */
00879   if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n'))
00880     rbuf[pos++] = '\0';         /* skip both r and n */
00881   rbuf[pos++] = '\0';
00882   connection->read_buffer += pos;
00883   connection->read_buffer_size -= pos;
00884   connection->read_buffer_offset -= pos;
00885   return rbuf;
00886 }
00887 
00891 static int
00892 connection_add_header (struct MHD_Connection *connection,
00893                        char *key, char *value, enum MHD_ValueKind kind)
00894 {
00895   struct MHD_HTTP_Header *hdr;
00896 
00897   hdr = MHD_pool_allocate (connection->pool,
00898                            sizeof (struct MHD_HTTP_Header), MHD_YES);
00899   if (hdr == NULL)
00900     {
00901 #if HAVE_MESSAGES
00902       MHD_DLOG (connection->daemon,
00903                 "Not enough memory to allocate header record!\n");
00904 #endif
00905       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00906                                REQUEST_TOO_BIG);
00907       return MHD_NO;
00908     }
00909   hdr->next = connection->headers_received;
00910   hdr->header = key;
00911   hdr->value = value;
00912   hdr->kind = kind;
00913   connection->headers_received = hdr;
00914   return MHD_YES;
00915 }
00916 
00920 static int
00921 parse_arguments (enum MHD_ValueKind kind,
00922                  struct MHD_Connection *connection, char *args)
00923 {
00924   char *equals;
00925   char *amper;
00926 
00927   while (args != NULL)
00928     {
00929       equals = strstr (args, "=");
00930       if (equals == NULL)
00931         return MHD_NO;          /* invalid, ignore */
00932       equals[0] = '\0';
00933       equals++;
00934       amper = strstr (equals, "&");
00935       if (amper != NULL)
00936         {
00937           amper[0] = '\0';
00938           amper++;
00939         }
00940       MHD_http_unescape (args);
00941       MHD_http_unescape (equals);
00942       if (MHD_NO == connection_add_header (connection, args, equals, kind))
00943         return MHD_NO;
00944       args = amper;
00945     }
00946   return MHD_YES;
00947 }
00948 
00954 static int
00955 parse_cookie_header (struct MHD_Connection *connection)
00956 {
00957   const char *hdr;
00958   char *cpy;
00959   char *pos;
00960   char *sce;
00961   char *semicolon;
00962   char *equals;
00963   char *ekill;
00964   char old;
00965   int quotes;
00966 
00967   hdr = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, "Cookie");
00968   if (hdr == NULL)
00969     return MHD_YES;
00970   cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
00971   if (cpy == NULL)
00972     {
00973 #if HAVE_MESSAGES
00974       MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
00975 #endif
00976       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
00977                                REQUEST_TOO_BIG);
00978       return MHD_NO;
00979     }
00980   memcpy (cpy, hdr, strlen (hdr) + 1);
00981   pos = cpy;
00982   while (pos != NULL)
00983     {
00984       while (*pos == ' ')
00985         pos++;                  /* skip spaces */
00986 
00987       sce = pos;
00988       while (((*sce) != '\0') &&
00989              ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
00990         sce++;
00991       /* remove tailing whitespace (if any) from key */
00992       ekill = sce - 1;
00993       while ((*ekill == ' ') && (ekill >= pos))
00994         *(ekill--) = '\0';
00995       old = *sce;
00996       *sce = '\0';
00997       if (old != '=')
00998         {
00999           /* value part omitted, use empty string... */
01000           if (MHD_NO ==
01001               connection_add_header (connection, pos, "", MHD_COOKIE_KIND))
01002             return MHD_NO;
01003           if (old == '\0')
01004             break;
01005           pos = sce + 1;
01006           continue;
01007         }
01008       equals = sce + 1;
01009       quotes = 0;
01010       semicolon = equals;
01011       while ((semicolon[0] != '\0') &&
01012              ((quotes != 0) ||
01013               ((semicolon[0] != ';') && (semicolon[0] != ','))))
01014         {
01015           if (semicolon[0] == '"')
01016             quotes = (quotes + 1) & 1;
01017           semicolon++;
01018         }
01019       if (semicolon[0] == '\0')
01020         semicolon = NULL;
01021       if (semicolon != NULL)
01022         {
01023           semicolon[0] = '\0';
01024           semicolon++;
01025         }
01026       /* remove quotes */
01027       if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
01028         {
01029           equals[strlen (equals) - 1] = '\0';
01030           equals++;
01031         }
01032       if (MHD_NO == connection_add_header (connection,
01033                                            pos, equals, MHD_COOKIE_KIND))
01034         return MHD_NO;
01035       pos = semicolon;
01036     }
01037   return MHD_YES;
01038 }
01039 
01047 static int
01048 parse_initial_message_line (struct MHD_Connection *connection, char *line)
01049 {
01050   char *uri;
01051   char *httpVersion;
01052   char *args;
01053 
01054   uri = strstr (line, " ");
01055   if (uri == NULL)
01056     return MHD_NO;              /* serious error */
01057   uri[0] = '\0';
01058   connection->method = line;
01059   uri++;
01060   while (uri[0] == ' ')
01061     uri++;
01062   httpVersion = strstr (uri, " ");
01063   if (httpVersion != NULL)
01064     {
01065       httpVersion[0] = '\0';
01066       httpVersion++;
01067     }
01068   if (connection->daemon->uri_log_callback != NULL)
01069     connection->client_context
01070       =
01071       connection->daemon->uri_log_callback (connection->daemon->
01072                                             uri_log_callback_cls, uri);
01073   args = strstr (uri, "?");
01074   if (args != NULL)
01075     {
01076       args[0] = '\0';
01077       args++;
01078       parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
01079     }
01080   MHD_http_unescape (uri);
01081   connection->url = uri;
01082   if (httpVersion == NULL)
01083     connection->version = "";
01084   else
01085     connection->version = httpVersion;
01086   return MHD_YES;
01087 }
01088 
01094 static void
01095 call_connection_handler (struct MHD_Connection *connection)
01096 {
01097   size_t processed;
01098   size_t available;
01099   size_t used;
01100   size_t i;
01101   int instant_retry;
01102   int malformed;
01103   char *buffer_head;
01104 
01105   if (connection->response != NULL)
01106     return;                     /* already queued a response */
01107 
01108   buffer_head = connection->read_buffer;
01109   available = connection->read_buffer_offset;
01110   do
01111     {
01112       instant_retry = MHD_NO;
01113       if ((connection->have_chunked_upload == MHD_YES) &&
01114           (connection->remaining_upload_size == MHD_SIZE_UNKNOWN))
01115         {
01116           if ((connection->current_chunk_offset ==
01117                connection->current_chunk_size)
01118               && (connection->current_chunk_offset != 0) && (available >= 2))
01119             {
01120               /* skip new line at the *end* of a chunk */
01121               i = 0;
01122               if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01123                 i++;            /* skip 1st part of line feed */
01124               if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01125                 i++;            /* skip 2nd part of line feed */
01126               if (i == 0)
01127                 {
01128                   /* malformed encoding */
01129 #if HAVE_MESSAGES
01130                   MHD_DLOG (connection->daemon,
01131                             "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01132 #endif
01133                   connection_close_error (connection);
01134                   return;
01135                 }
01136               available -= i;
01137               buffer_head += i;
01138               connection->current_chunk_offset = 0;
01139               connection->current_chunk_size = 0;
01140             }
01141           if (connection->current_chunk_offset <
01142               connection->current_chunk_size)
01143             {
01144               /* we are in the middle of a chunk, give
01145                  as much as possible to the client (without
01146                  crossing chunk boundaries) */
01147               processed =
01148                 connection->current_chunk_size -
01149                 connection->current_chunk_offset;
01150               if (processed > available)
01151                 processed = available;
01152               if (available > processed)
01153                 instant_retry = MHD_YES;
01154             }
01155           else
01156             {
01157               /* we need to read chunk boundaries */
01158               i = 0;
01159               while (i < available)
01160                 {
01161                   if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01162                     break;
01163                   i++;
01164                   if (i >= 6)
01165                     break;
01166                 }
01167               /* take '\n' into account; if '\n'
01168                  is the unavailable character, we
01169                  will need to wait until we have it
01170                  before going further */
01171               if ((i + 1 >= available) &&
01172                   !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
01173                 break;          /* need more data... */
01174               malformed = (i >= 6);
01175               if (!malformed)
01176                 {
01177                   buffer_head[i] = '\0';
01178                   malformed =
01179                     (1 != SSCANF (buffer_head, "%X",
01180                                   &connection->current_chunk_size)) &&
01181                     (1 != SSCANF (buffer_head, "%x",
01182                                   &connection->current_chunk_size));
01183                 }
01184               if (malformed)
01185                 {
01186                   /* malformed encoding */
01187 #if HAVE_MESSAGES
01188                   MHD_DLOG (connection->daemon,
01189                             "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01190 #endif
01191                   connection_close_error (connection);
01192                   return;
01193                 }
01194               i++;
01195               if ((i < available) &&
01196                   ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
01197                 i++;            /* skip 2nd part of line feed */
01198 
01199               buffer_head += i;
01200               available -= i;
01201               connection->current_chunk_offset = 0;
01202 
01203               if (available > 0)
01204                 instant_retry = MHD_YES;
01205               if (connection->current_chunk_size == 0)
01206                 {
01207                   connection->remaining_upload_size = 0;
01208                   break;
01209                 }
01210               continue;
01211             }
01212         }
01213       else
01214         {
01215           /* no chunked encoding, give all to the client */
01216           processed = available;
01217         }
01218       used = processed;
01219       connection->client_aware = MHD_YES;
01220       if (MHD_NO ==
01221           connection->daemon->default_handler (connection->daemon->
01222                                                default_handler_cls,
01223                                                connection, connection->url,
01224                                                connection->method,
01225                                                connection->version,
01226                                                buffer_head, &processed,
01227                                                &connection->client_context))
01228         {
01229           /* serious internal error, close connection */
01230 #if HAVE_MESSAGES
01231           MHD_DLOG (connection->daemon,
01232                     "Internal application error, closing connection.\n");
01233 #endif
01234           connection_close_error (connection);
01235           return;
01236         }
01237       if (processed > used)
01238         abort ();               /* fatal client API violation! */
01239       if (processed != 0)
01240         instant_retry = MHD_NO; /* client did not process everything */
01241       used -= processed;
01242       if (connection->have_chunked_upload == MHD_YES)
01243         connection->current_chunk_offset += used;
01244       /* dh left "processed" bytes in buffer for next time... */
01245       buffer_head += used;
01246       available -= used;
01247       if (connection->remaining_upload_size != MHD_SIZE_UNKNOWN)
01248         connection->remaining_upload_size -= used;
01249     }
01250   while (instant_retry == MHD_YES);
01251   if (available > 0)
01252     memmove (connection->read_buffer, buffer_head, available);
01253   connection->read_buffer_offset = available;
01254 }
01255 
01264 static int
01265 do_read (struct MHD_Connection *connection)
01266 {
01267   int bytes_read;
01268 
01269   if (connection->read_buffer_size == connection->read_buffer_offset)
01270     return MHD_NO;
01271 
01272   bytes_read = connection->recv_cls (connection,
01273                                      &connection->read_buffer
01274                                      [connection->read_buffer_offset],
01275                                      connection->read_buffer_size -
01276                                      connection->read_buffer_offset);
01277   if (bytes_read < 0)
01278     {
01279       if (errno == EINTR)
01280         return MHD_NO;
01281 #if HAVE_MESSAGES
01282       MHD_DLOG (connection->daemon,
01283                 "Failed to receive data: %s\n", STRERROR (errno));
01284 #endif
01285       connection_close_error (connection);
01286       return MHD_YES;
01287     }
01288   if (bytes_read == 0)
01289     {
01290       /* other side closed connection */
01291       connection->read_closed = MHD_YES;
01292       SHUTDOWN (connection->socket_fd, SHUT_RD);
01293       return MHD_NO;
01294     }
01295   connection->read_buffer_offset += bytes_read;
01296   return MHD_YES;
01297 }
01298 
01306 static int
01307 do_write (struct MHD_Connection *connection)
01308 {
01309   int ret;
01310 
01311   ret = connection->send_cls (connection,
01312                               &connection->write_buffer
01313                               [connection->write_buffer_send_offset],
01314                               connection->write_buffer_append_offset
01315                               - connection->write_buffer_send_offset);
01316 
01317   if (ret < 0)
01318     {
01319       if (errno == EINTR)
01320         return MHD_NO;
01321 #if HAVE_MESSAGES
01322       MHD_DLOG (connection->daemon,
01323                 "Failed to send data: %s\n", STRERROR (errno));
01324 #endif
01325       connection_close_error (connection);
01326       return MHD_YES;
01327     }
01328 #if DEBUG_SEND_DATA
01329   FPRINTF (stderr,
01330            "Sent response: `%.*s'\n",
01331            ret,
01332            &connection->write_buffer[connection->write_buffer_send_offset]);
01333 #endif
01334   connection->write_buffer_send_offset += ret;
01335   return MHD_YES;
01336 }
01337 
01343 static int
01344 check_write_done (struct MHD_Connection *connection,
01345                   enum MHD_CONNECTION_STATE next_state)
01346 {
01347   if (connection->write_buffer_append_offset !=
01348       connection->write_buffer_send_offset)
01349     return MHD_NO;
01350   connection->write_buffer_append_offset = 0;
01351   connection->write_buffer_send_offset = 0;
01352   connection->state = next_state;
01353   MHD_pool_reallocate (connection->pool, connection->write_buffer,
01354                        connection->write_buffer_size, 0);
01355   connection->write_buffer = NULL;
01356   connection->write_buffer_size = 0;
01357   return MHD_YES;
01358 }
01359 
01365 static int
01366 process_header_line (struct MHD_Connection *connection, char *line)
01367 {
01368   char *colon;
01369 
01370   /* line should be normal header line, find colon */
01371   colon = strstr (line, ":");
01372   if (colon == NULL)
01373     {
01374       /* error in header line, die hard */
01375 #if HAVE_MESSAGES
01376       MHD_DLOG (connection->daemon,
01377                 "Received malformed line (no colon), closing connection.\n");
01378 #endif
01379       connection->state = MHD_CONNECTION_CLOSED;
01380       return MHD_NO;
01381     }
01382   /* zero-terminate header */
01383   colon[0] = '\0';
01384   colon++;                      /* advance to value */
01385   while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
01386     colon++;
01387   /* we do the actual adding of the connection
01388      header at the beginning of the while
01389      loop since we need to be able to inspect
01390      the *next* header line (in case it starts
01391      with a space...) */
01392   connection->last = line;
01393   connection->colon = colon;
01394   return MHD_YES;
01395 }
01396 
01406 static int
01407 process_broken_line (struct MHD_Connection *connection,
01408                      char *line, enum MHD_ValueKind kind)
01409 {
01410   char *last;
01411   char *tmp;
01412 
01413   last = connection->last;
01414   if ((line[0] == ' ') || (line[0] == '\t'))
01415     {
01416       /* value was continued on the next line, see
01417          http://www.jmarshall.com/easy/http/ */
01418       last = MHD_pool_reallocate (connection->pool,
01419                                   last,
01420                                   strlen (last) + 1,
01421                                   strlen (line) + strlen (last) + 1);
01422       if (last == NULL)
01423         {
01424           transmit_error_response (connection,
01425                                    MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01426                                    REQUEST_TOO_BIG);
01427           return MHD_NO;
01428         }
01429       tmp = line;
01430       while ((tmp[0] == ' ') || (tmp[0] == '\t'))
01431         tmp++;                  /* skip whitespace at start of 2nd line */
01432       strcat (last, tmp);
01433       connection->last = last;
01434       return MHD_YES;           /* possibly more than 2 lines... */
01435     }
01436   EXTRA_CHECK ((last != NULL) && (connection->colon != NULL));
01437   if ((MHD_NO == connection_add_header (connection,
01438                                         last, connection->colon, kind)))
01439     {
01440       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01441                                REQUEST_TOO_BIG);
01442       return MHD_NO;
01443     }
01444   /* we still have the current line to deal with... */
01445   if (strlen (line) != 0)
01446     {
01447       if (MHD_NO == process_header_line (connection, line))
01448         {
01449           transmit_error_response (connection,
01450                                    MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED);
01451           return MHD_NO;
01452         }
01453     }
01454   return MHD_YES;
01455 }
01456 
01462 static void
01463 parse_connection_headers (struct MHD_Connection *connection)
01464 {
01465   const char *clen;
01466   unsigned long long cval;
01467   struct MHD_Response *response;
01468 
01469   parse_cookie_header (connection);
01470   if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
01471       && (NULL != connection->version)
01472       && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
01473       && (NULL ==
01474           MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
01475                                        MHD_HTTP_HEADER_HOST)))
01476     {
01477       /* die, http 1.1 request without host and we are pedantic */
01478       connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01479       connection->read_closed = MHD_YES;
01480 #if HAVE_MESSAGES
01481       MHD_DLOG (connection->daemon,
01482                 "Received `%s' request without `%s' header.\n",
01483                 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
01484 #endif
01485       response =
01486         MHD_create_response_from_data (strlen (REQUEST_LACKS_HOST),
01487                                        REQUEST_LACKS_HOST, MHD_NO, MHD_NO);
01488       MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
01489       MHD_destroy_response (response);
01490       return;
01491     }
01492 
01493   clen = MHD_lookup_connection_value (connection,
01494                                       MHD_HEADER_KIND,
01495                                       MHD_HTTP_HEADER_CONTENT_LENGTH);
01496   if (clen != NULL)
01497     {
01498       if (1 != SSCANF (clen, "%llu", &cval))
01499         {
01500 #if HAVE_MESSAGES
01501           MHD_DLOG (connection->daemon,
01502                     "Failed to parse `%s' header `%s', closing connection.\n",
01503                     MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
01504 #endif
01505           connection->state = MHD_CONNECTION_CLOSED;
01506           return;
01507         }
01508       connection->remaining_upload_size = cval;
01509     }
01510   else
01511     {
01512       if (NULL == MHD_lookup_connection_value (connection,
01513                                                MHD_HEADER_KIND,
01514                                                MHD_HTTP_HEADER_TRANSFER_ENCODING))
01515         {
01516           /* this request does not have a body */
01517           connection->remaining_upload_size = 0;
01518         }
01519       else
01520         {
01521           connection->remaining_upload_size = MHD_SIZE_UNKNOWN;
01522           if (0 ==
01523               strcasecmp (MHD_lookup_connection_value
01524                           (connection, MHD_HEADER_KIND,
01525                            MHD_HTTP_HEADER_TRANSFER_ENCODING), "chunked"))
01526             connection->have_chunked_upload = MHD_YES;
01527         }
01528     }
01529 }
01530 
01540 int
01541 MHD_connection_handle_read (struct MHD_Connection *connection)
01542 {
01543   connection->last_activity = time (NULL);
01544   if (connection->state == MHD_CONNECTION_CLOSED)
01545     return MHD_NO;
01546   /* make sure "read" has a reasonable number of bytes
01547      in buffer to use per system call (if possible) */
01548   if (connection->read_buffer_offset + MHD_BUF_INC_SIZE >
01549       connection->read_buffer_size)
01550     try_grow_read_buffer (connection);
01551   if (MHD_NO == do_read (connection))
01552     return MHD_YES;
01553   while (1)
01554     {
01555 #if DEBUG_STATES
01556       MHD_DLOG (connection->daemon, "%s: state: %s\n",
01557                 __FUNCTION__, MHD_state_to_string (connection->state));
01558 #endif
01559       switch (connection->state)
01560         {
01561         case MHD_CONNECTION_INIT:
01562         case MHD_CONNECTION_URL_RECEIVED:
01563         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01564         case MHD_CONNECTION_HEADERS_RECEIVED:
01565         case MHD_CONNECTION_HEADERS_PROCESSED:
01566         case MHD_CONNECTION_CONTINUE_SENDING:
01567         case MHD_CONNECTION_CONTINUE_SENT:
01568         case MHD_CONNECTION_BODY_RECEIVED:
01569         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01570           /* nothing to do but default action */
01571           if (MHD_YES == connection->read_closed)
01572             {
01573               connection->state = MHD_CONNECTION_CLOSED;
01574               continue;
01575             }
01576           break;
01577         case MHD_CONNECTION_CLOSED:
01578           if (connection->socket_fd != -1)
01579             connection_close_error (connection);
01580           return MHD_NO;
01581         default:
01582           /* shrink read buffer to how much is actually used */
01583           MHD_pool_reallocate (connection->pool,
01584                                connection->read_buffer,
01585                                connection->read_buffer_size + 1,
01586                                connection->read_buffer_offset);
01587           break;
01588         }
01589       break;
01590     }
01591   return MHD_YES;
01592 }
01593 
01603 int
01604 MHD_connection_handle_write (struct MHD_Connection *connection)
01605 {
01606   struct MHD_Response *response;
01607   int ret;
01608   connection->last_activity = time (NULL);
01609   while (1)
01610     {
01611 #if DEBUG_STATES
01612       MHD_DLOG (connection->daemon, "%s: state: %s\n",
01613                 __FUNCTION__, MHD_state_to_string (connection->state));
01614 #endif
01615       switch (connection->state)
01616         {
01617         case MHD_CONNECTION_INIT:
01618         case MHD_CONNECTION_URL_RECEIVED:
01619         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01620         case MHD_CONNECTION_HEADERS_RECEIVED:
01621           EXTRA_CHECK (0);
01622           break;
01623         case MHD_CONNECTION_HEADERS_PROCESSED:
01624           break;
01625         case MHD_CONNECTION_CONTINUE_SENDING:
01626           ret = connection->send_cls (connection,
01627                                       &HTTP_100_CONTINUE
01628                                       [connection->continue_message_write_offset],
01629                                       strlen (HTTP_100_CONTINUE) -
01630                                       connection->continue_message_write_offset);
01631           if (ret < 0)
01632             {
01633               if (errno == EINTR)
01634                 break;
01635 #if HAVE_MESSAGES
01636               MHD_DLOG (connection->daemon,
01637                         "Failed to send data: %s\n", STRERROR (errno));
01638 #endif
01639               connection_close_error (connection);
01640               return MHD_NO;
01641             }
01642 #if DEBUG_SEND_DATA
01643           FPRINTF (stderr,
01644                    "Sent 100 continue response: `%.*s'\n",
01645                    ret,
01646                    &HTTP_100_CONTINUE
01647                    [connection->continue_message_write_offset]);
01648 #endif
01649           connection->continue_message_write_offset += ret;
01650           break;
01651         case MHD_CONNECTION_CONTINUE_SENT:
01652         case MHD_CONNECTION_BODY_RECEIVED:
01653         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01654         case MHD_CONNECTION_FOOTERS_RECEIVED:
01655           EXTRA_CHECK (0);
01656           break;
01657         case MHD_CONNECTION_HEADERS_SENDING:
01658           do_write (connection);
01659           check_write_done (connection, MHD_CONNECTION_HEADERS_SENT);
01660           break;
01661         case MHD_CONNECTION_HEADERS_SENT:
01662           EXTRA_CHECK (0);
01663           break;
01664         case MHD_CONNECTION_NORMAL_BODY_READY:
01665           response = connection->response;
01666           if (response->crc != NULL)
01667             pthread_mutex_lock (&response->mutex);
01668           if (MHD_YES != try_ready_normal_body (connection))
01669             {
01670               if (response->crc != NULL)
01671                 pthread_mutex_unlock (&response->mutex);
01672               connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
01673               break;
01674             }
01675 #if HTTPS_SUPPORT
01676           if (connection->daemon->options & MHD_USE_SSL)
01677             {
01678               ret = MHD__gnutls_record_send (connection->tls_session,
01679                                              &connection->response->data
01680                                              [connection->
01681                                               response_write_position -
01682                                               response->data_start],
01683                                              response->data_size -
01684                                              (connection->response_write_position
01685                                               - response->data_start));
01686             }
01687           else
01688 #endif
01689             {
01690               ret = connection->send_cls (connection,
01691                                           &response->data
01692                                           [connection->response_write_position
01693                                            - response->data_start],
01694                                           response->data_size -
01695                                           (connection->response_write_position
01696                                            - response->data_start));
01697             }
01698 #if DEBUG_SEND_DATA
01699           if (ret > 0)
01700             FPRINTF (stderr,
01701                      "Sent DATA response: `%.*s'\n",
01702                      ret,
01703                      &response->data[connection->response_write_position -
01704                                      response->data_start]);
01705 #endif
01706           if (response->crc != NULL)
01707             pthread_mutex_unlock (&response->mutex);
01708           if (ret < 0)
01709             {
01710               if (errno == EINTR)
01711                 return MHD_YES;
01712 #if HAVE_MESSAGES
01713               MHD_DLOG (connection->daemon,
01714                         "Failed to send data: %s\n", STRERROR (errno));
01715 #endif
01716               connection_close_error (connection);
01717               return MHD_NO;
01718             }
01719           connection->response_write_position += ret;
01720           if (connection->response_write_position ==
01721               connection->response->total_size)
01722             connection->state = MHD_CONNECTION_FOOTERS_SENT;    /* have no footers... */
01723           break;
01724         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01725           EXTRA_CHECK (0);
01726           break;
01727         case MHD_CONNECTION_CHUNKED_BODY_READY:
01728           do_write (connection);
01729           check_write_done (connection,
01730                             (connection->response->total_size ==
01731                              connection->response_write_position) ?
01732                             MHD_CONNECTION_BODY_SENT :
01733                             MHD_CONNECTION_CHUNKED_BODY_UNREADY);
01734           break;
01735         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
01736         case MHD_CONNECTION_BODY_SENT:
01737           EXTRA_CHECK (0);
01738           break;
01739         case MHD_CONNECTION_FOOTERS_SENDING:
01740           do_write (connection);
01741           check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT);
01742           break;
01743         case MHD_CONNECTION_FOOTERS_SENT:
01744           EXTRA_CHECK (0);
01745           break;
01746         case MHD_CONNECTION_CLOSED:
01747           if (connection->socket_fd != -1)
01748             connection_close_error (connection);
01749           return MHD_NO;
01750         case MHD_TLS_CONNECTION_INIT:
01751         case MHD_TLS_HELLO_REQUEST:
01752         case MHD_TLS_HANDSHAKE_FAILED:
01753           EXTRA_CHECK (0);
01754           break;
01755         default:
01756           EXTRA_CHECK (0);
01757           connection_close_error (connection);
01758           return MHD_NO;
01759         }
01760       break;
01761     }
01762   return MHD_YES;
01763 }
01764 
01774 int
01775 MHD_connection_handle_idle (struct MHD_Connection *connection)
01776 {
01777   unsigned int timeout;
01778   const char *end;
01779   char *line;
01780 
01781   while (1)
01782     {
01783 #if DEBUG_STATES
01784       MHD_DLOG (connection->daemon, "%s: state: %s\n",
01785                 __FUNCTION__, MHD_state_to_string (connection->state));
01786 #endif
01787       switch (connection->state)
01788         {
01789         case MHD_CONNECTION_INIT:
01790           line = get_next_header_line (connection);
01791           if (line == NULL)
01792             {
01793               if (connection->state != MHD_CONNECTION_INIT)
01794                 continue;
01795               if (connection->read_closed)
01796                 {
01797                   connection->state = MHD_CONNECTION_CLOSED;
01798                   continue;
01799                 }
01800               break;
01801             }
01802           if (MHD_NO == parse_initial_message_line (connection, line))
01803             connection->state = MHD_CONNECTION_CLOSED;
01804           else
01805             connection->state = MHD_CONNECTION_URL_RECEIVED;
01806           continue;
01807         case MHD_CONNECTION_URL_RECEIVED:
01808           line = get_next_header_line (connection);
01809           if (line == NULL)
01810             {
01811               if (connection->state != MHD_CONNECTION_URL_RECEIVED)
01812                 continue;
01813               if (connection->read_closed)
01814                 {
01815                   connection->state = MHD_CONNECTION_CLOSED;
01816                   continue;
01817                 }
01818               break;
01819             }
01820           if (strlen (line) == 0)
01821             {
01822               connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01823               continue;
01824             }
01825           if (MHD_NO == process_header_line (connection, line))
01826             {
01827               transmit_error_response (connection,
01828                                        MHD_HTTP_BAD_REQUEST,
01829                                        REQUEST_MALFORMED);
01830               break;
01831             }
01832           connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
01833           continue;
01834         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01835           line = get_next_header_line (connection);
01836           if (line == NULL)
01837             {
01838               if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
01839                 continue;
01840               if (connection->read_closed)
01841                 {
01842                   connection->state = MHD_CONNECTION_CLOSED;
01843                   continue;
01844                 }
01845               break;
01846             }
01847           if (MHD_NO ==
01848               process_broken_line (connection, line, MHD_HEADER_KIND))
01849             continue;
01850           if (strlen (line) == 0)
01851             {
01852               connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01853               continue;
01854             }
01855           continue;
01856         case MHD_CONNECTION_HEADERS_RECEIVED:
01857           parse_connection_headers (connection);
01858           if (connection->state == MHD_CONNECTION_CLOSED)
01859             continue;
01860           connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
01861           continue;
01862         case MHD_CONNECTION_HEADERS_PROCESSED:
01863           call_connection_handler (connection); /* first call */
01864           if (connection->state == MHD_CONNECTION_CLOSED)
01865             continue;
01866           if (need_100_continue (connection))
01867             {
01868               connection->state = MHD_CONNECTION_CONTINUE_SENDING;
01869               break;
01870             }
01871           if (connection->response != NULL)
01872             {
01873               /* we refused (no upload allowed!) */
01874               connection->remaining_upload_size = 0;
01875               /* force close, in case client still tries to upload... */
01876               connection->read_closed = MHD_YES;
01877             }
01878           connection->state = (connection->remaining_upload_size == 0)
01879             ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
01880           continue;
01881         case MHD_CONNECTION_CONTINUE_SENDING:
01882           if (connection->continue_message_write_offset ==
01883               strlen (HTTP_100_CONTINUE))
01884             {
01885               connection->state = MHD_CONNECTION_CONTINUE_SENT;
01886               continue;
01887             }
01888           break;
01889         case MHD_CONNECTION_CONTINUE_SENT:
01890           if (connection->read_buffer_offset != 0)
01891             {
01892               call_connection_handler (connection);     /* loop call */
01893               if (connection->state == MHD_CONNECTION_CLOSED)
01894                 continue;
01895             }
01896           if ((connection->remaining_upload_size == 0) ||
01897               ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) &&
01898                (connection->read_buffer_offset == 0) &&
01899                (MHD_YES == connection->read_closed)))
01900             {
01901               if ((MHD_YES == connection->have_chunked_upload) &&
01902                   (MHD_NO == connection->read_closed))
01903                 connection->state = MHD_CONNECTION_BODY_RECEIVED;
01904               else
01905                 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01906               continue;
01907             }
01908           break;
01909         case MHD_CONNECTION_BODY_RECEIVED:
01910           line = get_next_header_line (connection);
01911           if (line == NULL)
01912             {
01913               if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
01914                 continue;
01915               if (connection->read_closed)
01916                 {
01917                   connection->state = MHD_CONNECTION_CLOSED;
01918                   continue;
01919                 }
01920               break;
01921             }
01922           if (strlen (line) == 0)
01923             {
01924               connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01925               continue;
01926             }
01927           if (MHD_NO == process_header_line (connection, line))
01928             {
01929               transmit_error_response (connection,
01930                                        MHD_HTTP_BAD_REQUEST,
01931                                        REQUEST_MALFORMED);
01932               break;
01933             }
01934           connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
01935           continue;
01936         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01937           line = get_next_header_line (connection);
01938           if (line == NULL)
01939             {
01940               if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
01941                 continue;
01942               if (connection->read_closed)
01943                 {
01944                   connection->state = MHD_CONNECTION_CLOSED;
01945                   continue;
01946                 }
01947               break;
01948             }
01949           if (MHD_NO ==
01950               process_broken_line (connection, line, MHD_FOOTER_KIND))
01951             continue;
01952           if (strlen (line) == 0)
01953             {
01954               connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01955               continue;
01956             }
01957           continue;
01958         case MHD_CONNECTION_FOOTERS_RECEIVED:
01959           call_connection_handler (connection); /* "final" call */
01960           if (connection->state == MHD_CONNECTION_CLOSED)
01961             continue;
01962           if (connection->response == NULL)
01963             break;              /* try again next time */
01964           if (MHD_NO == build_header_response (connection))
01965             {
01966               /* oops - close! */
01967 #if HAVE_MESSAGES
01968               MHD_DLOG (connection->daemon,
01969                         "Closing connection (failed to create response header)\n");
01970 #endif
01971               connection->state = MHD_CONNECTION_CLOSED;
01972               continue;
01973             }
01974           connection->state = MHD_CONNECTION_HEADERS_SENDING;
01975 
01976 #if HAVE_DECL_TCP_CORK
01977           /* starting header send, set TCP cork */
01978           {
01979             const int val = 1;
01980             setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
01981                         sizeof (val));
01982           }
01983 #endif
01984           break;
01985         case MHD_CONNECTION_HEADERS_SENDING:
01986           /* no default action */
01987           break;
01988         case MHD_CONNECTION_HEADERS_SENT:
01989           if (connection->have_chunked_upload)
01990             connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
01991           else
01992             connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
01993           continue;
01994         case MHD_CONNECTION_NORMAL_BODY_READY:
01995           /* nothing to do here */
01996           break;
01997         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01998           if (connection->response->crc != NULL)
01999             pthread_mutex_lock (&connection->response->mutex);
02000           if (MHD_YES == try_ready_normal_body (connection))
02001             {
02002               if (connection->response->crc != NULL)
02003                 pthread_mutex_unlock (&connection->response->mutex);
02004               connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
02005               break;
02006             }
02007           if (connection->response->crc != NULL)
02008             pthread_mutex_unlock (&connection->response->mutex);
02009           /* not ready, no socket action */
02010           break;
02011         case MHD_CONNECTION_CHUNKED_BODY_READY:
02012           /* nothing to do here */
02013           break;
02014         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
02015           if (connection->response->crc != NULL)
02016             pthread_mutex_lock (&connection->response->mutex);
02017           if (MHD_YES == try_ready_chunked_body (connection))
02018             {
02019               if (connection->response->crc != NULL)
02020                 pthread_mutex_unlock (&connection->response->mutex);
02021               connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
02022               continue;
02023             }
02024           if (connection->response->crc != NULL)
02025             pthread_mutex_unlock (&connection->response->mutex);
02026           break;
02027         case MHD_CONNECTION_BODY_SENT:
02028           build_header_response (connection);
02029           if (connection->write_buffer_send_offset ==
02030               connection->write_buffer_append_offset)
02031             connection->state = MHD_CONNECTION_FOOTERS_SENT;
02032           else
02033             connection->state = MHD_CONNECTION_FOOTERS_SENDING;
02034           continue;
02035         case MHD_CONNECTION_FOOTERS_SENDING:
02036           /* no default action */
02037           break;
02038         case MHD_CONNECTION_FOOTERS_SENT:
02039 #if HAVE_DECL_TCP_CORK
02040           /* done sending, uncork */
02041           {
02042             const int val = 0;
02043             setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02044                         sizeof (val));
02045           }
02046 #endif
02047           MHD_destroy_response (connection->response);
02048           if (connection->daemon->notify_completed != NULL)
02049             {
02050               connection->daemon->notify_completed (connection->daemon->
02051                                                     notify_completed_cls,
02052                                                     connection,
02053                                                     &connection->client_context,
02054                                                     MHD_REQUEST_TERMINATED_COMPLETED_OK);
02055             }
02056           connection->client_aware = MHD_NO;
02057           end =
02058             MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
02059                                          MHD_HTTP_HEADER_CONNECTION);
02060           connection->client_context = NULL;
02061           connection->continue_message_write_offset = 0;
02062           connection->responseCode = 0;
02063           connection->response = NULL;
02064           connection->headers_received = NULL;
02065           connection->response_write_position = 0;
02066           connection->have_chunked_upload = MHD_NO;
02067           connection->method = NULL;
02068           connection->url = NULL;
02069           connection->write_buffer = NULL;
02070           connection->write_buffer_size = 0;
02071           connection->write_buffer_send_offset = 0;
02072           connection->write_buffer_append_offset = 0;
02073           if ((end != NULL) && (0 == strcasecmp (end, "close")))
02074             {
02075               connection->read_closed = MHD_YES;
02076               connection->read_buffer_offset = 0;
02077             }
02078           if (((MHD_YES == connection->read_closed) &&
02079                (0 == connection->read_buffer_offset)) ||
02080               (connection->version == NULL) ||
02081               (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
02082             {
02083               /* http 1.0, version-less requests cannot be pipelined */
02084               connection->state = MHD_CONNECTION_CLOSED;
02085               MHD_pool_destroy (connection->pool);
02086               connection->pool = NULL;
02087               connection->read_buffer = NULL;
02088               connection->read_buffer_size = 0;
02089               connection->read_buffer_offset = 0;
02090             }
02091           else
02092             {
02093               connection->version = NULL;
02094               connection->state = MHD_CONNECTION_INIT;
02095               connection->read_buffer
02096                 = MHD_pool_reset (connection->pool,
02097                                   connection->read_buffer,
02098                                   connection->read_buffer_size);
02099             }
02100           continue;
02101         case MHD_CONNECTION_CLOSED:
02102           if (connection->socket_fd != -1)
02103             connection_close_error (connection);
02104           break;
02105         default:
02106           EXTRA_CHECK (0);
02107           break;
02108         }
02109       break;
02110     }
02111   timeout = connection->daemon->connection_timeout;
02112   if ((connection->socket_fd != -1) &&
02113       (timeout != 0) && (time (NULL) - timeout > connection->last_activity))
02114     {
02115       MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
02116       return MHD_NO;
02117     }
02118   return MHD_YES;
02119 
02120 }
02121 
02122 void
02123 MHD_set_http_calbacks (struct MHD_Connection *connection)
02124 {
02125   connection->read_handler = &MHD_connection_handle_read;
02126   connection->write_handler = &MHD_connection_handle_write;
02127   connection->idle_handler = &MHD_connection_handle_idle;
02128 }
02129 
02130 #if HTTPS_SUPPORT
02131 #include "gnutls_int.h"
02132 #include "gnutls_record.h"
02133 #endif
02134 
02144 const union MHD_ConnectionInfo *
02145 MHD_get_connection_info (struct MHD_Connection *connection,
02146                          enum MHD_ConnectionInfoType infoType, ...)
02147 {
02148   switch (infoType)
02149     {
02150 #if HTTPS_SUPPORT
02151     case MHD_CONNECTION_INFO_CIPHER_ALGO:
02152       if (connection->tls_session == NULL)
02153         return NULL;
02154       return (const union MHD_ConnectionInfo *) &connection->
02155         tls_session->security_parameters.read_bulk_cipher_algorithm;
02156     case MHD_CONNECTION_INFO_PROTOCOL:
02157       if (connection->tls_session == NULL)
02158         return NULL;
02159       return (const union MHD_ConnectionInfo *) &connection->
02160         tls_session->security_parameters.version;
02161 #endif
02162     case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
02163       return (const union MHD_ConnectionInfo *) &connection->addr;
02164     default:
02165       return NULL;
02166     };
02167 }
02168 
02169 
02170 /* end of connection.c */

Generated by  doxygen 1.6.2