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

Generated on 16 Nov 2010 for GNU libmicrohttpd by  doxygen 1.6.1