gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r5425 - in libmicrohttpd: . src/daemon


From: gnunet
Subject: [GNUnet-SVN] r5425 - in libmicrohttpd: . src/daemon
Date: Wed, 8 Aug 2007 14:03:13 -0600 (MDT)

Author: grothoff
Date: 2007-08-08 14:03:11 -0600 (Wed, 08 Aug 2007)
New Revision: 5425

Added:
   libmicrohttpd/src/daemon/daemontest_long_header.c
Modified:
   libmicrohttpd/README
   libmicrohttpd/src/daemon/Makefile.am
   libmicrohttpd/src/daemon/connection.c
Log:
handling of long headers (#1222)

Modified: libmicrohttpd/README
===================================================================
--- libmicrohttpd/README        2007-08-08 08:55:18 UTC (rev 5424)
+++ libmicrohttpd/README        2007-08-08 20:03:11 UTC (rev 5425)
@@ -14,9 +14,7 @@
 For http/1.1-compliance:
 ========================
 connection.c:
-- send proper error code back if headers are too long
-  (currently, we just close the connection) (#1222, ARCH, TEST)
-- support chunked requests from clients (#1260, TEST, TEST)
+- support chunked requests from clients (#1260, ARCH, TEST)
 - send proper error code back if client forgot the "Host" header (#1264, TRIV)
 - automatically add MHD_HTTP_HEADER_DATE if client "forgot" to add one (#1261, 
TRIV)
 - automatically drop body from responses to "HEAD" requests (#1262, TRIV)

Modified: libmicrohttpd/src/daemon/Makefile.am
===================================================================
--- libmicrohttpd/src/daemon/Makefile.am        2007-08-08 08:55:18 UTC (rev 
5424)
+++ libmicrohttpd/src/daemon/Makefile.am        2007-08-08 20:03:11 UTC (rev 
5425)
@@ -35,7 +35,8 @@
   daemontest_put \
   daemontest_get11 \
   daemontest_post11 \
-  daemontest_put11
+  daemontest_put11 \
+  daemontest_long_header
 
 TESTS = $(check_PROGRAMS)
 
@@ -74,11 +75,16 @@
   $(top_builddir)/src/daemon/libmicrohttpd.la \
   @LIBCURL@ 
 
-
 daemontest_put11_SOURCES = \
   daemontest_put.c
 daemontest_put11_LDADD = \
   $(top_builddir)/src/daemon/libmicrohttpd.la \
   @LIBCURL@ 
 
+daemontest_long_header_SOURCES = \
+  daemontest_long_header.c
+daemontest_long_header_LDADD = \
+  $(top_builddir)/src/daemon/libmicrohttpd.la \
+  @LIBCURL@ 
+
 endif
\ No newline at end of file

Modified: libmicrohttpd/src/daemon/connection.c
===================================================================
--- libmicrohttpd/src/daemon/connection.c       2007-08-08 08:55:18 UTC (rev 
5424)
+++ libmicrohttpd/src/daemon/connection.c       2007-08-08 20:03:11 UTC (rev 
5425)
@@ -41,6 +41,12 @@
 #define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"
 
 /**
+ * Response used when the request (http header) is too big to
+ * be processed.
+ */
+#define REQUEST_TOO_BIG ""
+
+/**
  * Get all of the headers from the request.
  *
  * @param iterator callback to call on each header;
@@ -146,16 +152,14 @@
   fd = connection->socket_fd;
   if (fd == -1)
     return MHD_YES;
-  if ( (connection->read_close == 0) &&
+  if ( (connection->read_close == MHD_NO) &&
        ( (connection->headersReceived == 0) ||
         (connection->readLoc < connection->read_buffer_size) ) ) {  
     FD_SET(fd, read_fd_set);
     if (fd > *max_fd) 
       *max_fd = fd;
   } else {
-
-
-    if ( (connection->read_close == 0) &&
+    if ( (connection->read_close == MHD_NO) &&
         ( (connection->headersReceived == 1) &&
           (connection->post_processed == MHD_NO) &&
           (connection->readLoc == connection->read_buffer_size) ) ) {
@@ -188,17 +192,32 @@
 
 /**
  * We ran out of memory processing the
- * header.  Handle it properly.
+ * header.  Handle it properly by stopping to read data
+ * and sending a HTTP 413 or HTTP 414 response.
+ * 
+ * @param status_code the response code to send (413 or 414)
  */
 static void
-MHD_excessive_header_handler(struct MHD_Connection * connection) {
+MHD_excessive_data_handler(struct MHD_Connection * connection,
+                          unsigned int status_code) {
+  struct MHD_Response * response;
+
   /* die, header far too long to be reasonable;
      FIXME: send proper response to client
      (stop reading, queue proper response) */
+  connection->read_close = MHD_YES;
+  connection->headersReceived = MHD_YES;
+  connection->bodyReceived = MHD_YES;
   MHD_DLOG(connection->daemon,
-          "Received excessively long header line, closing connection.\n");
-  CLOSE(connection->socket_fd);
-  connection->socket_fd = -1;
+          "Received excessively long header, closing connection.\n");
+  response = MHD_create_response_from_data(strlen(REQUEST_TOO_BIG),
+                                          REQUEST_TOO_BIG,
+                                          MHD_NO,
+                                          MHD_NO);
+  MHD_queue_response(connection,
+                    status_code,
+                    response);
+  MHD_destroy_response(response);
 }
 
 /**
@@ -230,7 +249,10 @@
                                 connection->read_buffer_size,
                                 connection->read_buffer_size * 2 + 
MHD_BUF_INC_SIZE);
       if (rbuf == NULL) {
-       MHD_excessive_header_handler(connection);
+       MHD_excessive_data_handler(connection,
+                                  (connection->url != NULL) 
+                                  ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
+                                  : MHD_HTTP_REQUEST_URI_TOO_LONG);
       } else {
        connection->read_buffer_size = connection->read_buffer_size * 2 + 
MHD_BUF_INC_SIZE;
        connection->read_buffer = rbuf;
@@ -265,7 +287,8 @@
   if (hdr == NULL) {
     MHD_DLOG(connection->daemon,
             "Not enough memory to allocate header record!\n");
-    MHD_excessive_header_handler(connection);
+    MHD_excessive_data_handler(connection,
+                              MHD_HTTP_REQUEST_ENTITY_TOO_LARGE);
     return MHD_NO;
   }
   hdr->next = connection->headers_received;
@@ -360,7 +383,8 @@
   if (cpy == NULL) {
     MHD_DLOG(connection->daemon,
             "Not enough memory to parse cookies!\n");
-    MHD_excessive_header_handler(connection);
+    MHD_excessive_data_handler(connection,
+                              MHD_HTTP_REQUEST_ENTITY_TOO_LARGE);
     return MHD_NO;
   }
   memcpy(cpy,
@@ -483,7 +507,8 @@
                                   strlen(last)+1,
                                   strlen(line) + strlen(last) + 1);
        if (last == NULL) {
-         MHD_excessive_header_handler(connection);
+         MHD_excessive_data_handler(connection,
+                                    MHD_HTTP_REQUEST_ENTITY_TOO_LARGE);
          break;
        }
        tmp = line;
@@ -620,8 +645,10 @@
   const char * encoding;
   void * buf;
 
-  if (0 != strcasecmp(connection->method,
-                     MHD_HTTP_METHOD_POST))
+  if ( (connection->method == NULL) ||
+       (connection->response != NULL) ||
+       (0 != strcasecmp(connection->method,
+                       MHD_HTTP_METHOD_POST)) )
     return MHD_NO;
   encoding = MHD_lookup_connection_value(connection,
                                         MHD_HEADER_KIND,
@@ -711,6 +738,8 @@
   struct MHD_Access_Handler * ah;
   unsigned int processed;
 
+  if (connection->response != NULL)
+    return; /* already queued a response */
   if (connection->headersReceived == 0)
     abort(); /* bad timing... */
   ah = MHD_find_access_handler(connection);
@@ -778,7 +807,8 @@
     if (tmp == NULL) {
       MHD_DLOG(connection->daemon,
               "Not enough memory for reading headers!\n");
-      MHD_excessive_header_handler(connection);
+      MHD_excessive_data_handler(connection,
+                                MHD_HTTP_REQUEST_ENTITY_TOO_LARGE);
       return MHD_NO;
     }
     connection->read_buffer = tmp;
@@ -824,8 +854,9 @@
         (connection->uploadSize == connection->readLoc) )
       if (MHD_NO == MHD_parse_post_data(connection)) 
        connection->post_processed = MHD_NO;      
-    if ( (connection->post_processed == MHD_NO) ||
-        (connection->read_buffer_size == connection->readLoc) )
+    if ( ( (connection->post_processed == MHD_NO) ||
+          (connection->read_buffer_size == connection->readLoc) ) &&
+        (connection->method != NULL) )
       MHD_call_connection_handler(connection);
   }
   return MHD_YES;
@@ -1065,7 +1096,7 @@
     connection->messagePos = 0;
     connection->method = NULL;
     connection->url = NULL;
-    if ( (connection->read_close != 0) ||
+    if ( (connection->read_close == MHD_YES) ||
         (0 != strcasecmp(MHD_HTTP_VERSION_1_1,
                          connection->version)) ) {
       /* closed for reading => close for good! */

Added: libmicrohttpd/src/daemon/daemontest_long_header.c
===================================================================
--- libmicrohttpd/src/daemon/daemontest_long_header.c                           
(rev 0)
+++ libmicrohttpd/src/daemon/daemontest_long_header.c   2007-08-08 20:03:11 UTC 
(rev 5425)
@@ -0,0 +1,287 @@
+/*
+     This file is part of libmicrohttpd
+     (C) 2007 Christian Grothoff
+
+     libmicrohttpd is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     libmicrohttpd is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with libmicrohttpd; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file daemontest_long_header.c
+ * @brief  Testcase for libmicrohttpd handling of very long headers
+ * @author Christian Grothoff
+ */
+
+#include "config.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+
+/**
+ * We will set the memory available per connection to
+ * half of this value, so the actual value does not have
+ * to be big at all...
+ */
+#define VERY_LONG (1024*10)
+
+static int oneone;
+
+static int apc_all(void * cls,
+                  const struct sockaddr * addr,
+                  socklen_t addrlen) {
+  return MHD_YES;
+}
+
+struct CBC {
+  char * buf;
+  size_t pos;
+  size_t size;
+};
+
+static size_t copyBuffer(void * ptr,
+                        size_t size,
+                        size_t nmemb,
+                        void * ctx) {
+  return size * nmemb;
+}
+
+static int ahc_echo(void * cls,
+                   struct MHD_Connection * connection,
+                   const char * url,
+                   const char * method,
+                   const char * version,
+                   const char * upload_data,
+                   unsigned int * upload_data_size) {
+  const char * me = cls;
+  struct MHD_Response * response;
+  int ret;
+
+  if (0 != strcmp(me, method))
+    return MHD_NO; /* unexpected method */
+  response = MHD_create_response_from_data(strlen(url),
+                                          (void*) url,
+                                          MHD_NO,
+                                          MHD_YES);
+  ret = MHD_queue_response(connection,
+                          MHD_HTTP_OK,
+                          response);
+  MHD_destroy_response(response);
+  return ret;
+}
+
+
+static int testLongUrlGet() {
+  struct MHD_Daemon * d;
+  CURL * c;
+  char buf[2048];
+  struct CBC cbc;
+  char * url;
+  long code;
+
+  cbc.buf = buf;
+  cbc.size = 2048;
+  cbc.pos = 0;
+  d = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */, 
+                      1080,
+                      &apc_all,
+                      NULL,
+                      &ahc_echo,
+                      "GET",
+                      MHD_OPTION_CONNECTION_MEMORY_LIMIT,
+                      VERY_LONG / 2,
+                      MHD_OPTION_END);
+  if (d == NULL)
+    return 1;
+  c = curl_easy_init();
+  url = malloc(VERY_LONG);
+  memset(url,
+        'a',
+        VERY_LONG);
+  url[VERY_LONG-1] = '\0';
+  memcpy(url,
+        "http://localhost:1080/";,
+        strlen("http://localhost:1080/";));
+  curl_easy_setopt(c,
+                  CURLOPT_URL,
+                  url);
+  curl_easy_setopt(c,
+                  CURLOPT_WRITEFUNCTION,
+                  &copyBuffer);
+  curl_easy_setopt(c,
+                  CURLOPT_WRITEDATA,
+                  &cbc);
+  curl_easy_setopt(c,
+                  CURLOPT_FAILONERROR,
+                  1);
+  curl_easy_setopt(c,
+                  CURLOPT_TIMEOUT,
+                  2L);
+  curl_easy_setopt(c,
+                  CURLOPT_CONNECTTIMEOUT,
+                  2L);
+  if (oneone)
+    curl_easy_setopt(c,
+                    CURLOPT_HTTP_VERSION,
+                    CURL_HTTP_VERSION_1_1);
+  else
+    curl_easy_setopt(c,
+                    CURLOPT_HTTP_VERSION,
+                    CURL_HTTP_VERSION_1_0);
+   // NOTE: use of CONNECTTIMEOUT without also
+  //   setting NOSIGNAL results in really weird
+  //   crashes on my system!
+  curl_easy_setopt(c,
+                  CURLOPT_NOSIGNAL,
+                  1);
+  if (CURLE_OK == curl_easy_perform(c)) {
+    curl_easy_cleanup(c);
+    MHD_stop_daemon(d);
+    free(url);
+    return 2;
+  }
+  if (CURLE_OK != curl_easy_getinfo(c,
+                                   CURLINFO_RESPONSE_CODE,
+                                   &code)) {
+    curl_easy_cleanup(c);
+    MHD_stop_daemon(d);
+    free(url);
+    return 4;
+  }
+  curl_easy_cleanup(c);
+  MHD_stop_daemon(d);
+  free(url);
+  if (code != MHD_HTTP_REQUEST_URI_TOO_LONG)
+    return 8;
+  return 0;
+}
+
+
+static int testLongHeaderGet() {
+  struct MHD_Daemon * d;
+  CURL * c;
+  char buf[2048];
+  struct CBC cbc;
+  char * url;
+  long code;
+  struct curl_slist * header = NULL;
+
+  cbc.buf = buf;
+  cbc.size = 2048;
+  cbc.pos = 0;
+  d = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */, 
+                      1080,
+                      &apc_all,
+                      NULL,
+                      &ahc_echo,
+                      "GET",
+                      MHD_OPTION_CONNECTION_MEMORY_LIMIT,
+                      VERY_LONG / 2,
+                      MHD_OPTION_END);
+  if (d == NULL)
+    return 16;
+  c = curl_easy_init();
+  url = malloc(VERY_LONG);
+  memset(url,
+        'a',
+        VERY_LONG);
+  url[VERY_LONG-1] = '\0';
+  url[VERY_LONG/2] = ':';
+  url[VERY_LONG/2+1] = ':';
+  header = curl_slist_append(header,
+                            url);
+  
+  curl_easy_setopt(c,
+                  CURLOPT_HTTPHEADER,
+                  header);
+  curl_easy_setopt(c,
+                  CURLOPT_URL,
+                  "http://localhost:1080/hello_world";);
+  curl_easy_setopt(c,
+                  CURLOPT_WRITEFUNCTION,
+                  &copyBuffer);
+  curl_easy_setopt(c,
+                  CURLOPT_WRITEDATA,
+                  &cbc);
+  curl_easy_setopt(c,
+                  CURLOPT_FAILONERROR,
+                  1);
+  curl_easy_setopt(c,
+                  CURLOPT_TIMEOUT,
+                  2L);
+  curl_easy_setopt(c,
+                  CURLOPT_CONNECTTIMEOUT,
+                  2L);
+  if (oneone)
+    curl_easy_setopt(c,
+                    CURLOPT_HTTP_VERSION,
+                    CURL_HTTP_VERSION_1_1);
+  else
+    curl_easy_setopt(c,
+                    CURLOPT_HTTP_VERSION,
+                    CURL_HTTP_VERSION_1_0);
+   // NOTE: use of CONNECTTIMEOUT without also
+  //   setting NOSIGNAL results in really weird
+  //   crashes on my system!
+  curl_easy_setopt(c,
+                  CURLOPT_NOSIGNAL,
+                  1);
+  if (CURLE_OK == curl_easy_perform(c)) {
+    curl_easy_cleanup(c);
+    MHD_stop_daemon(d);
+    curl_slist_free_all(header);
+    free(url);
+    return 32;
+  }
+  if (CURLE_OK != curl_easy_getinfo(c,
+                                   CURLINFO_RESPONSE_CODE,
+                                   &code)) {
+    curl_slist_free_all(header);
+    curl_easy_cleanup(c);
+    MHD_stop_daemon(d);
+    free(url);
+    return 64;
+  }
+  curl_slist_free_all(header);
+  curl_easy_cleanup(c);
+  MHD_stop_daemon(d);
+  free(url);
+  if (code != MHD_HTTP_REQUEST_ENTITY_TOO_LARGE)
+    return 128;
+  return 0;
+}
+
+
+
+
+
+int main(int argc,
+        char * const * argv) {
+  unsigned int errorCount = 0;
+
+  oneone = NULL != strstr(argv[0], "11");
+  if (0 != curl_global_init(CURL_GLOBAL_WIN32))
+    return 2;
+  errorCount += testLongUrlGet();
+  errorCount += testLongHeaderGet();
+  if (errorCount != 0)
+    fprintf(stderr,
+           "Error (code: %u)\n",
+           errorCount);
+  curl_global_cleanup();
+  return errorCount != 0; /* 0 == pass */
+}


Property changes on: libmicrohttpd/src/daemon/daemontest_long_header.c
___________________________________________________________________
Name: svn:eol-style
   + native





reply via email to

[Prev in Thread] Current Thread [Next in Thread]