connection.c

Go to the documentation of this file.
00001 /*
00002     This file is part of libmicrohttpd
00003      (C) 2007, 2008, 2009, 2010, 2011, 2012 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 <limits.h>
00030 #include "connection.h"
00031 #include "memorypool.h"
00032 #include "response.h"
00033 #include "reason_phrase.h"
00034 
00035 #if HAVE_NETINET_TCP_H
00036 /* for TCP_CORK */
00037 #include <netinet/tcp.h>
00038 #endif
00039 
00043 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
00044 
00052 #if HAVE_MESSAGES
00053 #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>"
00054 #else
00055 #define REQUEST_TOO_BIG ""
00056 #endif
00057 
00065 #if HAVE_MESSAGES
00066 #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>"
00067 #else
00068 #define REQUEST_LACKS_HOST ""
00069 #endif
00070 
00078 #if HAVE_MESSAGES
00079 #define REQUEST_MALFORMED "<html><head><title>Request malformed</title></head><body>Your HTTP request was syntactically incorrect.</body></html>"
00080 #else
00081 #define REQUEST_MALFORMED ""
00082 #endif
00083 
00090 #if HAVE_MESSAGES
00091 #define INTERNAL_ERROR "<html><head><title>Internal server error</title></head><body>Some programmer needs to study the manual more carefully.</body></html>"
00092 #else
00093 #define INTERNAL_ERROR ""
00094 #endif
00095 
00100 #define DEBUG_CLOSE MHD_NO
00101 
00105 #define DEBUG_SEND_DATA MHD_NO
00106 
00107 
00118 int
00119 MHD_get_connection_values (struct MHD_Connection *connection,
00120                            enum MHD_ValueKind kind,
00121                            MHD_KeyValueIterator iterator, void *iterator_cls)
00122 {
00123   int ret;
00124   struct MHD_HTTP_Header *pos;
00125 
00126   if (NULL == connection)
00127     return -1;
00128   ret = 0;
00129   for (pos = connection->headers_received; NULL != pos; pos = pos->next)
00130     if (0 != (pos->kind & kind))
00131       {
00132         ret++;
00133         if ((NULL != iterator) &&
00134             (MHD_YES != iterator (iterator_cls,
00135                                   kind, pos->header, pos->value)))
00136           return ret;
00137       }
00138   return ret;
00139 }
00140 
00141 
00171 int
00172 MHD_set_connection_value (struct MHD_Connection *connection,
00173                           enum MHD_ValueKind kind,
00174                           const char *key, const char *value)
00175 {
00176   struct MHD_HTTP_Header *pos;
00177 
00178   pos = MHD_pool_allocate (connection->pool,
00179                            sizeof (struct MHD_HTTP_Header), MHD_NO);
00180   if (NULL == pos)
00181     return MHD_NO;
00182   pos->header = (char *) key;
00183   pos->value = (char *) value;
00184   pos->kind = kind;
00185   pos->next = NULL;
00186   /* append 'pos' to the linked list of headers */
00187   if (NULL == connection->headers_received_tail)
00188   {
00189     connection->headers_received = pos;
00190     connection->headers_received_tail = pos;
00191   }
00192   else
00193   {
00194     connection->headers_received_tail->next = pos;
00195     connection->headers_received_tail = pos;
00196   }
00197   return MHD_YES;
00198 }
00199 
00200 
00210 const char *
00211 MHD_lookup_connection_value (struct MHD_Connection *connection,
00212                              enum MHD_ValueKind kind, const char *key)
00213 {
00214   struct MHD_HTTP_Header *pos;
00215 
00216   if (NULL == connection)
00217     return NULL;
00218   for (pos = connection->headers_received; NULL != pos; pos = pos->next)
00219     if ((0 != (pos->kind & kind)) && 
00220         ( (key == pos->header) ||
00221           ( (NULL != pos->header) &&
00222             (NULL != key) &&
00223             (0 == strcasecmp (key, pos->header))) ))
00224       return pos->value;    
00225   return NULL;
00226 }
00227 
00228 
00239 int
00240 MHD_queue_response (struct MHD_Connection *connection,
00241                     unsigned int status_code, struct MHD_Response *response)
00242 {
00243   if ( (NULL == connection) ||
00244        (NULL == response) ||
00245        (NULL != connection->response) ||
00246        ( (MHD_CONNECTION_HEADERS_PROCESSED != connection->state) &&
00247          (MHD_CONNECTION_FOOTERS_RECEIVED != connection->state) ) )
00248     return MHD_NO;
00249   MHD_increment_response_rc (response);
00250   connection->response = response;
00251   connection->responseCode = status_code;
00252   if ( (NULL != connection->method) &&
00253        (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD)) )
00254     {
00255       /* if this is a "HEAD" request, pretend that we
00256          have already sent the full message body */
00257       connection->response_write_position = response->total_size;
00258     }
00259   if (MHD_CONNECTION_HEADERS_PROCESSED == connection->state)
00260     {
00261       /* response was queued "early",
00262          refuse to read body / footers or further
00263          requests! */
00264       (void) SHUTDOWN (connection->socket_fd, SHUT_RD);
00265       connection->read_closed = MHD_YES;
00266       connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00267     }
00268   return MHD_YES;
00269 }
00270 
00271 
00279 static int
00280 need_100_continue (struct MHD_Connection *connection)
00281 {
00282   const char *expect;
00283 
00284   return ( (NULL == connection->response) &&
00285            (NULL != connection->version) &&
00286            (0 == strcasecmp (connection->version,
00287                              MHD_HTTP_VERSION_1_1)) &&
00288            (NULL != (expect = MHD_lookup_connection_value (connection,
00289                                                            MHD_HEADER_KIND,
00290                                                            MHD_HTTP_HEADER_EXPECT))) &&
00291            (0 == strcasecmp (expect, "100-continue")) &&
00292            (connection->continue_message_write_offset <
00293             strlen (HTTP_100_CONTINUE)) );
00294 }
00295 
00296 
00304 void
00305 MHD_connection_close (struct MHD_Connection *connection,
00306                       enum MHD_RequestTerminationCode termination_code)
00307 {
00308   struct MHD_Daemon *daemon;
00309 
00310   daemon = connection->daemon;
00311   SHUTDOWN (connection->socket_fd, 
00312             (connection->read_closed == MHD_YES) ? SHUT_WR : SHUT_RDWR);
00313   connection->state = MHD_CONNECTION_CLOSED;
00314   if ( (NULL != daemon->notify_completed) &&
00315        (MHD_YES == connection->client_aware) )
00316     daemon->notify_completed (daemon->notify_completed_cls, 
00317                               connection,
00318                               &connection->client_context,
00319                               termination_code);
00320   connection->client_aware = MHD_NO;
00321 }
00322 
00323 
00331 static void
00332 connection_close_error (struct MHD_Connection *connection,
00333                         const char *emsg)
00334 {
00335 #if HAVE_MESSAGES
00336   if (NULL != emsg)
00337     MHD_DLOG (connection->daemon, emsg);
00338 #endif
00339   MHD_connection_close (connection, MHD_REQUEST_TERMINATED_WITH_ERROR);
00340 }
00341 
00342 
00347 #if HAVE_MESSAGES
00348 #define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, emsg)
00349 #else
00350 #define CONNECTION_CLOSE_ERROR(c, emsg) connection_close_error (c, NULL)
00351 #endif
00352 
00353 
00364 static int
00365 try_ready_normal_body (struct MHD_Connection *connection)
00366 {
00367   int ret;
00368   struct MHD_Response *response;
00369 
00370   response = connection->response;
00371   if (NULL == response->crc)
00372     return MHD_YES;
00373   if ( (response->data_start <=
00374         connection->response_write_position) &&
00375        (response->data_size + response->data_start >
00376         connection->response_write_position) )
00377     return MHD_YES; /* response already ready */
00378 #if LINUX
00379   if ( (-1 != response->fd) &&
00380        (0 == (connection->daemon->options & MHD_USE_SSL)) )
00381     {
00382       /* will use sendfile, no need to bother response crc */
00383       return MHD_YES; 
00384     }
00385 #endif
00386   
00387   ret = response->crc (response->crc_cls,
00388                        connection->response_write_position,
00389                        response->data,
00390                        MHD_MIN (response->data_buffer_size,
00391                                 response->total_size -
00392                                 connection->response_write_position));
00393   if ((0 == ret) &&
00394       (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY)))
00395     mhd_panic (mhd_panic_cls, __FILE__, __LINE__, 
00396 #if HAVE_MESSAGES
00397                "API violation"
00398 #else
00399                NULL
00400 #endif
00401                );
00402   if ( (MHD_CONTENT_READER_END_OF_STREAM == ret) ||
00403        (MHD_CONTENT_READER_END_WITH_ERROR == ret) )
00404     {
00405       /* either error or http 1.0 transfer, close socket! */
00406       response->total_size = connection->response_write_position;
00407       CONNECTION_CLOSE_ERROR (connection,
00408                               (ret == MHD_CONTENT_READER_END_OF_STREAM) 
00409                               ? "Closing connection (end of response)\n"
00410                               : "Closing connection (stream error)\n");
00411       return MHD_NO;
00412     }
00413   response->data_start = connection->response_write_position;
00414   response->data_size = ret;
00415   if (0 == ret)
00416     {
00417       connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
00418       return MHD_NO;
00419     }
00420   return MHD_YES;
00421 }
00422 
00423 
00433 static int
00434 try_ready_chunked_body (struct MHD_Connection *connection)
00435 {
00436   int ret;
00437   char *buf;
00438   struct MHD_Response *response;
00439   size_t size;
00440   char cbuf[10];                /* 10: max strlen of "%x\r\n" */
00441   int cblen;
00442 
00443   response = connection->response;
00444   if (0 == connection->write_buffer_size)
00445     {
00446       size = connection->daemon->pool_size;
00447       do
00448         {
00449           size /= 2;
00450           if (size < 128)
00451             {
00452               /* not enough memory */
00453               CONNECTION_CLOSE_ERROR (connection,
00454                                       "Closing connection (out of memory)\n");
00455               return MHD_NO;
00456             }
00457           buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
00458         }
00459       while (NULL == buf);
00460       connection->write_buffer_size = size;
00461       connection->write_buffer = buf;
00462     }
00463 
00464   if ( (response->data_start <=
00465         connection->response_write_position) &&
00466        (response->data_size + response->data_start >
00467         connection->response_write_position) )
00468     {
00469       /* buffer already ready, use what is there for the chunk */
00470       ret = response->data_size + response->data_start - connection->response_write_position;
00471       if (ret > connection->write_buffer_size - sizeof (cbuf) - 2)
00472         ret = connection->write_buffer_size - sizeof (cbuf) - 2;
00473       memcpy (&connection->write_buffer[sizeof (cbuf)],
00474               &response->data[connection->response_write_position - response->data_start],
00475               ret);
00476     }
00477   else
00478     {
00479       /* buffer not in range, try to fill it */
00480       ret = response->crc (response->crc_cls,
00481                            connection->response_write_position,
00482                            &connection->write_buffer[sizeof (cbuf)],
00483                            connection->write_buffer_size - sizeof (cbuf) - 2);
00484     }
00485   if (MHD_CONTENT_READER_END_WITH_ERROR == ret)
00486     {
00487       /* error, close socket! */
00488       response->total_size = connection->response_write_position;
00489       CONNECTION_CLOSE_ERROR (connection,
00490                               "Closing connection (error generating response)\n");
00491       return MHD_NO;
00492     }
00493   if (MHD_CONTENT_READER_END_OF_STREAM == ret) 
00494     {
00495       /* end of message, signal other side! */
00496       strcpy (connection->write_buffer, "0\r\n");
00497       connection->write_buffer_append_offset = 3;
00498       connection->write_buffer_send_offset = 0;
00499       response->total_size = connection->response_write_position;
00500       return MHD_YES;
00501     }
00502   if (0 == ret)
00503     {
00504       connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
00505       return MHD_NO;
00506     }
00507   if (ret > 0xFFFFFF)
00508     ret = 0xFFFFFF;
00509   snprintf (cbuf, 
00510             sizeof (cbuf),
00511             "%X\r\n", ret);
00512   cblen = strlen (cbuf);
00513   EXTRA_CHECK (cblen <= sizeof (cbuf));
00514   memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
00515   memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
00516   connection->response_write_position += ret;
00517   connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
00518   connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
00519   return MHD_YES;
00520 }
00521 
00522 
00529 static void
00530 add_extra_headers (struct MHD_Connection *connection)
00531 {
00532   const char *have;
00533   char buf[128];
00534 
00535   connection->have_chunked_upload = MHD_NO;
00536   if (MHD_SIZE_UNKNOWN == connection->response->total_size)
00537     {
00538       have = MHD_get_response_header (connection->response,
00539                                       MHD_HTTP_HEADER_CONNECTION);
00540       if ((NULL == have) || (0 != strcasecmp (have, "close")))
00541         {
00542           if ((NULL != connection->version) &&
00543               (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00544             {
00545               connection->have_chunked_upload = MHD_YES;
00546               have = MHD_get_response_header (connection->response,
00547                                               MHD_HTTP_HEADER_TRANSFER_ENCODING);
00548               if (NULL == have)
00549                 MHD_add_response_header (connection->response,
00550                                          MHD_HTTP_HEADER_TRANSFER_ENCODING,
00551                                          "chunked");
00552             }
00553           else
00554             {
00555               MHD_add_response_header (connection->response,
00556                                        MHD_HTTP_HEADER_CONNECTION, "close");
00557             }
00558         }
00559     }
00560   else if (NULL == MHD_get_response_header (connection->response,
00561                                             MHD_HTTP_HEADER_CONTENT_LENGTH))
00562     {
00563       SPRINTF (buf,
00564                "%" MHD_LONG_LONG_PRINTF "u",
00565                (unsigned MHD_LONG_LONG) connection->response->total_size);
00566       MHD_add_response_header (connection->response,
00567                                MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
00568     }
00569 }
00570 
00571 
00578 static void
00579 get_date_string (char *date)
00580 {
00581   static const char *days[] =
00582     { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00583   static const char *mons[] =
00584     { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
00585     "Nov", "Dec"
00586   };
00587   struct tm now;
00588   time_t t;
00589 
00590   time (&t);
00591   gmtime_r (&t, &now);
00592   SPRINTF (date,
00593            "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
00594            days[now.tm_wday % 7],
00595            now.tm_mday,
00596            mons[now.tm_mon % 12],
00597            1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec);
00598 }
00599 
00600 
00607 static int
00608 try_grow_read_buffer (struct MHD_Connection *connection)
00609 {
00610   void *buf;
00611 
00612   buf = MHD_pool_reallocate (connection->pool,
00613                              connection->read_buffer,
00614                              connection->read_buffer_size,
00615                              connection->read_buffer_size * 2 +
00616                              MHD_BUF_INC_SIZE + 1);
00617   if (NULL == buf)
00618     return MHD_NO;
00619   /* we can actually grow the buffer, do it! */
00620   connection->read_buffer = buf;
00621   connection->read_buffer_size =
00622     connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00623   return MHD_YES;
00624 }
00625 
00626 
00634 static int
00635 build_header_response (struct MHD_Connection *connection)
00636 {
00637   size_t size;
00638   size_t off;
00639   struct MHD_HTTP_Header *pos;
00640   char code[256];
00641   char date[128];
00642   char *data;
00643   enum MHD_ValueKind kind;
00644   const char *reason_phrase;
00645   uint32_t rc;
00646   int must_add_close;
00647 
00648   EXTRA_CHECK (NULL != connection->version);
00649   if (0 == strlen(connection->version))
00650     {
00651       data = MHD_pool_allocate (connection->pool, 0, MHD_YES);
00652       connection->write_buffer = data;
00653       connection->write_buffer_append_offset = 0;
00654       connection->write_buffer_send_offset = 0;
00655       connection->write_buffer_size = 0;
00656       return MHD_YES;
00657     }
00658   if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
00659     {
00660       add_extra_headers (connection);
00661       rc = connection->responseCode & (~MHD_ICY_FLAG);
00662       reason_phrase = MHD_get_reason_phrase_for (rc);
00663       SPRINTF (code,
00664                "%s %u %s\r\n",
00665                (0 != (connection->responseCode & MHD_ICY_FLAG))
00666                ? "ICY" 
00667                : ( (0 == strcasecmp (MHD_HTTP_VERSION_1_0,
00668                                      connection->version)) 
00669                    ? MHD_HTTP_VERSION_1_0 
00670                    : MHD_HTTP_VERSION_1_1),
00671                rc, 
00672                reason_phrase);
00673       off = strlen (code);
00674       /* estimate size */
00675       size = off + 2;           /* extra \r\n at the end */
00676       kind = MHD_HEADER_KIND;
00677       if ( (0 == (connection->daemon->options & MHD_SUPPRESS_DATE_NO_CLOCK)) && 
00678            (NULL == MHD_get_response_header (connection->response,
00679                                              MHD_HTTP_HEADER_DATE)) )
00680         get_date_string (date);
00681       else
00682         date[0] = '\0';
00683       size += strlen (date);
00684     }
00685   else
00686     {
00687       size = 2;
00688       kind = MHD_FOOTER_KIND;
00689       off = 0;
00690     }
00691   must_add_close = ( (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED) &&
00692                      (connection->read_closed == MHD_YES) &&
00693                      (0 == strcasecmp (connection->version,
00694                                        MHD_HTTP_VERSION_1_1)) &&
00695                      (NULL == MHD_get_response_header (connection->response,
00696                                                        MHD_HTTP_HEADER_CONNECTION)) );
00697   if (must_add_close)
00698     size += strlen ("Connection: close\r\n");
00699   for (pos = connection->response->first_header; NULL != pos; pos = pos->next)
00700     if (pos->kind == kind)
00701       size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */
00702   /* produce data */
00703   data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
00704   if (NULL == data)
00705     {
00706 #if HAVE_MESSAGES
00707       MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
00708 #endif
00709       return MHD_NO;
00710     }
00711   if (MHD_CONNECTION_FOOTERS_RECEIVED == connection->state)
00712     {
00713       memcpy (data, code, off);
00714     }
00715   if (must_add_close)
00716     {
00717       /* we must add the 'close' header because circumstances forced us to
00718          stop reading from the socket; however, we are not adding the header
00719          to the response as the response may be used in a different context
00720          as well */
00721       memcpy (&data[off], "Connection: close\r\n",
00722               strlen ("Connection: close\r\n"));
00723       off += strlen ("Connection: close\r\n");
00724     }
00725   for (pos = connection->response->first_header; NULL != pos; pos = pos->next)
00726     if (pos->kind == kind)
00727       off += SPRINTF (&data[off], 
00728                       "%s: %s\r\n",
00729                       pos->header, 
00730                       pos->value);
00731   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00732     {
00733       strcpy (&data[off], date);
00734       off += strlen (date);
00735     }
00736   memcpy (&data[off], "\r\n", 2);
00737   off += 2;
00738 
00739   if (off != size)
00740     mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
00741   connection->write_buffer = data;
00742   connection->write_buffer_append_offset = size;
00743   connection->write_buffer_send_offset = 0;
00744   connection->write_buffer_size = size + 1;
00745   return MHD_YES;
00746 }
00747 
00748 
00758 static void
00759 transmit_error_response (struct MHD_Connection *connection,
00760                          unsigned int status_code, 
00761                          const char *message)
00762 {
00763   struct MHD_Response *response;
00764 
00765   if (NULL == connection->version)
00766     {
00767       /* we were unable to process the full header line, so we don't
00768          really know what version the client speaks; assume 1.0 */
00769       connection->version = MHD_HTTP_VERSION_1_0;
00770     }
00771   connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00772   connection->read_closed = MHD_YES;
00773 #if HAVE_MESSAGES
00774   MHD_DLOG (connection->daemon,
00775             "Error %u (`%s') processing request, closing connection.\n",
00776             status_code, message);
00777 #endif
00778   EXTRA_CHECK (connection->response == NULL);
00779   response = MHD_create_response_from_buffer (strlen (message),
00780                                               (void *) message, 
00781                                               MHD_RESPMEM_PERSISTENT);
00782   MHD_queue_response (connection, status_code, response);
00783   EXTRA_CHECK (connection->response != NULL);
00784   MHD_destroy_response (response);
00785   if (MHD_NO == build_header_response (connection))
00786     {
00787       /* oops - close! */
00788       CONNECTION_CLOSE_ERROR (connection,
00789                               "Closing connection (failed to create response header)\n");
00790     }
00791   else
00792     {
00793       connection->state = MHD_CONNECTION_HEADERS_SENDING;
00794     }
00795 }
00796 
00797 
00806 static void
00807 add_to_fd_set (int fd, 
00808                fd_set *set, 
00809                int *max_fd)
00810 {
00811   FD_SET (fd, set);
00812   if ( (NULL != max_fd) &&
00813        (fd > *max_fd) )
00814     *max_fd = fd;
00815 }
00816 
00817 
00830 int
00831 MHD_connection_get_fdset (struct MHD_Connection *connection,
00832                           fd_set *read_fd_set,
00833                           fd_set *write_fd_set,
00834                           fd_set *except_fd_set, 
00835                           int *max_fd)
00836 {
00837   int ret;
00838   struct MHD_Pollfd p;
00839 
00840   /* we use the 'poll fd' as a convenient way to re-use code 
00841      when determining the select sets */
00842   memset (&p, 0, sizeof(struct MHD_Pollfd));
00843   ret = MHD_connection_get_pollfd (connection, &p);
00844   if ( (MHD_YES == ret) && (p.fd >= 0) ) {
00845     if (0 != (p.events & MHD_POLL_ACTION_IN)) 
00846       add_to_fd_set(p.fd, read_fd_set, max_fd);    
00847     if (0 != (p.events & MHD_POLL_ACTION_OUT)) 
00848       add_to_fd_set(p.fd, write_fd_set, max_fd);    
00849   }
00850   return ret;
00851 }
00852 
00853 
00862 int
00863 MHD_connection_get_pollfd (struct MHD_Connection *connection, 
00864                            struct MHD_Pollfd *p)
00865 {
00866   int fd;
00867 
00868   if (NULL == connection->pool)
00869     connection->pool = MHD_pool_create (connection->daemon->pool_size);
00870   if (NULL == connection->pool)
00871     {
00872       CONNECTION_CLOSE_ERROR (connection,
00873                               "Failed to create memory pool!\n");
00874       return MHD_YES;
00875     }
00876   fd = connection->socket_fd;
00877   p->fd = fd;
00878   if (-1 == fd)
00879     return MHD_YES;
00880   while (1)
00881     {
00882 #if DEBUG_STATES
00883       MHD_DLOG (connection->daemon, "%s: state: %s\n",
00884                 __FUNCTION__, MHD_state_to_string (connection->state));
00885 #endif
00886       switch (connection->state)
00887         {
00888 #if HTTPS_SUPPORT     
00889         case MHD_TLS_CONNECTION_INIT:
00890           if (0 == gnutls_record_get_direction (connection->tls_session))
00891             p->events |= MHD_POLL_ACTION_IN;
00892           else
00893             p->events |= MHD_POLL_ACTION_OUT;
00894           break;
00895 #endif
00896         case MHD_CONNECTION_INIT:
00897         case MHD_CONNECTION_URL_RECEIVED:
00898         case MHD_CONNECTION_HEADER_PART_RECEIVED:
00899           /* while reading headers, we always grow the
00900              read buffer if needed, no size-check required */
00901           if ((connection->read_closed) &&
00902               (0 == connection->read_buffer_offset))
00903             {
00904               CONNECTION_CLOSE_ERROR (connection, 
00905                                       "Connection buffer to small for request\n");
00906               continue;
00907             }
00908           if ((connection->read_buffer_offset == connection->read_buffer_size)
00909               && (MHD_NO == try_grow_read_buffer (connection)))
00910             {
00911               transmit_error_response (connection,
00912                                        (connection->url != NULL)
00913                                        ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00914                                        : MHD_HTTP_REQUEST_URI_TOO_LONG,
00915                                        REQUEST_TOO_BIG);
00916               continue;
00917             }
00918           if (MHD_NO == connection->read_closed)
00919             p->events |= MHD_POLL_ACTION_IN;
00920           break;
00921         case MHD_CONNECTION_HEADERS_RECEIVED:
00922           /* we should never get here */
00923           EXTRA_CHECK (0);
00924           break;
00925         case MHD_CONNECTION_HEADERS_PROCESSED:
00926           EXTRA_CHECK (0);
00927           break;
00928         case MHD_CONNECTION_CONTINUE_SENDING:
00929           p->events |= MHD_POLL_ACTION_OUT;
00930           break;
00931         case MHD_CONNECTION_CONTINUE_SENT:
00932           if (connection->read_buffer_offset == connection->read_buffer_size)
00933             {
00934               if ((MHD_YES != try_grow_read_buffer (connection)) &&
00935                   (0 != (connection->daemon->options &
00936                          (MHD_USE_SELECT_INTERNALLY |
00937                           MHD_USE_THREAD_PER_CONNECTION))))
00938                 {
00939                   /* failed to grow the read buffer, and the
00940                      client which is supposed to handle the
00941                      received data in a *blocking* fashion
00942                      (in this mode) did not handle the data as
00943                      it was supposed to!
00944                      => we would either have to do busy-waiting
00945                      (on the client, which would likely fail),
00946                      or if we do nothing, we would just timeout
00947                      on the connection (if a timeout is even
00948                      set!).
00949                      Solution: we kill the connection with an error */
00950                   transmit_error_response (connection,
00951                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
00952                                            INTERNAL_ERROR);
00953                   continue;
00954                 }
00955             }
00956           if ((connection->read_buffer_offset < connection->read_buffer_size)
00957               && (MHD_NO == connection->read_closed))
00958             p->events |= MHD_POLL_ACTION_IN;
00959           break;
00960         case MHD_CONNECTION_BODY_RECEIVED:
00961         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
00962           /* while reading footers, we always grow the
00963              read buffer if needed, no size-check required */
00964           if (MHD_YES == connection->read_closed)
00965             {
00966               CONNECTION_CLOSE_ERROR (connection, 
00967                                       NULL);
00968               continue;
00969             }
00970           p->events |= MHD_POLL_ACTION_IN;
00971           /* transition to FOOTERS_RECEIVED
00972              happens in read handler */
00973           break;
00974         case MHD_CONNECTION_FOOTERS_RECEIVED:
00975           /* no socket action, wait for client
00976              to provide response */
00977           break;
00978         case MHD_CONNECTION_HEADERS_SENDING:
00979           /* headers in buffer, keep writing */
00980           p->events |= MHD_POLL_ACTION_OUT;
00981           break;
00982         case MHD_CONNECTION_HEADERS_SENT:
00983           EXTRA_CHECK (0);
00984           break;
00985         case MHD_CONNECTION_NORMAL_BODY_READY:
00986           p->events |= MHD_POLL_ACTION_OUT;
00987           break;
00988         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
00989           /* not ready, no socket action */
00990           break;
00991         case MHD_CONNECTION_CHUNKED_BODY_READY:
00992           p->events |= MHD_POLL_ACTION_OUT;
00993           break;
00994         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
00995           /* not ready, no socket action */
00996           break;
00997         case MHD_CONNECTION_BODY_SENT:
00998           EXTRA_CHECK (0);
00999           break;
01000         case MHD_CONNECTION_FOOTERS_SENDING:
01001           p->events |= MHD_POLL_ACTION_OUT;
01002           break;
01003         case MHD_CONNECTION_FOOTERS_SENT:
01004           EXTRA_CHECK (0);
01005           break;
01006         case MHD_CONNECTION_CLOSED:
01007           return MHD_YES;       /* do nothing, not even reading */
01008         default:
01009           EXTRA_CHECK (0);
01010         }
01011       break;
01012     }
01013   return MHD_YES;
01014 }
01015 
01016 
01025 static char *
01026 get_next_header_line (struct MHD_Connection *connection)
01027 {
01028   char *rbuf;
01029   size_t pos;
01030 
01031   if (0 == connection->read_buffer_offset)
01032     return NULL;
01033   pos = 0;
01034   rbuf = connection->read_buffer;
01035   while ((pos < connection->read_buffer_offset - 1) &&
01036          ('\r' != rbuf[pos]) && ('\n' != rbuf[pos]))
01037     pos++;
01038   if (pos == connection->read_buffer_offset - 1)
01039     {
01040       /* not found, consider growing... */
01041       if (connection->read_buffer_offset == connection->read_buffer_size)
01042         {
01043           rbuf = MHD_pool_reallocate (connection->pool,
01044                                       connection->read_buffer,
01045                                       connection->read_buffer_size,
01046                                       connection->read_buffer_size * 2 +
01047                                       MHD_BUF_INC_SIZE);
01048           if (NULL == rbuf)
01049             {
01050               transmit_error_response (connection,
01051                                        (NULL != connection->url)
01052                                        ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
01053                                        : MHD_HTTP_REQUEST_URI_TOO_LONG,
01054                                        REQUEST_TOO_BIG);
01055             }
01056           else
01057             {
01058               connection->read_buffer_size =
01059                 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
01060               connection->read_buffer = rbuf;
01061             }
01062         }
01063       return NULL;
01064     }
01065   /* found, check if we have proper CRLF */
01066   if (('\r' == rbuf[pos]) && ('\n' == rbuf[pos + 1]))
01067     rbuf[pos++] = '\0';         /* skip both r and n */
01068   rbuf[pos++] = '\0';
01069   connection->read_buffer += pos;
01070   connection->read_buffer_size -= pos;
01071   connection->read_buffer_offset -= pos;
01072   return rbuf;
01073 }
01074 
01075 
01087 static int
01088 connection_add_header (struct MHD_Connection *connection,
01089                        char *key, char *value, enum MHD_ValueKind kind)
01090 {
01091   if (MHD_NO == MHD_set_connection_value (connection,
01092                                           kind,
01093                                           key, value))
01094     {
01095 #if HAVE_MESSAGES
01096       MHD_DLOG (connection->daemon,
01097                 "Not enough memory to allocate header record!\n");
01098 #endif
01099       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01100                                REQUEST_TOO_BIG);
01101       return MHD_NO;
01102     }
01103   return MHD_YES;
01104 }
01105 
01106 
01116 static int
01117 parse_arguments (enum MHD_ValueKind kind,
01118                  struct MHD_Connection *connection, 
01119                  char *args)
01120 {
01121   char *equals;
01122   char *amper;
01123 
01124   while (NULL != args)
01125     {
01126       if (NULL == (equals = strstr (args, "=")))
01127         {
01128           /* add with 'value' NULL */
01129           connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01130                                                  connection,
01131                                                  args);
01132           
01133           return connection_add_header (connection,
01134                                         args,
01135                                         NULL,
01136                                         kind);
01137         }
01138       equals[0] = '\0';
01139       equals++;
01140       amper = strstr (equals, "&");
01141       if (amper != NULL)
01142         {
01143           amper[0] = '\0';
01144           amper++;
01145         }
01146       connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01147                                              connection,
01148                                              args);
01149       connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01150                                              connection,
01151                                              equals);
01152       if (MHD_NO == connection_add_header (connection, args, equals, kind))
01153         return MHD_NO;
01154       args = amper;
01155     }
01156   return MHD_YES;
01157 }
01158 
01159 
01165 static int
01166 parse_cookie_header (struct MHD_Connection *connection)
01167 {
01168   const char *hdr;
01169   char *cpy;
01170   char *pos;
01171   char *sce;
01172   char *semicolon;
01173   char *equals;
01174   char *ekill;
01175   char old;
01176   int quotes;
01177 
01178   hdr = MHD_lookup_connection_value (connection,
01179                                      MHD_HEADER_KIND,
01180                                      MHD_HTTP_HEADER_COOKIE);
01181   if (hdr == NULL)
01182     return MHD_YES;
01183   cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
01184   if (cpy == NULL)
01185     {
01186 #if HAVE_MESSAGES
01187       MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
01188 #endif
01189       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01190                                REQUEST_TOO_BIG);
01191       return MHD_NO;
01192     }
01193   memcpy (cpy, hdr, strlen (hdr) + 1);
01194   pos = cpy;
01195   while (pos != NULL)
01196     {
01197       while (*pos == ' ')
01198         pos++;                  /* skip spaces */
01199 
01200       sce = pos;
01201       while (((*sce) != '\0') &&
01202              ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
01203         sce++;
01204       /* remove tailing whitespace (if any) from key */
01205       ekill = sce - 1;
01206       while ((*ekill == ' ') && (ekill >= pos))
01207         *(ekill--) = '\0';
01208       old = *sce;
01209       *sce = '\0';
01210       if (old != '=')
01211         {
01212           /* value part omitted, use empty string... */
01213           if (MHD_NO ==
01214               connection_add_header (connection, pos, "", MHD_COOKIE_KIND))
01215             return MHD_NO;
01216           if (old == '\0')
01217             break;
01218           pos = sce + 1;
01219           continue;
01220         }
01221       equals = sce + 1;
01222       quotes = 0;
01223       semicolon = equals;
01224       while ((semicolon[0] != '\0') &&
01225              ((quotes != 0) ||
01226               ((semicolon[0] != ';') && (semicolon[0] != ','))))
01227         {
01228           if (semicolon[0] == '"')
01229             quotes = (quotes + 1) & 1;
01230           semicolon++;
01231         }
01232       if (semicolon[0] == '\0')
01233         semicolon = NULL;
01234       if (semicolon != NULL)
01235         {
01236           semicolon[0] = '\0';
01237           semicolon++;
01238         }
01239       /* remove quotes */
01240       if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
01241         {
01242           equals[strlen (equals) - 1] = '\0';
01243           equals++;
01244         }
01245       if (MHD_NO == connection_add_header (connection,
01246                                            pos, equals, MHD_COOKIE_KIND))
01247         return MHD_NO;
01248       pos = semicolon;
01249     }
01250   return MHD_YES;
01251 }
01252 
01253 
01261 static int
01262 parse_initial_message_line (struct MHD_Connection *connection, char *line)
01263 {
01264   char *uri;
01265   char *httpVersion;
01266   char *args;
01267 
01268   if (NULL == (uri = strstr (line, " ")))
01269     return MHD_NO;              /* serious error */
01270   uri[0] = '\0';
01271   connection->method = line;
01272   uri++;
01273   while (uri[0] == ' ')
01274     uri++;
01275   httpVersion = strstr (uri, " ");
01276   if (httpVersion != NULL)
01277     {
01278       httpVersion[0] = '\0';
01279       httpVersion++;
01280     }
01281   if (connection->daemon->uri_log_callback != NULL)
01282     connection->client_context
01283       =
01284       connection->daemon->uri_log_callback (connection->daemon->
01285                                             uri_log_callback_cls, uri);
01286   args = strstr (uri, "?");
01287   if (NULL != args)
01288     {
01289       args[0] = '\0';
01290       args++;
01291       parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
01292     }
01293   connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01294                                          connection,
01295                                          uri);
01296   connection->url = uri;
01297   if (NULL == httpVersion)
01298     connection->version = "";
01299   else
01300     connection->version = httpVersion;
01301   return MHD_YES;
01302 }
01303 
01304 
01310 static void
01311 call_connection_handler (struct MHD_Connection *connection)
01312 {
01313   size_t processed;
01314 
01315   if (NULL != connection->response)
01316     return;                     /* already queued a response */  
01317   processed = 0;
01318   connection->client_aware = MHD_YES;
01319   if (MHD_NO ==
01320       connection->daemon->default_handler (connection->daemon->
01321                                            default_handler_cls,
01322                                            connection, connection->url,
01323                                            connection->method,
01324                                            connection->version,
01325                                            NULL, &processed,
01326                                            &connection->client_context))
01327     {
01328       /* serious internal error, close connection */
01329       CONNECTION_CLOSE_ERROR (connection, 
01330                               "Internal application error, closing connection.\n");
01331       return;
01332     }
01333 }
01334 
01335 
01336 
01342 static void
01343 process_request_body (struct MHD_Connection *connection)
01344 {
01345   size_t processed;
01346   size_t available;
01347   size_t used;
01348   size_t i;
01349   int instant_retry;
01350   int malformed;
01351   char *buffer_head;
01352   char *end;
01353 
01354   if (NULL != connection->response)
01355     return;                     /* already queued a response */
01356 
01357   buffer_head = connection->read_buffer;
01358   available = connection->read_buffer_offset;
01359   do
01360     {
01361       instant_retry = MHD_NO;
01362       if ((connection->have_chunked_upload == MHD_YES) &&
01363           (connection->remaining_upload_size == MHD_SIZE_UNKNOWN))
01364         {
01365           if ((connection->current_chunk_offset ==
01366                connection->current_chunk_size)
01367               && (connection->current_chunk_offset != 0) && (available >= 2))
01368             {
01369               /* skip new line at the *end* of a chunk */
01370               i = 0;
01371               if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01372                 i++;            /* skip 1st part of line feed */
01373               if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01374                 i++;            /* skip 2nd part of line feed */
01375               if (i == 0)
01376                 {
01377                   /* malformed encoding */
01378                   CONNECTION_CLOSE_ERROR (connection,
01379                                           "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01380                   return;
01381                 }
01382               available -= i;
01383               buffer_head += i;
01384               connection->current_chunk_offset = 0;
01385               connection->current_chunk_size = 0;
01386             }
01387           if (connection->current_chunk_offset <
01388               connection->current_chunk_size)
01389             {
01390               /* we are in the middle of a chunk, give
01391                  as much as possible to the client (without
01392                  crossing chunk boundaries) */
01393               processed =
01394                 connection->current_chunk_size -
01395                 connection->current_chunk_offset;
01396               if (processed > available)
01397                 processed = available;
01398               if (available > processed)
01399                 instant_retry = MHD_YES;
01400             }
01401           else
01402             {
01403               /* we need to read chunk boundaries */
01404               i = 0;
01405               while (i < available)
01406                 {
01407                   if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01408                     break;
01409                   i++;
01410                   if (i >= 6)
01411                     break;
01412                 }
01413               /* take '\n' into account; if '\n'
01414                  is the unavailable character, we
01415                  will need to wait until we have it
01416                  before going further */
01417               if ((i + 1 >= available) &&
01418                   !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
01419                 break;          /* need more data... */
01420               malformed = (i >= 6);
01421               if (!malformed)
01422                 {
01423                   buffer_head[i] = '\0';
01424                   connection->current_chunk_size = strtoul (buffer_head, &end, 16);
01425                   malformed = ('\0' != *end);
01426                 }
01427               if (malformed)
01428                 {
01429                   /* malformed encoding */
01430                   CONNECTION_CLOSE_ERROR (connection,
01431                                           "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01432                   return;
01433                 }
01434               i++;
01435               if ((i < available) &&
01436                   ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
01437                 i++;            /* skip 2nd part of line feed */
01438 
01439               buffer_head += i;
01440               available -= i;
01441               connection->current_chunk_offset = 0;
01442 
01443               if (available > 0)
01444                 instant_retry = MHD_YES;
01445               if (connection->current_chunk_size == 0)
01446                 {
01447                   connection->remaining_upload_size = 0;
01448                   break;
01449                 }
01450               continue;
01451             }
01452         }
01453       else
01454         {
01455           /* no chunked encoding, give all to the client */
01456           if ( (0 != connection->remaining_upload_size) && 
01457                (MHD_SIZE_UNKNOWN != connection->remaining_upload_size) &&
01458                (connection->remaining_upload_size < available) )
01459             {
01460               processed = connection->remaining_upload_size;
01461             }
01462           else
01463             {
01468               processed = available;
01469             }
01470         }
01471       used = processed;
01472       connection->client_aware = MHD_YES;
01473       if (MHD_NO ==
01474           connection->daemon->default_handler (connection->daemon->
01475                                                default_handler_cls,
01476                                                connection, connection->url,
01477                                                connection->method,
01478                                                connection->version,
01479                                                buffer_head, &processed,
01480                                                &connection->client_context))
01481         {
01482           /* serious internal error, close connection */
01483           CONNECTION_CLOSE_ERROR (connection,
01484                                   "Internal application error, closing connection.\n");
01485           return;
01486         }
01487       if (processed > used)
01488         mhd_panic (mhd_panic_cls, __FILE__, __LINE__, 
01489 #if HAVE_MESSAGES
01490                    "API violation"
01491 #else
01492                    NULL
01493 #endif
01494                    );
01495       if (processed != 0)
01496         instant_retry = MHD_NO; /* client did not process everything */
01497       used -= processed;
01498       if (connection->have_chunked_upload == MHD_YES)
01499         connection->current_chunk_offset += used;
01500       /* dh left "processed" bytes in buffer for next time... */
01501       buffer_head += used;
01502       available -= used;
01503       if (connection->remaining_upload_size != MHD_SIZE_UNKNOWN)
01504         connection->remaining_upload_size -= used;
01505     }
01506   while (MHD_YES == instant_retry);
01507   if (available > 0)
01508     memmove (connection->read_buffer, buffer_head, available);
01509   connection->read_buffer_offset = available;
01510 }
01511 
01520 static int
01521 do_read (struct MHD_Connection *connection)
01522 {
01523   int bytes_read;
01524 
01525   if (connection->read_buffer_size == connection->read_buffer_offset)
01526     return MHD_NO;
01527 
01528   bytes_read = connection->recv_cls (connection,
01529                                      &connection->read_buffer
01530                                      [connection->read_buffer_offset],
01531                                      connection->read_buffer_size -
01532                                      connection->read_buffer_offset);
01533   if (bytes_read < 0)
01534     {
01535       if ((EINTR == errno) || (EAGAIN == errno))
01536         return MHD_NO;
01537 #if HAVE_MESSAGES
01538 #if HTTPS_SUPPORT
01539       if (0 != (connection->daemon->options & MHD_USE_SSL))
01540         MHD_DLOG (connection->daemon,
01541                   "Failed to receive data: %s\n",
01542                   gnutls_strerror (bytes_read));
01543       else
01544 #endif      
01545         MHD_DLOG (connection->daemon,
01546                   "Failed to receive data: %s\n", STRERROR (errno));
01547 #endif
01548       CONNECTION_CLOSE_ERROR (connection, NULL);
01549       return MHD_YES;
01550     }
01551   if (0 == bytes_read)
01552     {
01553       /* other side closed connection */
01554       connection->read_closed = MHD_YES;
01555       SHUTDOWN (connection->socket_fd, SHUT_RD);
01556       return MHD_YES;
01557     }
01558   connection->read_buffer_offset += bytes_read;
01559   return MHD_YES;
01560 }
01561 
01569 static int
01570 do_write (struct MHD_Connection *connection)
01571 {
01572   int ret;
01573 
01574   ret = connection->send_cls (connection,
01575                               &connection->write_buffer
01576                               [connection->write_buffer_send_offset],
01577                               connection->write_buffer_append_offset
01578                               - connection->write_buffer_send_offset);
01579 
01580   if (ret < 0)
01581     {
01582       if ((EINTR == errno) || (EAGAIN == errno))
01583         return MHD_NO;
01584 #if HAVE_MESSAGES
01585 #if HTTPS_SUPPORT
01586       if (0 != (connection->daemon->options & MHD_USE_SSL))
01587         MHD_DLOG (connection->daemon,
01588                   "Failed to send data: %s\n",
01589                   gnutls_strerror (ret));
01590       else
01591 #endif      
01592         MHD_DLOG (connection->daemon,
01593                   "Failed to send data: %s\n", STRERROR (errno));
01594 #endif
01595       CONNECTION_CLOSE_ERROR (connection, NULL);
01596       return MHD_YES;
01597     }
01598 #if DEBUG_SEND_DATA
01599   FPRINTF (stderr,
01600            "Sent response: `%.*s'\n",
01601            ret,
01602            &connection->write_buffer[connection->write_buffer_send_offset]);
01603 #endif
01604   connection->write_buffer_send_offset += ret;
01605   return MHD_YES;
01606 }
01607 
01613 static int
01614 check_write_done (struct MHD_Connection *connection,
01615                   enum MHD_CONNECTION_STATE next_state)
01616 {
01617   if (connection->write_buffer_append_offset !=
01618       connection->write_buffer_send_offset)
01619     return MHD_NO;
01620   connection->write_buffer_append_offset = 0;
01621   connection->write_buffer_send_offset = 0;
01622   connection->state = next_state;
01623   MHD_pool_reallocate (connection->pool, connection->write_buffer,
01624                        connection->write_buffer_size, 0);
01625   connection->write_buffer = NULL;
01626   connection->write_buffer_size = 0;
01627   return MHD_YES;
01628 }
01629 
01635 static int
01636 process_header_line (struct MHD_Connection *connection, char *line)
01637 {
01638   char *colon;
01639 
01640   /* line should be normal header line, find colon */
01641   colon = strstr (line, ":");
01642   if (colon == NULL)
01643     {
01644       /* error in header line, die hard */
01645       CONNECTION_CLOSE_ERROR (connection, 
01646                               "Received malformed line (no colon), closing connection.\n");
01647       return MHD_NO;
01648     }
01649   /* zero-terminate header */
01650   colon[0] = '\0';
01651   colon++;                      /* advance to value */
01652   while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
01653     colon++;
01654   /* we do the actual adding of the connection
01655      header at the beginning of the while
01656      loop since we need to be able to inspect
01657      the *next* header line (in case it starts
01658      with a space...) */
01659   connection->last = line;
01660   connection->colon = colon;
01661   return MHD_YES;
01662 }
01663 
01664 
01674 static int
01675 process_broken_line (struct MHD_Connection *connection,
01676                      char *line, enum MHD_ValueKind kind)
01677 {
01678   char *last;
01679   char *tmp;
01680   size_t last_len;
01681   size_t tmp_len;
01682 
01683   last = connection->last;
01684   if ((line[0] == ' ') || (line[0] == '\t'))
01685     {
01686       /* value was continued on the next line, see
01687          http://www.jmarshall.com/easy/http/ */
01688       last_len = strlen (last);
01689       /* skip whitespace at start of 2nd line */
01690       tmp = line;
01691       while ((tmp[0] == ' ') || (tmp[0] == '\t'))
01692         tmp++;                  
01693       tmp_len = strlen (tmp);
01694       last = MHD_pool_reallocate (connection->pool,
01695                                   last,
01696                                   last_len + 1,
01697                                   last_len + tmp_len + 1);
01698       if (last == NULL)
01699         {
01700           transmit_error_response (connection,
01701                                    MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01702                                    REQUEST_TOO_BIG);
01703           return MHD_NO;
01704         }
01705       memcpy (&last[last_len], tmp, tmp_len + 1);
01706       connection->last = last;
01707       return MHD_YES;           /* possibly more than 2 lines... */
01708     }
01709   EXTRA_CHECK ((last != NULL) && (connection->colon != NULL));
01710   if ((MHD_NO == connection_add_header (connection,
01711                                         last, connection->colon, kind)))
01712     {
01713       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01714                                REQUEST_TOO_BIG);
01715       return MHD_NO;
01716     }
01717   /* we still have the current line to deal with... */
01718   if (strlen (line) != 0)
01719     {
01720       if (MHD_NO == process_header_line (connection, line))
01721         {
01722           transmit_error_response (connection,
01723                                    MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED);
01724           return MHD_NO;
01725         }
01726     }
01727   return MHD_YES;
01728 }
01729 
01730 
01736 static void
01737 parse_connection_headers (struct MHD_Connection *connection)
01738 {
01739   const char *clen;
01740   unsigned MHD_LONG_LONG cval;
01741   struct MHD_Response *response;
01742   const char *enc;
01743   char *end;
01744 
01745   parse_cookie_header (connection);
01746   if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
01747       && (NULL != connection->version)
01748       && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
01749       && (NULL ==
01750           MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
01751                                        MHD_HTTP_HEADER_HOST)))
01752     {
01753       /* die, http 1.1 request without host and we are pedantic */
01754       connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01755       connection->read_closed = MHD_YES;
01756 #if HAVE_MESSAGES
01757       MHD_DLOG (connection->daemon,
01758                 "Received `%s' request without `%s' header.\n",
01759                 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
01760 #endif
01761       EXTRA_CHECK (connection->response == NULL);
01762       response =
01763         MHD_create_response_from_buffer (strlen (REQUEST_LACKS_HOST),
01764                                          REQUEST_LACKS_HOST,
01765                                          MHD_RESPMEM_PERSISTENT);
01766       MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
01767       MHD_destroy_response (response);
01768       return;
01769     }
01770 
01771   clen = MHD_lookup_connection_value (connection,
01772                                       MHD_HEADER_KIND,
01773                                       MHD_HTTP_HEADER_CONTENT_LENGTH);
01774   if (clen != NULL)
01775     {
01776       cval = strtoul (clen, &end, 10);
01777       if ( ('\0' != *end) ||
01778          ( (LONG_MAX == cval) && (errno == ERANGE) ) )
01779         {
01780 #if HAVE_MESSAGES
01781           MHD_DLOG (connection->daemon,
01782                     "Failed to parse `%s' header `%s', closing connection.\n",
01783                     MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
01784 #endif
01785           CONNECTION_CLOSE_ERROR (connection, NULL);
01786           return;
01787         }
01788       connection->remaining_upload_size = cval;
01789     }
01790   else
01791     {
01792       enc = MHD_lookup_connection_value (connection,
01793                                          MHD_HEADER_KIND,
01794                                          MHD_HTTP_HEADER_TRANSFER_ENCODING);
01795       if (NULL == enc)
01796         {
01797           /* this request (better) not have a body */
01798           connection->remaining_upload_size = 0;
01799         }
01800       else
01801         {
01802           connection->remaining_upload_size = MHD_SIZE_UNKNOWN;
01803           if (0 == strcasecmp (enc, "chunked"))
01804             connection->have_chunked_upload = MHD_YES;
01805         }
01806     }
01807 }
01808 
01809 
01820 int
01821 MHD_connection_handle_read (struct MHD_Connection *connection)
01822 {
01823   connection->last_activity = MHD_monotonic_time();
01824   if (connection->state == MHD_CONNECTION_CLOSED)
01825     return MHD_YES;
01826   /* make sure "read" has a reasonable number of bytes
01827      in buffer to use per system call (if possible) */
01828   if (connection->read_buffer_offset + MHD_BUF_INC_SIZE >
01829       connection->read_buffer_size)
01830     try_grow_read_buffer (connection);
01831   if (MHD_NO == do_read (connection))
01832     return MHD_YES;
01833   while (1)
01834     {
01835 #if DEBUG_STATES
01836       MHD_DLOG (connection->daemon, "%s: state: %s\n",
01837                 __FUNCTION__, MHD_state_to_string (connection->state));
01838 #endif
01839       switch (connection->state)
01840         {
01841         case MHD_CONNECTION_INIT:
01842         case MHD_CONNECTION_URL_RECEIVED:
01843         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01844         case MHD_CONNECTION_HEADERS_RECEIVED:
01845         case MHD_CONNECTION_HEADERS_PROCESSED:
01846         case MHD_CONNECTION_CONTINUE_SENDING:
01847         case MHD_CONNECTION_CONTINUE_SENT:
01848         case MHD_CONNECTION_BODY_RECEIVED:
01849         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01850           /* nothing to do but default action */
01851           if (MHD_YES == connection->read_closed)
01852             {
01853               MHD_connection_close (connection,
01854                                     MHD_REQUEST_TERMINATED_READ_ERROR);
01855               continue;
01856             }
01857           break;
01858         case MHD_CONNECTION_CLOSED:
01859           return MHD_YES;
01860         default:
01861           /* shrink read buffer to how much is actually used */
01862           MHD_pool_reallocate (connection->pool,
01863                                connection->read_buffer,
01864                                connection->read_buffer_size + 1,
01865                                connection->read_buffer_offset);
01866           break;
01867         }
01868       break;
01869     }
01870   return MHD_YES;
01871 }
01872 
01873 
01884 int
01885 MHD_connection_handle_write (struct MHD_Connection *connection)
01886 {
01887   struct MHD_Response *response;
01888   int ret;
01889   connection->last_activity = MHD_monotonic_time();
01890   while (1)
01891     {
01892 #if DEBUG_STATES
01893       MHD_DLOG (connection->daemon, "%s: state: %s\n",
01894                 __FUNCTION__, MHD_state_to_string (connection->state));
01895 #endif
01896       switch (connection->state)
01897         {
01898         case MHD_CONNECTION_INIT:
01899         case MHD_CONNECTION_URL_RECEIVED:
01900         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01901         case MHD_CONNECTION_HEADERS_RECEIVED:
01902           EXTRA_CHECK (0);
01903           break;
01904         case MHD_CONNECTION_HEADERS_PROCESSED:
01905           break;
01906         case MHD_CONNECTION_CONTINUE_SENDING:
01907           ret = connection->send_cls (connection,
01908                                       &HTTP_100_CONTINUE
01909                                       [connection->continue_message_write_offset],
01910                                       strlen (HTTP_100_CONTINUE) -
01911                                       connection->continue_message_write_offset);
01912           if (ret < 0)
01913             {
01914               if ((errno == EINTR) || (errno == EAGAIN))
01915                 break;
01916 #if HAVE_MESSAGES
01917               MHD_DLOG (connection->daemon,
01918                         "Failed to send data: %s\n", STRERROR (errno));
01919 #endif
01920               CONNECTION_CLOSE_ERROR (connection, NULL);
01921               return MHD_YES;
01922             }
01923 #if DEBUG_SEND_DATA
01924           FPRINTF (stderr,
01925                    "Sent 100 continue response: `%.*s'\n",
01926                    ret,
01927                    &HTTP_100_CONTINUE
01928                    [connection->continue_message_write_offset]);
01929 #endif
01930           connection->continue_message_write_offset += ret;
01931           break;
01932         case MHD_CONNECTION_CONTINUE_SENT:
01933         case MHD_CONNECTION_BODY_RECEIVED:
01934         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01935         case MHD_CONNECTION_FOOTERS_RECEIVED:
01936           EXTRA_CHECK (0);
01937           break;
01938         case MHD_CONNECTION_HEADERS_SENDING:
01939           do_write (connection);
01940           if (connection->state != MHD_CONNECTION_HEADERS_SENDING)
01941              break;
01942           check_write_done (connection, MHD_CONNECTION_HEADERS_SENT);
01943           break;
01944         case MHD_CONNECTION_HEADERS_SENT:
01945           EXTRA_CHECK (0);
01946           break;
01947         case MHD_CONNECTION_NORMAL_BODY_READY:
01948           response = connection->response;
01949           if (response->crc != NULL)
01950             pthread_mutex_lock (&response->mutex);
01951           if (MHD_YES != try_ready_normal_body (connection))
01952             {
01953               if (response->crc != NULL)
01954                 pthread_mutex_unlock (&response->mutex);
01955               break;
01956             }
01957           ret = connection->send_cls (connection,
01958                                       &response->data
01959                                       [connection->response_write_position
01960                                        - response->data_start],
01961                                       response->data_size -
01962                                       (connection->response_write_position
01963                                        - response->data_start));
01964 #if DEBUG_SEND_DATA
01965           if (ret > 0)
01966             FPRINTF (stderr,
01967                      "Sent DATA response: `%.*s'\n",
01968                      ret,
01969                      &response->data[connection->response_write_position -
01970                                      response->data_start]);
01971 #endif
01972           if (response->crc != NULL)
01973             pthread_mutex_unlock (&response->mutex);
01974           if (ret < 0)
01975             {
01976               if ((errno == EINTR) || (errno == EAGAIN))
01977                 return MHD_YES;
01978 #if HAVE_MESSAGES
01979               MHD_DLOG (connection->daemon,
01980                         "Failed to send data: %s\n", STRERROR (errno));
01981 #endif
01982               CONNECTION_CLOSE_ERROR (connection, NULL);
01983               return MHD_YES;
01984             }
01985           connection->response_write_position += ret;
01986           if (connection->response_write_position ==
01987               connection->response->total_size)
01988             connection->state = MHD_CONNECTION_FOOTERS_SENT;    /* have no footers... */
01989           break;
01990         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01991           EXTRA_CHECK (0);
01992           break;
01993         case MHD_CONNECTION_CHUNKED_BODY_READY:
01994           do_write (connection);
01995           if (connection->state !=  MHD_CONNECTION_CHUNKED_BODY_READY)
01996              break;
01997           check_write_done (connection,
01998                             (connection->response->total_size ==
01999                              connection->response_write_position) ?
02000                             MHD_CONNECTION_BODY_SENT :
02001                             MHD_CONNECTION_CHUNKED_BODY_UNREADY);
02002           break;
02003         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
02004         case MHD_CONNECTION_BODY_SENT:
02005           EXTRA_CHECK (0);
02006           break;
02007         case MHD_CONNECTION_FOOTERS_SENDING:
02008           do_write (connection);
02009           if (connection->state != MHD_CONNECTION_FOOTERS_SENDING)
02010             break;
02011           check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT);
02012           break;
02013         case MHD_CONNECTION_FOOTERS_SENT:
02014           EXTRA_CHECK (0);
02015           break;
02016         case MHD_CONNECTION_CLOSED:
02017           return MHD_YES;
02018         case MHD_TLS_CONNECTION_INIT:
02019           EXTRA_CHECK (0);
02020           break;
02021         default:
02022           EXTRA_CHECK (0);
02023           CONNECTION_CLOSE_ERROR (connection, "Internal error\n");
02024           return MHD_YES;
02025         }
02026       break;
02027     }
02028   return MHD_YES;
02029 }
02030 
02031 
02042 int
02043 MHD_connection_handle_idle (struct MHD_Connection *connection)
02044 {
02045   struct MHD_Daemon *daemon;
02046   unsigned int timeout;
02047   const char *end;
02048   int rend;
02049   char *line;
02050 
02051   while (1)
02052     {
02053 #if DEBUG_STATES
02054       MHD_DLOG (connection->daemon, "%s: state: %s\n",
02055                 __FUNCTION__, MHD_state_to_string (connection->state));
02056 #endif
02057       switch (connection->state)
02058         {
02059         case MHD_CONNECTION_INIT:
02060           line = get_next_header_line (connection);
02061           if (line == NULL)
02062             {
02063               if (connection->state != MHD_CONNECTION_INIT)
02064                 continue;
02065               if (connection->read_closed)
02066                 {
02067                   CONNECTION_CLOSE_ERROR (connection, 
02068                                           NULL);
02069                   continue;
02070                 }
02071               break;
02072             }
02073           if (MHD_NO == parse_initial_message_line (connection, line))
02074             CONNECTION_CLOSE_ERROR (connection, NULL);
02075           else
02076             connection->state = MHD_CONNECTION_URL_RECEIVED;
02077           continue;
02078         case MHD_CONNECTION_URL_RECEIVED:
02079           line = get_next_header_line (connection);
02080           if (line == NULL)
02081             {
02082               if (connection->state != MHD_CONNECTION_URL_RECEIVED)
02083                 continue;
02084               if (connection->read_closed)
02085                 {
02086                   CONNECTION_CLOSE_ERROR (connection, 
02087                                           NULL);
02088                   continue;
02089                 }
02090               break;
02091             }
02092           if (strlen (line) == 0)
02093             {
02094               connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
02095               continue;
02096             }
02097           if (MHD_NO == process_header_line (connection, line))
02098             {
02099               transmit_error_response (connection,
02100                                        MHD_HTTP_BAD_REQUEST,
02101                                        REQUEST_MALFORMED);
02102               break;
02103             }
02104           connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
02105           continue;
02106         case MHD_CONNECTION_HEADER_PART_RECEIVED:
02107           line = get_next_header_line (connection);
02108           if (line == NULL)
02109             {
02110               if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
02111                 continue;
02112               if (connection->read_closed)
02113                 {
02114                   CONNECTION_CLOSE_ERROR (connection, 
02115                                           NULL);
02116                   continue;
02117                 }
02118               break;
02119             }
02120           if (MHD_NO ==
02121               process_broken_line (connection, line, MHD_HEADER_KIND))
02122             continue;
02123           if (strlen (line) == 0)
02124             {
02125               connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
02126               continue;
02127             }
02128           continue;
02129         case MHD_CONNECTION_HEADERS_RECEIVED:
02130           parse_connection_headers (connection);
02131           if (connection->state == MHD_CONNECTION_CLOSED)
02132             continue;
02133           connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
02134           continue;
02135         case MHD_CONNECTION_HEADERS_PROCESSED:
02136           call_connection_handler (connection); /* first call */
02137           if (connection->state == MHD_CONNECTION_CLOSED)
02138             continue;
02139           if (need_100_continue (connection))
02140             {
02141               connection->state = MHD_CONNECTION_CONTINUE_SENDING;
02142               break;
02143             }
02144           if (connection->response != NULL)
02145             {
02146               /* we refused (no upload allowed!) */
02147               connection->remaining_upload_size = 0;
02148               /* force close, in case client still tries to upload... */
02149               connection->read_closed = MHD_YES;
02150             }
02151           connection->state = (connection->remaining_upload_size == 0)
02152             ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
02153           continue;
02154         case MHD_CONNECTION_CONTINUE_SENDING:
02155           if (connection->continue_message_write_offset ==
02156               strlen (HTTP_100_CONTINUE))
02157             {
02158               connection->state = MHD_CONNECTION_CONTINUE_SENT;
02159               continue;
02160             }
02161           break;
02162         case MHD_CONNECTION_CONTINUE_SENT:
02163           if (connection->read_buffer_offset != 0)
02164             {
02165               process_request_body (connection);     /* loop call */
02166               if (connection->state == MHD_CONNECTION_CLOSED)
02167                 continue;
02168             }
02169           if ((connection->remaining_upload_size == 0) ||
02170               ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) &&
02171                (connection->read_buffer_offset == 0) &&
02172                (MHD_YES == connection->read_closed)))
02173             {
02174               if ((MHD_YES == connection->have_chunked_upload) &&
02175                   (MHD_NO == connection->read_closed))
02176                 connection->state = MHD_CONNECTION_BODY_RECEIVED;
02177               else
02178                 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02179               continue;
02180             }
02181           break;
02182         case MHD_CONNECTION_BODY_RECEIVED:
02183           line = get_next_header_line (connection);
02184           if (line == NULL)
02185             {
02186               if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
02187                 continue;
02188               if (connection->read_closed)
02189                 {
02190                   CONNECTION_CLOSE_ERROR (connection, 
02191                                           NULL);
02192                   continue;
02193                 }
02194               break;
02195             }
02196           if (strlen (line) == 0)
02197             {
02198               connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02199               continue;
02200             }
02201           if (MHD_NO == process_header_line (connection, line))
02202             {
02203               transmit_error_response (connection,
02204                                        MHD_HTTP_BAD_REQUEST,
02205                                        REQUEST_MALFORMED);
02206               break;
02207             }
02208           connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
02209           continue;
02210         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
02211           line = get_next_header_line (connection);
02212           if (line == NULL)
02213             {
02214               if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
02215                 continue;
02216               if (connection->read_closed)
02217                 {
02218                   CONNECTION_CLOSE_ERROR (connection, 
02219                                           NULL);
02220                   continue;
02221                 }
02222               break;
02223             }
02224           if (MHD_NO ==
02225               process_broken_line (connection, line, MHD_FOOTER_KIND))
02226             continue;
02227           if (strlen (line) == 0)
02228             {
02229               connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02230               continue;
02231             }
02232           continue;
02233         case MHD_CONNECTION_FOOTERS_RECEIVED:
02234           call_connection_handler (connection); /* "final" call */
02235           if (connection->state == MHD_CONNECTION_CLOSED)
02236             continue;
02237           if (connection->response == NULL)
02238             break;              /* try again next time */
02239           if (MHD_NO == build_header_response (connection))
02240             {
02241               /* oops - close! */
02242               CONNECTION_CLOSE_ERROR (connection, 
02243                                       "Closing connection (failed to create response header)\n");
02244               continue;
02245             }
02246           connection->state = MHD_CONNECTION_HEADERS_SENDING;
02247 
02248 #if HAVE_DECL_TCP_CORK
02249           /* starting header send, set TCP cork */
02250           {
02251             const int val = 1;
02252             setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02253                         sizeof (val));
02254           }
02255 #endif
02256           break;
02257         case MHD_CONNECTION_HEADERS_SENDING:
02258           /* no default action */
02259           break;
02260         case MHD_CONNECTION_HEADERS_SENT:
02261           if (connection->have_chunked_upload)
02262             connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
02263           else
02264             connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
02265           continue;
02266         case MHD_CONNECTION_NORMAL_BODY_READY:
02267           /* nothing to do here */
02268           break;
02269         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
02270           if (connection->response->crc != NULL)
02271             pthread_mutex_lock (&connection->response->mutex);
02272           if (MHD_YES == try_ready_normal_body (connection))
02273             {
02274               if (connection->response->crc != NULL)
02275                 pthread_mutex_unlock (&connection->response->mutex);
02276               connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
02277               break;
02278             }
02279           if (connection->response->crc != NULL)
02280             pthread_mutex_unlock (&connection->response->mutex);
02281           /* not ready, no socket action */
02282           break;
02283         case MHD_CONNECTION_CHUNKED_BODY_READY:
02284           /* nothing to do here */
02285           break;
02286         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
02287           if (connection->response->crc != NULL)
02288             pthread_mutex_lock (&connection->response->mutex);
02289           if (MHD_YES == try_ready_chunked_body (connection))
02290             {
02291               if (connection->response->crc != NULL)
02292                 pthread_mutex_unlock (&connection->response->mutex);
02293               connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
02294               continue;
02295             }
02296           if (connection->response->crc != NULL)
02297             pthread_mutex_unlock (&connection->response->mutex);
02298           break;
02299         case MHD_CONNECTION_BODY_SENT:
02300           build_header_response (connection);
02301           if (connection->write_buffer_send_offset ==
02302               connection->write_buffer_append_offset)
02303             connection->state = MHD_CONNECTION_FOOTERS_SENT;
02304           else
02305             connection->state = MHD_CONNECTION_FOOTERS_SENDING;
02306           continue;
02307         case MHD_CONNECTION_FOOTERS_SENDING:
02308           /* no default action */
02309           break;
02310         case MHD_CONNECTION_FOOTERS_SENT:
02311 #if HAVE_DECL_TCP_CORK
02312           /* done sending, uncork */
02313           {
02314             const int val = 0;
02315             setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02316                         sizeof (val));
02317           }
02318 #endif
02319           end =
02320             MHD_get_response_header (connection->response, 
02321                                      MHD_HTTP_HEADER_CONNECTION);
02322           rend = ( (end != NULL) && (0 == strcasecmp (end, "close")) );
02323           MHD_destroy_response (connection->response);
02324           connection->response = NULL;
02325           if (connection->daemon->notify_completed != NULL)
02326             connection->daemon->notify_completed (connection->daemon->
02327                                                   notify_completed_cls,
02328                                                   connection,
02329                                                   &connection->client_context,
02330                                                   MHD_REQUEST_TERMINATED_COMPLETED_OK);     
02331           connection->client_aware = MHD_NO;
02332           end =
02333             MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
02334                                          MHD_HTTP_HEADER_CONNECTION);
02335           connection->client_context = NULL;
02336           connection->continue_message_write_offset = 0;
02337           connection->responseCode = 0;
02338           connection->headers_received = NULL;
02339           connection->headers_received_tail = NULL;
02340           connection->response_write_position = 0;
02341           connection->have_chunked_upload = MHD_NO;
02342           connection->method = NULL;
02343           connection->url = NULL;
02344           connection->write_buffer = NULL;
02345           connection->write_buffer_size = 0;
02346           connection->write_buffer_send_offset = 0;
02347           connection->write_buffer_append_offset = 0;
02348           if ( (rend) || ((end != NULL) && (0 == strcasecmp (end, "close"))) )
02349             {
02350               connection->read_closed = MHD_YES;
02351               connection->read_buffer_offset = 0;
02352             }
02353           if (((MHD_YES == connection->read_closed) &&
02354                (0 == connection->read_buffer_offset)) ||
02355               (connection->version == NULL) ||
02356               (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
02357             {
02358               /* http 1.0, version-less requests cannot be pipelined */
02359               MHD_connection_close (connection, MHD_REQUEST_TERMINATED_COMPLETED_OK);
02360               MHD_pool_destroy (connection->pool);
02361               connection->pool = NULL;
02362               connection->read_buffer = NULL;
02363               connection->read_buffer_size = 0;
02364               connection->read_buffer_offset = 0;
02365             }
02366           else
02367             {
02368               connection->version = NULL;
02369               connection->state = MHD_CONNECTION_INIT;
02370               connection->read_buffer
02371                 = MHD_pool_reset (connection->pool,
02372                                   connection->read_buffer,
02373                                   connection->read_buffer_size);
02374             }
02375           continue;
02376         case MHD_CONNECTION_CLOSED:
02377           if (connection->response != NULL)
02378             {
02379               MHD_destroy_response (connection->response);
02380               connection->response = NULL;
02381             }
02382           daemon = connection->daemon;
02383           if (0 != pthread_mutex_lock(&daemon->cleanup_connection_mutex))
02384             {
02385               MHD_PANIC ("Failed to acquire cleanup mutex\n");
02386             }
02387           DLL_remove (daemon->connections_head,
02388                       daemon->connections_tail,
02389                       connection);
02390           DLL_insert (daemon->cleanup_head,
02391                       daemon->cleanup_tail,
02392                       connection);
02393           if (0 != pthread_mutex_unlock(&daemon->cleanup_connection_mutex))
02394             {
02395               MHD_PANIC ("Failed to release cleanup mutex\n");
02396             }
02397           return MHD_NO;
02398         default:
02399           EXTRA_CHECK (0);
02400           break;
02401         }
02402       break;
02403     }
02404   timeout = connection->connection_timeout;
02405   if ( (timeout != 0) &&
02406        (timeout <= (MHD_monotonic_time() - connection->last_activity)) )
02407     {
02408       MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
02409       return MHD_YES;
02410     }
02411   return MHD_YES;
02412 }
02413 
02414 
02420 void
02421 MHD_set_http_callbacks_ (struct MHD_Connection *connection)
02422 {
02423   connection->read_handler = &MHD_connection_handle_read;
02424   connection->write_handler = &MHD_connection_handle_write;
02425   connection->idle_handler = &MHD_connection_handle_idle;
02426 }
02427 
02428 
02438 const union MHD_ConnectionInfo *
02439 MHD_get_connection_info (struct MHD_Connection *connection,
02440                          enum MHD_ConnectionInfoType infoType, ...)
02441 {
02442   switch (infoType)
02443     {
02444 #if HTTPS_SUPPORT
02445     case MHD_CONNECTION_INFO_CIPHER_ALGO:
02446       if (connection->tls_session == NULL)
02447         return NULL;
02448       connection->cipher = gnutls_cipher_get (connection->tls_session);
02449       return (const union MHD_ConnectionInfo *) &connection->cipher;
02450     case MHD_CONNECTION_INFO_PROTOCOL:
02451       if (connection->tls_session == NULL)
02452         return NULL;
02453       connection->protocol = gnutls_protocol_get_version (connection->tls_session);
02454       return (const union MHD_ConnectionInfo *) &connection->protocol;
02455     case MHD_CONNECTION_INFO_GNUTLS_SESSION:
02456       if (connection->tls_session == NULL)
02457         return NULL;
02458       return (const union MHD_ConnectionInfo *) &connection->tls_session;
02459 #endif
02460     case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
02461       return (const union MHD_ConnectionInfo *) &connection->addr;
02462     case MHD_CONNECTION_INFO_DAEMON:
02463       return (const union MHD_ConnectionInfo *) &connection->daemon;
02464     default:
02465       return NULL;
02466     };
02467 }
02468 
02469 
02478 int 
02479 MHD_set_connection_option (struct MHD_Connection *connection,
02480                            enum MHD_CONNECTION_OPTION option,
02481                            ...)
02482 {
02483   va_list ap;
02484 
02485   switch (option)
02486     {
02487     case MHD_CONNECTION_OPTION_TIMEOUT:
02488       va_start (ap, option);
02489       connection->connection_timeout = va_arg (ap, unsigned int);
02490       va_end (ap);
02491       return MHD_YES;
02492     default:
02493       return MHD_NO;
02494     }
02495 }
02496 
02497 
02498 /* end of connection.c */

Generated on 4 Sep 2013 for GNU libmicrohttpd by  doxygen 1.6.1