GNU libmicrohttpd  0.9.5
connection.c
Go to the documentation of this file.
00001 /*
00002     This file is part of libmicrohttpd
00003      (C) 2007, 2008, 2009, 2010 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 
00313 
00323 static int
00324 try_ready_normal_body (struct MHD_Connection *connection)
00325 {
00326   int ret;
00327   struct MHD_Response *response;
00328 
00329   response = connection->response;
00330   if (response->crc == NULL)
00331     return MHD_YES;
00332   if ( (response->data_start <=
00333         connection->response_write_position) &&
00334        (response->data_size + response->data_start >
00335         connection->response_write_position) )
00336     return MHD_YES; /* response already ready */
00337 #if LINUX
00338   if ( (response->fd != -1) &&
00339        (0 == (connection->daemon->options & MHD_USE_SSL)) )
00340     {
00341       /* will use sendfile, no need to bother response crc */
00342       return MHD_YES; 
00343     }
00344 #endif
00345   
00346   ret = response->crc (response->crc_cls,
00347                        connection->response_write_position,
00348                        response->data,
00349                        MHD_MIN (response->data_buffer_size,
00350                                 response->total_size -
00351                                 connection->response_write_position));
00352   if ((ret == 0) &&
00353       (0 != (connection->daemon->options & MHD_USE_SELECT_INTERNALLY)))
00354     mhd_panic (mhd_panic_cls, __FILE__, __LINE__, 
00355 #if HAVE_MESSAGES
00356                "API violation"
00357 #else
00358                NULL
00359 #endif
00360                );
00361   if ( (ret == MHD_CONTENT_READER_END_OF_STREAM) ||
00362        (ret == MHD_CONTENT_READER_END_WITH_ERROR) )
00363     {
00364       /* either error or http 1.0 transfer, close
00365          socket! */
00366 #if DEBUG_CLOSE
00367 #if HAVE_MESSAGES
00368       MHD_DLOG (connection->daemon, 
00369                 "Closing connection (end of response or error)\n");
00370 #endif
00371 #endif
00372       response->total_size = connection->response_write_position;
00373       connection_close_error (connection);
00374       return MHD_NO;
00375     }
00376   response->data_start = connection->response_write_position;
00377   response->data_size = ret;
00378   if (ret == 0)
00379     return MHD_NO;
00380   return MHD_YES;
00381 }
00382 
00383 
00392 static int
00393 try_ready_chunked_body (struct MHD_Connection *connection)
00394 {
00395   int ret;
00396   char *buf;
00397   struct MHD_Response *response;
00398   size_t size;
00399   char cbuf[10];                /* 10: max strlen of "%x\r\n" */
00400   int cblen;
00401 
00402   response = connection->response;
00403   if (connection->write_buffer_size == 0)
00404     {
00405       size = connection->daemon->pool_size;
00406       do
00407         {
00408           size /= 2;
00409           if (size < 128)
00410             {
00411               /* not enough memory */
00412 #if DEBUG_CLOSE
00413 #if HAVE_MESSAGES
00414               MHD_DLOG (connection->daemon,
00415                         "Closing connection (out of memory)\n");
00416 #endif
00417 #endif
00418               connection_close_error (connection);
00419               return MHD_NO;
00420             }
00421           buf = MHD_pool_allocate (connection->pool, size, MHD_NO);
00422         }
00423       while (buf == NULL);
00424       connection->write_buffer_size = size;
00425       connection->write_buffer = buf;
00426     }
00427 
00428   if ( (response->data_start <=
00429         connection->response_write_position) &&
00430        (response->data_size + response->data_start >
00431         connection->response_write_position) )
00432     {
00433       /* buffer already ready, use what is there for the chunk */
00434       ret = response->data_size + response->data_start - connection->response_write_position;
00435       if (ret > connection->write_buffer_size - sizeof (cbuf) - 2)
00436         ret = connection->write_buffer_size - sizeof (cbuf) - 2;
00437       memcpy (&connection->write_buffer[sizeof (cbuf)],
00438               &response->data[connection->response_write_position - response->data_start],
00439               ret);
00440     }
00441   else
00442     {
00443       /* buffer not in range, try to fill it */
00444       ret = response->crc (response->crc_cls,
00445                            connection->response_write_position,
00446                            &connection->write_buffer[sizeof (cbuf)],
00447                            connection->write_buffer_size - sizeof (cbuf) - 2);
00448     }
00449   if (ret == MHD_CONTENT_READER_END_WITH_ERROR) 
00450     {
00451       /* error, close socket! */
00452 #if DEBUG_CLOSE
00453 #if HAVE_MESSAGES
00454       MHD_DLOG (connection->daemon, 
00455                 "Closing connection (error generating response)\n");
00456 #endif
00457 #endif
00458       response->total_size = connection->response_write_position;
00459       connection_close_error (connection);
00460       return MHD_NO;
00461     }
00462   if (ret == MHD_CONTENT_READER_END_OF_STREAM) 
00463     {
00464       /* end of message, signal other side! */
00465       strcpy (connection->write_buffer, "0\r\n");
00466       connection->write_buffer_append_offset = 3;
00467       connection->write_buffer_send_offset = 0;
00468       response->total_size = connection->response_write_position;
00469       return MHD_YES;
00470     }
00471   if (ret == 0)
00472     {
00473       connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
00474       return MHD_NO;
00475     }
00476   if (ret > 0xFFFFFF)
00477     ret = 0xFFFFFF;
00478   snprintf (cbuf, 
00479             sizeof (cbuf),
00480             "%X\r\n", ret);
00481   cblen = strlen (cbuf);
00482   EXTRA_CHECK (cblen <= sizeof (cbuf));
00483   memcpy (&connection->write_buffer[sizeof (cbuf) - cblen], cbuf, cblen);
00484   memcpy (&connection->write_buffer[sizeof (cbuf) + ret], "\r\n", 2);
00485   connection->response_write_position += ret;
00486   connection->write_buffer_send_offset = sizeof (cbuf) - cblen;
00487   connection->write_buffer_append_offset = sizeof (cbuf) + ret + 2;
00488   return MHD_YES;
00489 }
00490 
00495 static void
00496 add_extra_headers (struct MHD_Connection *connection)
00497 {
00498   const char *have;
00499   char buf[128];
00500 
00501   connection->have_chunked_upload = MHD_NO;
00502   if (connection->response->total_size == MHD_SIZE_UNKNOWN)
00503     {
00504       have = MHD_get_response_header (connection->response,
00505                                       MHD_HTTP_HEADER_CONNECTION);
00506       if ((have == NULL) || (0 != strcasecmp (have, "close")))
00507         {
00508           if ((connection->version != NULL) &&
00509               (0 == strcasecmp (connection->version, MHD_HTTP_VERSION_1_1)))
00510             {
00511               connection->have_chunked_upload = MHD_YES;
00512               have = MHD_get_response_header (connection->response,
00513                                               MHD_HTTP_HEADER_TRANSFER_ENCODING);
00514               if (have == NULL)
00515                 MHD_add_response_header (connection->response,
00516                                          MHD_HTTP_HEADER_TRANSFER_ENCODING,
00517                                          "chunked");
00518             }
00519           else
00520             {
00521               MHD_add_response_header (connection->response,
00522                                        MHD_HTTP_HEADER_CONNECTION, "close");
00523             }
00524         }
00525     }
00526   else if (NULL == MHD_get_response_header (connection->response,
00527                                             MHD_HTTP_HEADER_CONTENT_LENGTH))
00528     {
00529       SPRINTF (buf,
00530                "%" MHD_LONG_LONG_PRINTF "u",
00531                (unsigned MHD_LONG_LONG)connection->response->total_size);
00532       MHD_add_response_header (connection->response,
00533                                MHD_HTTP_HEADER_CONTENT_LENGTH, buf);
00534     }
00535 }
00536 
00543 static void
00544 get_date_string (char *date)
00545 {
00546   static const char *days[] =
00547     { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
00548   static const char *mons[] =
00549     { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
00550     "Nov", "Dec"
00551   };
00552   struct tm now;
00553   time_t t;
00554 
00555   time (&t);
00556   gmtime_r (&t, &now);
00557   SPRINTF (date,
00558            "Date: %3s, %02u %3s %04u %02u:%02u:%02u GMT\r\n",
00559            days[now.tm_wday % 7],
00560            now.tm_mday,
00561            mons[now.tm_mon % 12],
00562            1900 + now.tm_year, now.tm_hour, now.tm_min, now.tm_sec);
00563 }
00564 
00570 static int
00571 try_grow_read_buffer (struct MHD_Connection *connection)
00572 {
00573   void *buf;
00574 
00575   buf = MHD_pool_reallocate (connection->pool,
00576                              connection->read_buffer,
00577                              connection->read_buffer_size,
00578                              connection->read_buffer_size * 2 +
00579                              MHD_BUF_INC_SIZE + 1);
00580   if (buf == NULL)
00581     return MHD_NO;
00582   /* we can actually grow the buffer, do it! */
00583   connection->read_buffer = buf;
00584   connection->read_buffer_size =
00585     connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00586   return MHD_YES;
00587 }
00588 
00595 static int
00596 build_header_response (struct MHD_Connection *connection)
00597 {
00598   size_t size;
00599   size_t off;
00600   struct MHD_HTTP_Header *pos;
00601   char code[256];
00602   char date[128];
00603   char *data;
00604   enum MHD_ValueKind kind;
00605   const char *reason_phrase;
00606   uint32_t rc;
00607 
00608   EXTRA_CHECK (NULL != connection->version);
00609   if (0 == strlen(connection->version))
00610     {
00611       data = MHD_pool_allocate (connection->pool, 0, MHD_YES);
00612       connection->write_buffer = data;
00613       connection->write_buffer_append_offset = 0;
00614       connection->write_buffer_send_offset = 0;
00615       connection->write_buffer_size = 0;
00616       return MHD_YES;
00617     }
00618   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00619     {
00620       add_extra_headers (connection);
00621       rc = connection->responseCode & (~MHD_ICY_FLAG);
00622       reason_phrase = MHD_get_reason_phrase_for (rc);
00623       SPRINTF (code,
00624                "%s %u %s\r\n",
00625                (0 != (connection->responseCode & MHD_ICY_FLAG))
00626                ? "ICY" 
00627                : ( (0 == strcasecmp (MHD_HTTP_VERSION_1_0,
00628                                      connection->version)) 
00629                    ? MHD_HTTP_VERSION_1_0 
00630                    : MHD_HTTP_VERSION_1_1),
00631                rc, 
00632                reason_phrase);
00633       off = strlen (code);
00634       /* estimate size */
00635       size = off + 2;           /* extra \r\n at the end */
00636       kind = MHD_HEADER_KIND;
00637       if (NULL == MHD_get_response_header (connection->response,
00638                                            MHD_HTTP_HEADER_DATE))
00639         get_date_string (date);
00640       else
00641         date[0] = '\0';
00642       size += strlen (date);
00643     }
00644   else
00645     {
00646       size = 2;
00647       kind = MHD_FOOTER_KIND;
00648       off = 0;
00649     }
00650   pos = connection->response->first_header;
00651   while (pos != NULL)
00652     {
00653       if (pos->kind == kind)
00654         size += strlen (pos->header) + strlen (pos->value) + 4; /* colon, space, linefeeds */
00655       pos = pos->next;
00656     }
00657   /* produce data */
00658   data = MHD_pool_allocate (connection->pool, size + 1, MHD_YES);
00659   if (data == NULL)
00660     {
00661 #if HAVE_MESSAGES
00662       MHD_DLOG (connection->daemon, "Not enough memory for write!\n");
00663 #endif
00664       return MHD_NO;
00665     }
00666   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00667     {
00668       memcpy (data, code, off);
00669     }
00670   pos = connection->response->first_header;
00671   while (pos != NULL)
00672     {
00673       if (pos->kind == kind)
00674         off += SPRINTF (&data[off], "%s: %s\r\n", pos->header, pos->value);
00675       pos = pos->next;
00676     }
00677   if (connection->state == MHD_CONNECTION_FOOTERS_RECEIVED)
00678     {
00679       strcpy (&data[off], date);
00680       off += strlen (date);
00681     }
00682   memcpy (&data[off], "\r\n", 2);
00683   off += 2;
00684   if (off != size)
00685     mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL);
00686   connection->write_buffer = data;
00687   connection->write_buffer_append_offset = size;
00688   connection->write_buffer_send_offset = 0;
00689   connection->write_buffer_size = size + 1;
00690   return MHD_YES;
00691 }
00692 
00700 static void
00701 transmit_error_response (struct MHD_Connection *connection,
00702                          unsigned int status_code, const char *message)
00703 {
00704   struct MHD_Response *response;
00705 
00706   if (connection->version == NULL)
00707     {
00708       /* we were unable to process the full header line, so we don't
00709          really know what version the client speaks; assume 1.0 */
00710       connection->version = MHD_HTTP_VERSION_1_0;
00711     }
00712   connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
00713   connection->read_closed = MHD_YES;
00714 #if HAVE_MESSAGES
00715   MHD_DLOG (connection->daemon,
00716             "Error %u (`%s') processing request, closing connection.\n",
00717             status_code, message);
00718 #endif
00719   EXTRA_CHECK (connection->response == NULL);
00720   response = MHD_create_response_from_buffer (strlen (message),
00721                                               (void *) message, 
00722                                               MHD_RESPMEM_PERSISTENT);
00723   MHD_queue_response (connection, status_code, response);
00724   EXTRA_CHECK (connection->response != NULL);
00725   MHD_destroy_response (response);
00726   if (MHD_NO == build_header_response (connection))
00727     {
00728       /* oops - close! */
00729 #if HAVE_MESSAGES
00730       MHD_DLOG (connection->daemon,
00731                 "Closing connection (failed to create response header)\n");
00732 #endif
00733       connection->state = MHD_CONNECTION_CLOSED;
00734     }
00735   else
00736     {
00737       connection->state = MHD_CONNECTION_HEADERS_SENDING;
00738     }
00739 }
00740 
00745 static void
00746 do_fd_set (int fd, fd_set * set, int *max_fd)
00747 {
00748   FD_SET (fd, set);
00749   if ( (NULL != max_fd) &&
00750        (fd > *max_fd) )
00751     *max_fd = fd;
00752 }
00753 
00759 int
00760 MHD_connection_get_fdset (struct MHD_Connection *connection,
00761                           fd_set * read_fd_set,
00762                           fd_set * write_fd_set,
00763                           fd_set * except_fd_set, int *max_fd)
00764 {
00765   int ret;
00766   struct MHD_Pollfd p;
00767 
00768   memset(&p, 0, sizeof(struct MHD_Pollfd));
00769   ret = MHD_connection_get_pollfd(connection, &p);
00770   if ( (ret == MHD_YES) && (p.fd >= 0) ) {
00771     if (0 != (p.events & MHD_POLL_ACTION_IN)) 
00772       do_fd_set(p.fd, read_fd_set, max_fd);    
00773     if (0 != (p.events & MHD_POLL_ACTION_OUT)) 
00774       do_fd_set(p.fd, write_fd_set, max_fd);    
00775   }
00776   return ret;
00777 }
00778 
00785 int
00786 MHD_connection_get_pollfd (struct MHD_Connection *connection, struct MHD_Pollfd *p)
00787 {
00788   int fd;
00789 
00790   if (connection->pool == NULL)
00791     connection->pool = MHD_pool_create (connection->daemon->pool_size);
00792   if (connection->pool == NULL)
00793     {
00794 #if HAVE_MESSAGES
00795       MHD_DLOG (connection->daemon, "Failed to create memory pool!\n");
00796 #endif
00797       connection_close_error (connection);
00798       return MHD_NO;
00799     }
00800   fd = connection->socket_fd;
00801   p->fd = fd;
00802   if (fd == -1)
00803     return MHD_YES;
00804   while (1)
00805     {
00806 #if DEBUG_STATES
00807       MHD_DLOG (connection->daemon, "%s: state: %s\n",
00808                 __FUNCTION__, MHD_state_to_string (connection->state));
00809 #endif
00810       switch (connection->state)
00811         {
00812 #if HTTPS_SUPPORT     
00813         case MHD_TLS_CONNECTION_INIT:
00814           if (0 == gnutls_record_get_direction (connection->tls_session))
00815             p->events |= MHD_POLL_ACTION_IN;
00816           else
00817             p->events |= MHD_POLL_ACTION_OUT;
00818           break;
00819 #endif
00820         case MHD_CONNECTION_INIT:
00821         case MHD_CONNECTION_URL_RECEIVED:
00822         case MHD_CONNECTION_HEADER_PART_RECEIVED:
00823           /* while reading headers, we always grow the
00824              read buffer if needed, no size-check required */
00825           if ((connection->read_closed) &&
00826               (connection->read_buffer_offset == 0))
00827             {
00828               connection->state = MHD_CONNECTION_CLOSED;
00829               continue;
00830             }
00831           if ((connection->read_buffer_offset == connection->read_buffer_size)
00832               && (MHD_NO == try_grow_read_buffer (connection)))
00833             {
00834               transmit_error_response (connection,
00835                                        (connection->url != NULL)
00836                                        ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00837                                        : MHD_HTTP_REQUEST_URI_TOO_LONG,
00838                                        REQUEST_TOO_BIG);
00839               continue;
00840             }
00841           if (MHD_NO == connection->read_closed)
00842             p->events |= MHD_POLL_ACTION_IN;
00843           break;
00844         case MHD_CONNECTION_HEADERS_RECEIVED:
00845           /* we should never get here */
00846           EXTRA_CHECK (0);
00847           break;
00848         case MHD_CONNECTION_HEADERS_PROCESSED:
00849           EXTRA_CHECK (0);
00850           break;
00851         case MHD_CONNECTION_CONTINUE_SENDING:
00852           p->events |= MHD_POLL_ACTION_OUT;
00853           break;
00854         case MHD_CONNECTION_CONTINUE_SENT:
00855           if (connection->read_buffer_offset == connection->read_buffer_size)
00856             {
00857               if ((MHD_YES != try_grow_read_buffer (connection)) &&
00858                   (0 != (connection->daemon->options &
00859                          (MHD_USE_SELECT_INTERNALLY |
00860                           MHD_USE_THREAD_PER_CONNECTION))))
00861                 {
00862                   /* failed to grow the read buffer, and the
00863                      client which is supposed to handle the
00864                      received data in a *blocking* fashion
00865                      (in this mode) did not handle the data as
00866                      it was supposed to!
00867                      => we would either have to do busy-waiting
00868                      (on the client, which would likely fail),
00869                      or if we do nothing, we would just timeout
00870                      on the connection (if a timeout is even
00871                      set!).
00872                      Solution: we kill the connection with an error */
00873                   transmit_error_response (connection,
00874                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
00875                                            INTERNAL_ERROR);
00876                   continue;
00877                 }
00878             }
00879           if ((connection->read_buffer_offset < connection->read_buffer_size)
00880               && (MHD_NO == connection->read_closed))
00881             p->events |= MHD_POLL_ACTION_IN;
00882           break;
00883         case MHD_CONNECTION_BODY_RECEIVED:
00884         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
00885           /* while reading footers, we always grow the
00886              read buffer if needed, no size-check required */
00887           if (MHD_YES == connection->read_closed)
00888             {
00889               connection->state = MHD_CONNECTION_CLOSED;
00890               continue;
00891             }
00892           p->events |= MHD_POLL_ACTION_IN;
00893           /* transition to FOOTERS_RECEIVED
00894              happens in read handler */
00895           break;
00896         case MHD_CONNECTION_FOOTERS_RECEIVED:
00897           /* no socket action, wait for client
00898              to provide response */
00899           break;
00900         case MHD_CONNECTION_HEADERS_SENDING:
00901           /* headers in buffer, keep writing */
00902           p->events |= MHD_POLL_ACTION_OUT;
00903           break;
00904         case MHD_CONNECTION_HEADERS_SENT:
00905           EXTRA_CHECK (0);
00906           break;
00907         case MHD_CONNECTION_NORMAL_BODY_READY:
00908           p->events |= MHD_POLL_ACTION_OUT;
00909           break;
00910         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
00911           /* not ready, no socket action */
00912           break;
00913         case MHD_CONNECTION_CHUNKED_BODY_READY:
00914           p->events |= MHD_POLL_ACTION_OUT;
00915           break;
00916         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
00917           /* not ready, no socket action */
00918           break;
00919         case MHD_CONNECTION_BODY_SENT:
00920           EXTRA_CHECK (0);
00921           break;
00922         case MHD_CONNECTION_FOOTERS_SENDING:
00923           p->events |= MHD_POLL_ACTION_OUT;
00924           break;
00925         case MHD_CONNECTION_FOOTERS_SENT:
00926           EXTRA_CHECK (0);
00927           break;
00928         case MHD_CONNECTION_CLOSED:
00929           if (connection->socket_fd != -1)
00930             connection_close_error (connection);
00931           return MHD_YES;       /* do nothing, not even reading */
00932 
00933         default:
00934           EXTRA_CHECK (0);
00935         }
00936       break;
00937     }
00938   return MHD_YES;
00939 }
00940 
00949 static char *
00950 get_next_header_line (struct MHD_Connection *connection)
00951 {
00952   char *rbuf;
00953   size_t pos;
00954 
00955   if (connection->read_buffer_offset == 0)
00956     return NULL;
00957   pos = 0;
00958   rbuf = connection->read_buffer;
00959   while ((pos < connection->read_buffer_offset - 1) &&
00960          (rbuf[pos] != '\r') && (rbuf[pos] != '\n'))
00961     pos++;
00962   if (pos == connection->read_buffer_offset - 1)
00963     {
00964       /* not found, consider growing... */
00965       if (connection->read_buffer_offset == connection->read_buffer_size)
00966         {
00967           rbuf = MHD_pool_reallocate (connection->pool,
00968                                       connection->read_buffer,
00969                                       connection->read_buffer_size,
00970                                       connection->read_buffer_size * 2 +
00971                                       MHD_BUF_INC_SIZE);
00972           if (rbuf == NULL)
00973             {
00974               transmit_error_response (connection,
00975                                        (connection->url != NULL)
00976                                        ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
00977                                        : MHD_HTTP_REQUEST_URI_TOO_LONG,
00978                                        REQUEST_TOO_BIG);
00979             }
00980           else
00981             {
00982               connection->read_buffer_size =
00983                 connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
00984               connection->read_buffer = rbuf;
00985             }
00986         }
00987       return NULL;
00988     }
00989   /* found, check if we have proper CRLF */
00990   if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n'))
00991     rbuf[pos++] = '\0';         /* skip both r and n */
00992   rbuf[pos++] = '\0';
00993   connection->read_buffer += pos;
00994   connection->read_buffer_size -= pos;
00995   connection->read_buffer_offset -= pos;
00996   return rbuf;
00997 }
00998 
01002 static int
01003 connection_add_header (struct MHD_Connection *connection,
01004                        char *key, char *value, enum MHD_ValueKind kind)
01005 {
01006   struct MHD_HTTP_Header *hdr;
01007 
01008   hdr = MHD_pool_allocate (connection->pool,
01009                            sizeof (struct MHD_HTTP_Header), MHD_YES);
01010   if (hdr == NULL)
01011     {
01012 #if HAVE_MESSAGES
01013       MHD_DLOG (connection->daemon,
01014                 "Not enough memory to allocate header record!\n");
01015 #endif
01016       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01017                                REQUEST_TOO_BIG);
01018       return MHD_NO;
01019     }
01020   hdr->next = connection->headers_received;
01021   hdr->header = key;
01022   hdr->value = value;
01023   hdr->kind = kind;
01024   connection->headers_received = hdr;
01025   return MHD_YES;
01026 }
01027 
01031 static int
01032 parse_arguments (enum MHD_ValueKind kind,
01033                  struct MHD_Connection *connection, char *args)
01034 {
01035   char *equals;
01036   char *amper;
01037 
01038   while (args != NULL)
01039     {
01040       equals = strstr (args, "=");
01041       if (equals == NULL)
01042         return MHD_NO;          /* invalid, ignore */
01043       equals[0] = '\0';
01044       equals++;
01045       amper = strstr (equals, "&");
01046       if (amper != NULL)
01047         {
01048           amper[0] = '\0';
01049           amper++;
01050         }
01051       connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01052                                              connection,
01053                                              args);
01054       connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01055                                              connection,
01056                                              equals);
01057       if (MHD_NO == connection_add_header (connection, args, equals, kind))
01058         return MHD_NO;
01059       args = amper;
01060     }
01061   return MHD_YES;
01062 }
01063 
01069 static int
01070 parse_cookie_header (struct MHD_Connection *connection)
01071 {
01072   const char *hdr;
01073   char *cpy;
01074   char *pos;
01075   char *sce;
01076   char *semicolon;
01077   char *equals;
01078   char *ekill;
01079   char old;
01080   int quotes;
01081 
01082   hdr = MHD_lookup_connection_value (connection,
01083                                      MHD_HEADER_KIND,
01084                                      MHD_HTTP_HEADER_COOKIE);
01085   if (hdr == NULL)
01086     return MHD_YES;
01087   cpy = MHD_pool_allocate (connection->pool, strlen (hdr) + 1, MHD_YES);
01088   if (cpy == NULL)
01089     {
01090 #if HAVE_MESSAGES
01091       MHD_DLOG (connection->daemon, "Not enough memory to parse cookies!\n");
01092 #endif
01093       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01094                                REQUEST_TOO_BIG);
01095       return MHD_NO;
01096     }
01097   memcpy (cpy, hdr, strlen (hdr) + 1);
01098   pos = cpy;
01099   while (pos != NULL)
01100     {
01101       while (*pos == ' ')
01102         pos++;                  /* skip spaces */
01103 
01104       sce = pos;
01105       while (((*sce) != '\0') &&
01106              ((*sce) != ',') && ((*sce) != ';') && ((*sce) != '='))
01107         sce++;
01108       /* remove tailing whitespace (if any) from key */
01109       ekill = sce - 1;
01110       while ((*ekill == ' ') && (ekill >= pos))
01111         *(ekill--) = '\0';
01112       old = *sce;
01113       *sce = '\0';
01114       if (old != '=')
01115         {
01116           /* value part omitted, use empty string... */
01117           if (MHD_NO ==
01118               connection_add_header (connection, pos, "", MHD_COOKIE_KIND))
01119             return MHD_NO;
01120           if (old == '\0')
01121             break;
01122           pos = sce + 1;
01123           continue;
01124         }
01125       equals = sce + 1;
01126       quotes = 0;
01127       semicolon = equals;
01128       while ((semicolon[0] != '\0') &&
01129              ((quotes != 0) ||
01130               ((semicolon[0] != ';') && (semicolon[0] != ','))))
01131         {
01132           if (semicolon[0] == '"')
01133             quotes = (quotes + 1) & 1;
01134           semicolon++;
01135         }
01136       if (semicolon[0] == '\0')
01137         semicolon = NULL;
01138       if (semicolon != NULL)
01139         {
01140           semicolon[0] = '\0';
01141           semicolon++;
01142         }
01143       /* remove quotes */
01144       if ((equals[0] == '"') && (equals[strlen (equals) - 1] == '"'))
01145         {
01146           equals[strlen (equals) - 1] = '\0';
01147           equals++;
01148         }
01149       if (MHD_NO == connection_add_header (connection,
01150                                            pos, equals, MHD_COOKIE_KIND))
01151         return MHD_NO;
01152       pos = semicolon;
01153     }
01154   return MHD_YES;
01155 }
01156 
01164 static int
01165 parse_initial_message_line (struct MHD_Connection *connection, char *line)
01166 {
01167   char *uri;
01168   char *httpVersion;
01169   char *args;
01170 
01171   uri = strstr (line, " ");
01172   if (uri == NULL)
01173     return MHD_NO;              /* serious error */
01174   uri[0] = '\0';
01175   connection->method = line;
01176   uri++;
01177   while (uri[0] == ' ')
01178     uri++;
01179   httpVersion = strstr (uri, " ");
01180   if (httpVersion != NULL)
01181     {
01182       httpVersion[0] = '\0';
01183       httpVersion++;
01184     }
01185   if (connection->daemon->uri_log_callback != NULL)
01186     connection->client_context
01187       =
01188       connection->daemon->uri_log_callback (connection->daemon->
01189                                             uri_log_callback_cls, uri);
01190   args = strstr (uri, "?");
01191   if (args != NULL)
01192     {
01193       args[0] = '\0';
01194       args++;
01195       parse_arguments (MHD_GET_ARGUMENT_KIND, connection, args);
01196     }
01197   connection->daemon->unescape_callback (connection->daemon->unescape_callback_cls,
01198                                          connection,
01199                                          uri);
01200   connection->url = uri;
01201   if (httpVersion == NULL)
01202     connection->version = "";
01203   else
01204     connection->version = httpVersion;
01205   return MHD_YES;
01206 }
01207 
01208 
01214 static void
01215 call_connection_handler (struct MHD_Connection *connection)
01216 {
01217   size_t processed;
01218 
01219   if (connection->response != NULL)
01220     return;                     /* already queued a response */  
01221   processed = 0;
01222   connection->client_aware = MHD_YES;
01223   if (MHD_NO ==
01224       connection->daemon->default_handler (connection->daemon->
01225                                            default_handler_cls,
01226                                            connection, connection->url,
01227                                            connection->method,
01228                                            connection->version,
01229                                            NULL, &processed,
01230                                            &connection->client_context))
01231     {
01232       /* serious internal error, close connection */
01233 #if HAVE_MESSAGES
01234       MHD_DLOG (connection->daemon,
01235                 "Internal application error, closing connection.\n");
01236 #endif
01237       connection_close_error (connection);
01238       return;
01239     }
01240 }
01241 
01242 
01243 
01249 static void
01250 process_request_body (struct MHD_Connection *connection)
01251 {
01252   size_t processed;
01253   size_t available;
01254   size_t used;
01255   size_t i;
01256   int instant_retry;
01257   int malformed;
01258   char *buffer_head;
01259 
01260   if (connection->response != NULL)
01261     return;                     /* already queued a response */
01262 
01263   buffer_head = connection->read_buffer;
01264   available = connection->read_buffer_offset;
01265   do
01266     {
01267       instant_retry = MHD_NO;
01268       if ((connection->have_chunked_upload == MHD_YES) &&
01269           (connection->remaining_upload_size == MHD_SIZE_UNKNOWN))
01270         {
01271           if ((connection->current_chunk_offset ==
01272                connection->current_chunk_size)
01273               && (connection->current_chunk_offset != 0) && (available >= 2))
01274             {
01275               /* skip new line at the *end* of a chunk */
01276               i = 0;
01277               if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01278                 i++;            /* skip 1st part of line feed */
01279               if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01280                 i++;            /* skip 2nd part of line feed */
01281               if (i == 0)
01282                 {
01283                   /* malformed encoding */
01284 #if HAVE_MESSAGES
01285                   MHD_DLOG (connection->daemon,
01286                             "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01287 #endif
01288                   connection_close_error (connection);
01289                   return;
01290                 }
01291               available -= i;
01292               buffer_head += i;
01293               connection->current_chunk_offset = 0;
01294               connection->current_chunk_size = 0;
01295             }
01296           if (connection->current_chunk_offset <
01297               connection->current_chunk_size)
01298             {
01299               /* we are in the middle of a chunk, give
01300                  as much as possible to the client (without
01301                  crossing chunk boundaries) */
01302               processed =
01303                 connection->current_chunk_size -
01304                 connection->current_chunk_offset;
01305               if (processed > available)
01306                 processed = available;
01307               if (available > processed)
01308                 instant_retry = MHD_YES;
01309             }
01310           else
01311             {
01312               /* we need to read chunk boundaries */
01313               i = 0;
01314               while (i < available)
01315                 {
01316                   if ((buffer_head[i] == '\r') || (buffer_head[i] == '\n'))
01317                     break;
01318                   i++;
01319                   if (i >= 6)
01320                     break;
01321                 }
01322               /* take '\n' into account; if '\n'
01323                  is the unavailable character, we
01324                  will need to wait until we have it
01325                  before going further */
01326               if ((i + 1 >= available) &&
01327                   !((i == 1) && (available == 2) && (buffer_head[0] == '0')))
01328                 break;          /* need more data... */
01329               malformed = (i >= 6);
01330               if (!malformed)
01331                 {
01332                   buffer_head[i] = '\0';
01333                   malformed =
01334                     (1 != SSCANF (buffer_head, "%X",
01335                                   &connection->current_chunk_size)) &&
01336                     (1 != SSCANF (buffer_head, "%x",
01337                                   &connection->current_chunk_size));
01338                 }
01339               if (malformed)
01340                 {
01341                   /* malformed encoding */
01342 #if HAVE_MESSAGES
01343                   MHD_DLOG (connection->daemon,
01344                             "Received malformed HTTP request (bad chunked encoding), closing connection.\n");
01345 #endif
01346                   connection_close_error (connection);
01347                   return;
01348                 }
01349               i++;
01350               if ((i < available) &&
01351                   ((buffer_head[i] == '\r') || (buffer_head[i] == '\n')))
01352                 i++;            /* skip 2nd part of line feed */
01353 
01354               buffer_head += i;
01355               available -= i;
01356               connection->current_chunk_offset = 0;
01357 
01358               if (available > 0)
01359                 instant_retry = MHD_YES;
01360               if (connection->current_chunk_size == 0)
01361                 {
01362                   connection->remaining_upload_size = 0;
01363                   break;
01364                 }
01365               continue;
01366             }
01367         }
01368       else
01369         {
01370           /* no chunked encoding, give all to the client */
01371           processed = available;
01372         }
01373       used = processed;
01374       connection->client_aware = MHD_YES;
01375       if (MHD_NO ==
01376           connection->daemon->default_handler (connection->daemon->
01377                                                default_handler_cls,
01378                                                connection, connection->url,
01379                                                connection->method,
01380                                                connection->version,
01381                                                buffer_head, &processed,
01382                                                &connection->client_context))
01383         {
01384           /* serious internal error, close connection */
01385 #if HAVE_MESSAGES
01386           MHD_DLOG (connection->daemon,
01387                     "Internal application error, closing connection.\n");
01388 #endif
01389           connection_close_error (connection);
01390           return;
01391         }
01392       if (processed > used)
01393         mhd_panic (mhd_panic_cls, __FILE__, __LINE__, 
01394 #if HAVE_MESSAGES
01395                    "API violation"
01396 #else
01397                    NULL
01398 #endif
01399                    );
01400       if (processed != 0)
01401         instant_retry = MHD_NO; /* client did not process everything */
01402       used -= processed;
01403       if (connection->have_chunked_upload == MHD_YES)
01404         connection->current_chunk_offset += used;
01405       /* dh left "processed" bytes in buffer for next time... */
01406       buffer_head += used;
01407       available -= used;
01408       if (connection->remaining_upload_size != MHD_SIZE_UNKNOWN)
01409         connection->remaining_upload_size -= used;
01410     }
01411   while (instant_retry == MHD_YES);
01412   if (available > 0)
01413     memmove (connection->read_buffer, buffer_head, available);
01414   connection->read_buffer_offset = available;
01415 }
01416 
01425 static int
01426 do_read (struct MHD_Connection *connection)
01427 {
01428   int bytes_read;
01429 
01430   if (connection->read_buffer_size == connection->read_buffer_offset)
01431     return MHD_NO;
01432 
01433   bytes_read = connection->recv_cls (connection,
01434                                      &connection->read_buffer
01435                                      [connection->read_buffer_offset],
01436                                      connection->read_buffer_size -
01437                                      connection->read_buffer_offset);
01438   if (bytes_read < 0)
01439     {
01440       if (errno == EINTR)
01441         return MHD_NO;
01442 #if HAVE_MESSAGES
01443 #if HTTPS_SUPPORT
01444       if (0 != (connection->daemon->options & MHD_USE_SSL))
01445         MHD_DLOG (connection->daemon,
01446                   "Failed to receive data: %s\n",
01447                   gnutls_strerror (bytes_read));
01448       else
01449 #endif      
01450         MHD_DLOG (connection->daemon,
01451                   "Failed to receive data: %s\n", STRERROR (errno));
01452 #endif
01453       connection_close_error (connection);
01454       return MHD_YES;
01455     }
01456   if (bytes_read == 0)
01457     {
01458       /* other side closed connection */
01459       connection->read_closed = MHD_YES;
01460       SHUTDOWN (connection->socket_fd, SHUT_RD);
01461       return MHD_YES;
01462     }
01463   connection->read_buffer_offset += bytes_read;
01464   return MHD_YES;
01465 }
01466 
01474 static int
01475 do_write (struct MHD_Connection *connection)
01476 {
01477   int ret;
01478 
01479   ret = connection->send_cls (connection,
01480                               &connection->write_buffer
01481                               [connection->write_buffer_send_offset],
01482                               connection->write_buffer_append_offset
01483                               - connection->write_buffer_send_offset);
01484 
01485   if (ret < 0)
01486     {
01487       if (errno == EINTR)
01488         return MHD_NO;
01489 #if HAVE_MESSAGES
01490 #if HTTPS_SUPPORT
01491       if (0 != (connection->daemon->options & MHD_USE_SSL))
01492         MHD_DLOG (connection->daemon,
01493                   "Failed to send data: %s\n",
01494                   gnutls_strerror (ret));
01495       else
01496 #endif      
01497         MHD_DLOG (connection->daemon,
01498                   "Failed to send data: %s\n", STRERROR (errno));
01499 #endif
01500       connection_close_error (connection);
01501       return MHD_YES;
01502     }
01503 #if DEBUG_SEND_DATA
01504   FPRINTF (stderr,
01505            "Sent response: `%.*s'\n",
01506            ret,
01507            &connection->write_buffer[connection->write_buffer_send_offset]);
01508 #endif
01509   connection->write_buffer_send_offset += ret;
01510   return MHD_YES;
01511 }
01512 
01518 static int
01519 check_write_done (struct MHD_Connection *connection,
01520                   enum MHD_CONNECTION_STATE next_state)
01521 {
01522   if (connection->write_buffer_append_offset !=
01523       connection->write_buffer_send_offset)
01524     return MHD_NO;
01525   connection->write_buffer_append_offset = 0;
01526   connection->write_buffer_send_offset = 0;
01527   connection->state = next_state;
01528   MHD_pool_reallocate (connection->pool, connection->write_buffer,
01529                        connection->write_buffer_size, 0);
01530   connection->write_buffer = NULL;
01531   connection->write_buffer_size = 0;
01532   return MHD_YES;
01533 }
01534 
01540 static int
01541 process_header_line (struct MHD_Connection *connection, char *line)
01542 {
01543   char *colon;
01544 
01545   /* line should be normal header line, find colon */
01546   colon = strstr (line, ":");
01547   if (colon == NULL)
01548     {
01549       /* error in header line, die hard */
01550 #if HAVE_MESSAGES
01551       MHD_DLOG (connection->daemon,
01552                 "Received malformed line (no colon), closing connection.\n");
01553 #endif
01554       connection->state = MHD_CONNECTION_CLOSED;
01555       return MHD_NO;
01556     }
01557   /* zero-terminate header */
01558   colon[0] = '\0';
01559   colon++;                      /* advance to value */
01560   while ((colon[0] != '\0') && ((colon[0] == ' ') || (colon[0] == '\t')))
01561     colon++;
01562   /* we do the actual adding of the connection
01563      header at the beginning of the while
01564      loop since we need to be able to inspect
01565      the *next* header line (in case it starts
01566      with a space...) */
01567   connection->last = line;
01568   connection->colon = colon;
01569   return MHD_YES;
01570 }
01571 
01581 static int
01582 process_broken_line (struct MHD_Connection *connection,
01583                      char *line, enum MHD_ValueKind kind)
01584 {
01585   char *last;
01586   char *tmp;
01587   size_t last_len;
01588   size_t tmp_len;
01589 
01590   last = connection->last;
01591   if ((line[0] == ' ') || (line[0] == '\t'))
01592     {
01593       /* value was continued on the next line, see
01594          http://www.jmarshall.com/easy/http/ */
01595       last_len = strlen (last);
01596       /* skip whitespace at start of 2nd line */
01597       tmp = line;
01598       while ((tmp[0] == ' ') || (tmp[0] == '\t'))
01599         tmp++;                  
01600       tmp_len = strlen (tmp);
01601       last = MHD_pool_reallocate (connection->pool,
01602                                   last,
01603                                   last_len + 1,
01604                                   last_len + tmp_len + 1);
01605       if (last == NULL)
01606         {
01607           transmit_error_response (connection,
01608                                    MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01609                                    REQUEST_TOO_BIG);
01610           return MHD_NO;
01611         }
01612       memcpy (&last[last_len], tmp, tmp_len + 1);
01613       connection->last = last;
01614       return MHD_YES;           /* possibly more than 2 lines... */
01615     }
01616   EXTRA_CHECK ((last != NULL) && (connection->colon != NULL));
01617   if ((MHD_NO == connection_add_header (connection,
01618                                         last, connection->colon, kind)))
01619     {
01620       transmit_error_response (connection, MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
01621                                REQUEST_TOO_BIG);
01622       return MHD_NO;
01623     }
01624   /* we still have the current line to deal with... */
01625   if (strlen (line) != 0)
01626     {
01627       if (MHD_NO == process_header_line (connection, line))
01628         {
01629           transmit_error_response (connection,
01630                                    MHD_HTTP_BAD_REQUEST, REQUEST_MALFORMED);
01631           return MHD_NO;
01632         }
01633     }
01634   return MHD_YES;
01635 }
01636 
01642 static void
01643 parse_connection_headers (struct MHD_Connection *connection)
01644 {
01645   const char *clen;
01646   unsigned MHD_LONG_LONG cval;
01647   struct MHD_Response *response;
01648   const char *enc;
01649 
01650   parse_cookie_header (connection);
01651   if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
01652       && (NULL != connection->version)
01653       && (0 == strcasecmp (MHD_HTTP_VERSION_1_1, connection->version))
01654       && (NULL ==
01655           MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
01656                                        MHD_HTTP_HEADER_HOST)))
01657     {
01658       /* die, http 1.1 request without host and we are pedantic */
01659       connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
01660       connection->read_closed = MHD_YES;
01661 #if HAVE_MESSAGES
01662       MHD_DLOG (connection->daemon,
01663                 "Received `%s' request without `%s' header.\n",
01664                 MHD_HTTP_VERSION_1_1, MHD_HTTP_HEADER_HOST);
01665 #endif
01666       EXTRA_CHECK (connection->response == NULL);
01667       response =
01668         MHD_create_response_from_buffer (strlen (REQUEST_LACKS_HOST),
01669                                          REQUEST_LACKS_HOST,
01670                                          MHD_RESPMEM_PERSISTENT);
01671       MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, response);
01672       MHD_destroy_response (response);
01673       return;
01674     }
01675 
01676   clen = MHD_lookup_connection_value (connection,
01677                                       MHD_HEADER_KIND,
01678                                       MHD_HTTP_HEADER_CONTENT_LENGTH);
01679   if (clen != NULL)
01680     {
01681       if (1 != SSCANF (clen, "%" MHD_LONG_LONG_PRINTF "u", &cval))
01682         {
01683 #if HAVE_MESSAGES
01684           MHD_DLOG (connection->daemon,
01685                     "Failed to parse `%s' header `%s', closing connection.\n",
01686                     MHD_HTTP_HEADER_CONTENT_LENGTH, clen);
01687 #endif
01688           connection->state = MHD_CONNECTION_CLOSED;
01689           return;
01690         }
01691       connection->remaining_upload_size = cval;
01692     }
01693   else
01694     {
01695       enc = MHD_lookup_connection_value (connection,
01696                                          MHD_HEADER_KIND,
01697                                          MHD_HTTP_HEADER_TRANSFER_ENCODING);
01698       if (NULL == enc)
01699         {
01700           /* this request (better) not have a body */
01701           connection->remaining_upload_size = 0;
01702         }
01703       else
01704         {
01705           connection->remaining_upload_size = MHD_SIZE_UNKNOWN;
01706           if (0 == strcasecmp (enc, "chunked"))
01707             connection->have_chunked_upload = MHD_YES;
01708         }
01709     }
01710 }
01711 
01721 int
01722 MHD_connection_handle_read (struct MHD_Connection *connection)
01723 {
01724   connection->last_activity = time (NULL);
01725   if (connection->state == MHD_CONNECTION_CLOSED)
01726     return MHD_NO;
01727   /* make sure "read" has a reasonable number of bytes
01728      in buffer to use per system call (if possible) */
01729   if (connection->read_buffer_offset + MHD_BUF_INC_SIZE >
01730       connection->read_buffer_size)
01731     try_grow_read_buffer (connection);
01732   if (MHD_NO == do_read (connection))
01733     return MHD_YES;
01734   while (1)
01735     {
01736 #if DEBUG_STATES
01737       MHD_DLOG (connection->daemon, "%s: state: %s\n",
01738                 __FUNCTION__, MHD_state_to_string (connection->state));
01739 #endif
01740       switch (connection->state)
01741         {
01742         case MHD_CONNECTION_INIT:
01743         case MHD_CONNECTION_URL_RECEIVED:
01744         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01745         case MHD_CONNECTION_HEADERS_RECEIVED:
01746         case MHD_CONNECTION_HEADERS_PROCESSED:
01747         case MHD_CONNECTION_CONTINUE_SENDING:
01748         case MHD_CONNECTION_CONTINUE_SENT:
01749         case MHD_CONNECTION_BODY_RECEIVED:
01750         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01751           /* nothing to do but default action */
01752           if (MHD_YES == connection->read_closed)
01753             {
01754               connection->state = MHD_CONNECTION_CLOSED;
01755               continue;
01756             }
01757           break;
01758         case MHD_CONNECTION_CLOSED:
01759           if (connection->socket_fd != -1)
01760             connection_close_error (connection);
01761           return MHD_NO;
01762         default:
01763           /* shrink read buffer to how much is actually used */
01764           MHD_pool_reallocate (connection->pool,
01765                                connection->read_buffer,
01766                                connection->read_buffer_size + 1,
01767                                connection->read_buffer_offset);
01768           break;
01769         }
01770       break;
01771     }
01772   return MHD_YES;
01773 }
01774 
01784 int
01785 MHD_connection_handle_write (struct MHD_Connection *connection)
01786 {
01787   struct MHD_Response *response;
01788   int ret;
01789   connection->last_activity = time (NULL);
01790   while (1)
01791     {
01792 #if DEBUG_STATES
01793       MHD_DLOG (connection->daemon, "%s: state: %s\n",
01794                 __FUNCTION__, MHD_state_to_string (connection->state));
01795 #endif
01796       switch (connection->state)
01797         {
01798         case MHD_CONNECTION_INIT:
01799         case MHD_CONNECTION_URL_RECEIVED:
01800         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01801         case MHD_CONNECTION_HEADERS_RECEIVED:
01802           EXTRA_CHECK (0);
01803           break;
01804         case MHD_CONNECTION_HEADERS_PROCESSED:
01805           break;
01806         case MHD_CONNECTION_CONTINUE_SENDING:
01807           ret = connection->send_cls (connection,
01808                                       &HTTP_100_CONTINUE
01809                                       [connection->continue_message_write_offset],
01810                                       strlen (HTTP_100_CONTINUE) -
01811                                       connection->continue_message_write_offset);
01812           if (ret < 0)
01813             {
01814               if (errno == EINTR)
01815                 break;
01816 #if HAVE_MESSAGES
01817               MHD_DLOG (connection->daemon,
01818                         "Failed to send data: %s\n", STRERROR (errno));
01819 #endif
01820               connection_close_error (connection);
01821               return MHD_NO;
01822             }
01823 #if DEBUG_SEND_DATA
01824           FPRINTF (stderr,
01825                    "Sent 100 continue response: `%.*s'\n",
01826                    ret,
01827                    &HTTP_100_CONTINUE
01828                    [connection->continue_message_write_offset]);
01829 #endif
01830           connection->continue_message_write_offset += ret;
01831           break;
01832         case MHD_CONNECTION_CONTINUE_SENT:
01833         case MHD_CONNECTION_BODY_RECEIVED:
01834         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
01835         case MHD_CONNECTION_FOOTERS_RECEIVED:
01836           EXTRA_CHECK (0);
01837           break;
01838         case MHD_CONNECTION_HEADERS_SENDING:
01839           do_write (connection);
01840           check_write_done (connection, MHD_CONNECTION_HEADERS_SENT);
01841           break;
01842         case MHD_CONNECTION_HEADERS_SENT:
01843           EXTRA_CHECK (0);
01844           break;
01845         case MHD_CONNECTION_NORMAL_BODY_READY:
01846           response = connection->response;
01847           if (response->crc != NULL)
01848             pthread_mutex_lock (&response->mutex);
01849           if (MHD_YES != try_ready_normal_body (connection))
01850             {
01851               if (response->crc != NULL)
01852                 pthread_mutex_unlock (&response->mutex);
01853               connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
01854               break;
01855             }
01856           ret = connection->send_cls (connection,
01857                                       &response->data
01858                                       [connection->response_write_position
01859                                        - response->data_start],
01860                                       response->data_size -
01861                                       (connection->response_write_position
01862                                        - response->data_start));
01863 #if DEBUG_SEND_DATA
01864           if (ret > 0)
01865             FPRINTF (stderr,
01866                      "Sent DATA response: `%.*s'\n",
01867                      ret,
01868                      &response->data[connection->response_write_position -
01869                                      response->data_start]);
01870 #endif
01871           if (response->crc != NULL)
01872             pthread_mutex_unlock (&response->mutex);
01873           if (ret < 0)
01874             {
01875               if (errno == EINTR)
01876                 return MHD_YES;
01877 #if HAVE_MESSAGES
01878               MHD_DLOG (connection->daemon,
01879                         "Failed to send data: %s\n", STRERROR (errno));
01880 #endif
01881               connection_close_error (connection);
01882               return MHD_NO;
01883             }
01884           connection->response_write_position += ret;
01885           if (connection->response_write_position ==
01886               connection->response->total_size)
01887             connection->state = MHD_CONNECTION_FOOTERS_SENT;    /* have no footers... */
01888           break;
01889         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
01890           EXTRA_CHECK (0);
01891           break;
01892         case MHD_CONNECTION_CHUNKED_BODY_READY:
01893           do_write (connection);
01894           check_write_done (connection,
01895                             (connection->response->total_size ==
01896                              connection->response_write_position) ?
01897                             MHD_CONNECTION_BODY_SENT :
01898                             MHD_CONNECTION_CHUNKED_BODY_UNREADY);
01899           break;
01900         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
01901         case MHD_CONNECTION_BODY_SENT:
01902           EXTRA_CHECK (0);
01903           break;
01904         case MHD_CONNECTION_FOOTERS_SENDING:
01905           do_write (connection);
01906           check_write_done (connection, MHD_CONNECTION_FOOTERS_SENT);
01907           break;
01908         case MHD_CONNECTION_FOOTERS_SENT:
01909           EXTRA_CHECK (0);
01910           break;
01911         case MHD_CONNECTION_CLOSED:
01912           if (connection->socket_fd != -1)
01913             connection_close_error (connection);
01914           return MHD_NO;
01915         case MHD_TLS_CONNECTION_INIT:
01916           EXTRA_CHECK (0);
01917           break;
01918         default:
01919           EXTRA_CHECK (0);
01920           connection_close_error (connection);
01921           return MHD_NO;
01922         }
01923       break;
01924     }
01925   return MHD_YES;
01926 }
01927 
01937 int
01938 MHD_connection_handle_idle (struct MHD_Connection *connection)
01939 {
01940   unsigned int timeout;
01941   const char *end;
01942   char *line;
01943 
01944   while (1)
01945     {
01946 #if DEBUG_STATES
01947       MHD_DLOG (connection->daemon, "%s: state: %s\n",
01948                 __FUNCTION__, MHD_state_to_string (connection->state));
01949 #endif
01950       switch (connection->state)
01951         {
01952         case MHD_CONNECTION_INIT:
01953           line = get_next_header_line (connection);
01954           if (line == NULL)
01955             {
01956               if (connection->state != MHD_CONNECTION_INIT)
01957                 continue;
01958               if (connection->read_closed)
01959                 {
01960                   connection->state = MHD_CONNECTION_CLOSED;
01961                   continue;
01962                 }
01963               break;
01964             }
01965           if (MHD_NO == parse_initial_message_line (connection, line))
01966             connection->state = MHD_CONNECTION_CLOSED;
01967           else
01968             connection->state = MHD_CONNECTION_URL_RECEIVED;
01969           continue;
01970         case MHD_CONNECTION_URL_RECEIVED:
01971           line = get_next_header_line (connection);
01972           if (line == NULL)
01973             {
01974               if (connection->state != MHD_CONNECTION_URL_RECEIVED)
01975                 continue;
01976               if (connection->read_closed)
01977                 {
01978                   connection->state = MHD_CONNECTION_CLOSED;
01979                   continue;
01980                 }
01981               break;
01982             }
01983           if (strlen (line) == 0)
01984             {
01985               connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
01986               continue;
01987             }
01988           if (MHD_NO == process_header_line (connection, line))
01989             {
01990               transmit_error_response (connection,
01991                                        MHD_HTTP_BAD_REQUEST,
01992                                        REQUEST_MALFORMED);
01993               break;
01994             }
01995           connection->state = MHD_CONNECTION_HEADER_PART_RECEIVED;
01996           continue;
01997         case MHD_CONNECTION_HEADER_PART_RECEIVED:
01998           line = get_next_header_line (connection);
01999           if (line == NULL)
02000             {
02001               if (connection->state != MHD_CONNECTION_HEADER_PART_RECEIVED)
02002                 continue;
02003               if (connection->read_closed)
02004                 {
02005                   connection->state = MHD_CONNECTION_CLOSED;
02006                   continue;
02007                 }
02008               break;
02009             }
02010           if (MHD_NO ==
02011               process_broken_line (connection, line, MHD_HEADER_KIND))
02012             continue;
02013           if (strlen (line) == 0)
02014             {
02015               connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
02016               continue;
02017             }
02018           continue;
02019         case MHD_CONNECTION_HEADERS_RECEIVED:
02020           parse_connection_headers (connection);
02021           if (connection->state == MHD_CONNECTION_CLOSED)
02022             continue;
02023           connection->state = MHD_CONNECTION_HEADERS_PROCESSED;
02024           continue;
02025         case MHD_CONNECTION_HEADERS_PROCESSED:
02026           call_connection_handler (connection); /* first call */
02027           if (connection->state == MHD_CONNECTION_CLOSED)
02028             continue;
02029           if (need_100_continue (connection))
02030             {
02031               connection->state = MHD_CONNECTION_CONTINUE_SENDING;
02032               break;
02033             }
02034           if (connection->response != NULL)
02035             {
02036               /* we refused (no upload allowed!) */
02037               connection->remaining_upload_size = 0;
02038               /* force close, in case client still tries to upload... */
02039               connection->read_closed = MHD_YES;
02040             }
02041           connection->state = (connection->remaining_upload_size == 0)
02042             ? MHD_CONNECTION_FOOTERS_RECEIVED : MHD_CONNECTION_CONTINUE_SENT;
02043           continue;
02044         case MHD_CONNECTION_CONTINUE_SENDING:
02045           if (connection->continue_message_write_offset ==
02046               strlen (HTTP_100_CONTINUE))
02047             {
02048               connection->state = MHD_CONNECTION_CONTINUE_SENT;
02049               continue;
02050             }
02051           break;
02052         case MHD_CONNECTION_CONTINUE_SENT:
02053           if (connection->read_buffer_offset != 0)
02054             {
02055               process_request_body (connection);     /* loop call */
02056               if (connection->state == MHD_CONNECTION_CLOSED)
02057                 continue;
02058             }
02059           if ((connection->remaining_upload_size == 0) ||
02060               ((connection->remaining_upload_size == MHD_SIZE_UNKNOWN) &&
02061                (connection->read_buffer_offset == 0) &&
02062                (MHD_YES == connection->read_closed)))
02063             {
02064               if ((MHD_YES == connection->have_chunked_upload) &&
02065                   (MHD_NO == connection->read_closed))
02066                 connection->state = MHD_CONNECTION_BODY_RECEIVED;
02067               else
02068                 connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02069               continue;
02070             }
02071           break;
02072         case MHD_CONNECTION_BODY_RECEIVED:
02073           line = get_next_header_line (connection);
02074           if (line == NULL)
02075             {
02076               if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
02077                 continue;
02078               if (connection->read_closed)
02079                 {
02080                   connection->state = MHD_CONNECTION_CLOSED;
02081                   continue;
02082                 }
02083               break;
02084             }
02085           if (strlen (line) == 0)
02086             {
02087               connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02088               continue;
02089             }
02090           if (MHD_NO == process_header_line (connection, line))
02091             {
02092               transmit_error_response (connection,
02093                                        MHD_HTTP_BAD_REQUEST,
02094                                        REQUEST_MALFORMED);
02095               break;
02096             }
02097           connection->state = MHD_CONNECTION_FOOTER_PART_RECEIVED;
02098           continue;
02099         case MHD_CONNECTION_FOOTER_PART_RECEIVED:
02100           line = get_next_header_line (connection);
02101           if (line == NULL)
02102             {
02103               if (connection->state != MHD_CONNECTION_FOOTER_PART_RECEIVED)
02104                 continue;
02105               if (connection->read_closed)
02106                 {
02107                   connection->state = MHD_CONNECTION_CLOSED;
02108                   continue;
02109                 }
02110               break;
02111             }
02112           if (MHD_NO ==
02113               process_broken_line (connection, line, MHD_FOOTER_KIND))
02114             continue;
02115           if (strlen (line) == 0)
02116             {
02117               connection->state = MHD_CONNECTION_FOOTERS_RECEIVED;
02118               continue;
02119             }
02120           continue;
02121         case MHD_CONNECTION_FOOTERS_RECEIVED:
02122           call_connection_handler (connection); /* "final" call */
02123           if (connection->state == MHD_CONNECTION_CLOSED)
02124             continue;
02125           if (connection->response == NULL)
02126             break;              /* try again next time */
02127           if (MHD_NO == build_header_response (connection))
02128             {
02129               /* oops - close! */
02130 #if HAVE_MESSAGES
02131               MHD_DLOG (connection->daemon,
02132                         "Closing connection (failed to create response header)\n");
02133 #endif
02134               connection->state = MHD_CONNECTION_CLOSED;
02135               continue;
02136             }
02137           connection->state = MHD_CONNECTION_HEADERS_SENDING;
02138 
02139 #if HAVE_DECL_TCP_CORK
02140           /* starting header send, set TCP cork */
02141           {
02142             const int val = 1;
02143             setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02144                         sizeof (val));
02145           }
02146 #endif
02147           break;
02148         case MHD_CONNECTION_HEADERS_SENDING:
02149           /* no default action */
02150           break;
02151         case MHD_CONNECTION_HEADERS_SENT:
02152           if (connection->have_chunked_upload)
02153             connection->state = MHD_CONNECTION_CHUNKED_BODY_UNREADY;
02154           else
02155             connection->state = MHD_CONNECTION_NORMAL_BODY_UNREADY;
02156           continue;
02157         case MHD_CONNECTION_NORMAL_BODY_READY:
02158           /* nothing to do here */
02159           break;
02160         case MHD_CONNECTION_NORMAL_BODY_UNREADY:
02161           if (connection->response->crc != NULL)
02162             pthread_mutex_lock (&connection->response->mutex);
02163           if (MHD_YES == try_ready_normal_body (connection))
02164             {
02165               if (connection->response->crc != NULL)
02166                 pthread_mutex_unlock (&connection->response->mutex);
02167               connection->state = MHD_CONNECTION_NORMAL_BODY_READY;
02168               break;
02169             }
02170           if (connection->response->crc != NULL)
02171             pthread_mutex_unlock (&connection->response->mutex);
02172           /* not ready, no socket action */
02173           break;
02174         case MHD_CONNECTION_CHUNKED_BODY_READY:
02175           /* nothing to do here */
02176           break;
02177         case MHD_CONNECTION_CHUNKED_BODY_UNREADY:
02178           if (connection->response->crc != NULL)
02179             pthread_mutex_lock (&connection->response->mutex);
02180           if (MHD_YES == try_ready_chunked_body (connection))
02181             {
02182               if (connection->response->crc != NULL)
02183                 pthread_mutex_unlock (&connection->response->mutex);
02184               connection->state = MHD_CONNECTION_CHUNKED_BODY_READY;
02185               continue;
02186             }
02187           if (connection->response->crc != NULL)
02188             pthread_mutex_unlock (&connection->response->mutex);
02189           break;
02190         case MHD_CONNECTION_BODY_SENT:
02191           build_header_response (connection);
02192           if (connection->write_buffer_send_offset ==
02193               connection->write_buffer_append_offset)
02194             connection->state = MHD_CONNECTION_FOOTERS_SENT;
02195           else
02196             connection->state = MHD_CONNECTION_FOOTERS_SENDING;
02197           continue;
02198         case MHD_CONNECTION_FOOTERS_SENDING:
02199           /* no default action */
02200           break;
02201         case MHD_CONNECTION_FOOTERS_SENT:
02202 #if HAVE_DECL_TCP_CORK
02203           /* done sending, uncork */
02204           {
02205             const int val = 0;
02206             setsockopt (connection->socket_fd, IPPROTO_TCP, TCP_CORK, &val,
02207                         sizeof (val));
02208           }
02209 #endif
02210           MHD_destroy_response (connection->response);
02211           connection->response = NULL;
02212           if (connection->daemon->notify_completed != NULL)
02213             connection->daemon->notify_completed (connection->daemon->
02214                                                   notify_completed_cls,
02215                                                   connection,
02216                                                   &connection->client_context,
02217                                                   MHD_REQUEST_TERMINATED_COMPLETED_OK);     
02218           connection->client_aware = MHD_NO;
02219           end =
02220             MHD_lookup_connection_value (connection, MHD_HEADER_KIND,
02221                                          MHD_HTTP_HEADER_CONNECTION);
02222           connection->client_context = NULL;
02223           connection->continue_message_write_offset = 0;
02224           connection->responseCode = 0;
02225           connection->headers_received = NULL;
02226           connection->response_write_position = 0;
02227           connection->have_chunked_upload = MHD_NO;
02228           connection->method = NULL;
02229           connection->url = NULL;
02230           connection->write_buffer = NULL;
02231           connection->write_buffer_size = 0;
02232           connection->write_buffer_send_offset = 0;
02233           connection->write_buffer_append_offset = 0;
02234           if ((end != NULL) && (0 == strcasecmp (end, "close")))
02235             {
02236               connection->read_closed = MHD_YES;
02237               connection->read_buffer_offset = 0;
02238             }
02239           if (((MHD_YES == connection->read_closed) &&
02240                (0 == connection->read_buffer_offset)) ||
02241               (connection->version == NULL) ||
02242               (0 != strcasecmp (MHD_HTTP_VERSION_1_1, connection->version)))
02243             {
02244               /* http 1.0, version-less requests cannot be pipelined */
02245               connection->state = MHD_CONNECTION_CLOSED;
02246               MHD_pool_destroy (connection->pool);
02247               connection->pool = NULL;
02248               connection->read_buffer = NULL;
02249               connection->read_buffer_size = 0;
02250               connection->read_buffer_offset = 0;
02251             }
02252           else
02253             {
02254               connection->version = NULL;
02255               connection->state = MHD_CONNECTION_INIT;
02256               connection->read_buffer
02257                 = MHD_pool_reset (connection->pool,
02258                                   connection->read_buffer,
02259                                   connection->read_buffer_size);
02260             }
02261           continue;
02262         case MHD_CONNECTION_CLOSED:
02263           if (connection->socket_fd != -1)
02264             connection_close_error (connection);
02265           break;
02266         default:
02267           EXTRA_CHECK (0);
02268           break;
02269         }
02270       break;
02271     }
02272   timeout = connection->daemon->connection_timeout;
02273   if ((connection->socket_fd != -1) &&
02274       (timeout != 0) &&
02275       (timeout < (time (NULL) - connection->last_activity)) )
02276     {
02277       MHD_connection_close (connection, MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
02278       return MHD_NO;
02279     }
02280   return MHD_YES;
02281 }
02282 
02283 
02284 void
02285 MHD_set_http_callbacks_ (struct MHD_Connection *connection)
02286 {
02287   connection->read_handler = &MHD_connection_handle_read;
02288   connection->write_handler = &MHD_connection_handle_write;
02289   connection->idle_handler = &MHD_connection_handle_idle;
02290 }
02291 
02292 
02302 const union MHD_ConnectionInfo *
02303 MHD_get_connection_info (struct MHD_Connection *connection,
02304                          enum MHD_ConnectionInfoType infoType, ...)
02305 {
02306   switch (infoType)
02307     {
02308 #if HTTPS_SUPPORT
02309     case MHD_CONNECTION_INFO_CIPHER_ALGO:
02310       if (connection->tls_session == NULL)
02311         return NULL;
02312       connection->cipher = gnutls_cipher_get (connection->tls_session);
02313       return (const union MHD_ConnectionInfo *) &connection->cipher;
02314     case MHD_CONNECTION_INFO_PROTOCOL:
02315       if (connection->tls_session == NULL)
02316         return NULL;
02317       connection->protocol = gnutls_protocol_get_version (connection->tls_session);
02318       return (const union MHD_ConnectionInfo *) &connection->protocol;
02319     case MHD_CONNECTION_INFO_GNUTLS_SESSION:
02320       if (connection->tls_session == NULL)
02321         return NULL;
02322       return (const union MHD_ConnectionInfo *) &connection->tls_session;
02323 #endif
02324     case MHD_CONNECTION_INFO_CLIENT_ADDRESS:
02325       return (const union MHD_ConnectionInfo *) &connection->addr;
02326     default:
02327       return NULL;
02328     };
02329 }
02330 
02331 
02332 /* end of connection.c */