gnunet-svn
[Top][All Lists]
Advanced

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

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


From: gnunet
Subject: [GNUnet-SVN] r5926 - in libmicrohttpd: . src/daemon
Date: Sun, 16 Dec 2007 03:27:30 -0700 (MST)

Author: grothoff
Date: 2007-12-16 03:27:29 -0700 (Sun, 16 Dec 2007)
New Revision: 5926

Added:
   libmicrohttpd/src/daemon/daemontest_put_chunked.c
Modified:
   libmicrohttpd/ChangeLog
   libmicrohttpd/README
   libmicrohttpd/src/daemon/Makefile.am
   libmicrohttpd/src/daemon/connection.c
   libmicrohttpd/src/daemon/daemon.c
   libmicrohttpd/src/daemon/internal.h
Log:
fixing Mantis 1260

Modified: libmicrohttpd/ChangeLog
===================================================================
--- libmicrohttpd/ChangeLog     2007-12-16 05:47:40 UTC (rev 5925)
+++ libmicrohttpd/ChangeLog     2007-12-16 10:27:29 UTC (rev 5926)
@@ -1,3 +1,11 @@
+Sun Dec 16 03:24:13 MST 2007
+        Implemented handling of chunked (HTTP 1.1) uploads.
+        Note that the upload callback must be able to 
+        process chunks in the size uploaded by the client,
+        MHD will not "join" small chunks into a big 
+        contiguous block of memory (even if buffer space
+        would be available).  - CG
+
 Wed Dec  5 21:39:35 MST 2007
         Fixed race in multi-threaded server mode.
         Fixed handling of POST data when receiving a

Modified: libmicrohttpd/README
===================================================================
--- libmicrohttpd/README        2007-12-16 05:47:40 UTC (rev 5925)
+++ libmicrohttpd/README        2007-12-16 10:27:29 UTC (rev 5926)
@@ -53,7 +53,7 @@
 For http/1.1-compliance:
 ========================
 connection.c:
-- support chunked requests from clients (#1260, ARCH, TEST)
+- support sending of chunked responses (#1260, TEST)
 
 For POST:
 =========

Modified: libmicrohttpd/src/daemon/Makefile.am
===================================================================
--- libmicrohttpd/src/daemon/Makefile.am        2007-12-16 05:47:40 UTC (rev 
5925)
+++ libmicrohttpd/src/daemon/Makefile.am        2007-12-16 10:27:29 UTC (rev 
5926)
@@ -48,6 +48,7 @@
   daemontest_postform \
   daemontest_post_loop \
   daemontest_put \
+  daemontest_put_chunked \
   daemontest_large_put \
   daemontest_get11 \
   daemontest_post11 \
@@ -94,6 +95,12 @@
   $(top_builddir)/src/daemon/libmicrohttpd.la \
   @LIBCURL@ 
 
+daemontest_put_chunked_SOURCES = \
+  daemontest_put_chunked.c
+daemontest_put_chunked_LDADD = \
+  $(top_builddir)/src/daemon/libmicrohttpd.la \
+  @LIBCURL@ 
+
 daemontest_get11_SOURCES = \
   daemontest_get.c
 daemontest_get11_LDADD = \

Modified: libmicrohttpd/src/daemon/connection.c
===================================================================
--- libmicrohttpd/src/daemon/connection.c       2007-12-16 05:47:40 UTC (rev 
5925)
+++ libmicrohttpd/src/daemon/connection.c       2007-12-16 10:27:29 UTC (rev 
5926)
@@ -152,7 +152,7 @@
   if ((connection == NULL) ||
       (response == NULL) ||
       (connection->response != NULL) ||
-      (connection->bodyReceived == MHD_NO) || (connection->headersReceived == 
MHD_NO))
+      (connection->have_received_body == MHD_NO) || 
(connection->have_received_headers == MHD_NO))
     return MHD_NO;
   MHD_increment_response_rc (response);
   connection->response = response;
@@ -162,7 +162,7 @@
     {
       /* if this is a "HEAD" request, pretend that we
          have already sent the full message body */
-      connection->messagePos = response->total_size;
+      connection->response_write_position = response->total_size;
     }
   return MHD_YES;
 }
@@ -179,12 +179,12 @@
   return ((connection->version != NULL) &&
           (0 == strcasecmp (connection->version,
                             MHD_HTTP_VERSION_1_1)) &&
-          (connection->headersReceived == MHD_YES) &&
+          (connection->have_received_headers == MHD_YES) &&
           (NULL != (expect = MHD_lookup_connection_value (connection,
                                                           MHD_HEADER_KIND,
                                                           
MHD_HTTP_HEADER_EXPECT)))
           && (0 == strcasecmp (expect, "100-continue"))
-          && (connection->continuePos < strlen (HTTP_100_CONTINUE)));
+          && (connection->continue_message_write_offset < strlen 
(HTTP_100_CONTINUE)));
 }
 
 /**
@@ -221,10 +221,10 @@
 
   response = connection->response;
   ret = response->crc (response->crc_cls,
-                       connection->messagePos,
+                       connection->response_write_position,
                        response->data,
                        MIN (response->data_buffer_size,
-                            response->total_size - connection->messagePos));
+                            response->total_size - 
connection->response_write_position));
   if (ret == -1)
     {
       /* end of message, signal other side by closing! */
@@ -233,11 +233,11 @@
       MHD_DLOG (connection->daemon, "Closing connection (end of response)\n");
 #endif
 #endif
-      response->total_size = connection->messagePos;
+      response->total_size = connection->response_write_position;
       connection_close_error (connection);
       return MHD_NO;
     }
-  response->data_start = connection->messagePos;
+  response->data_start = connection->response_write_position;
   response->data_size = ret;
   if (ret == 0)
     {
@@ -278,8 +278,8 @@
   if (fd == -1)
     return MHD_YES;
   if ((connection->read_close == MHD_NO) &&
-      ((connection->headersReceived == MHD_NO) ||
-       (connection->readLoc < connection->read_buffer_size)))
+      ((connection->have_received_headers == MHD_NO) ||
+       (connection->read_buffer_offset < connection->read_buffer_size)))
     {
       FD_SET (fd, read_fd_set);
       if (fd > *max_fd)
@@ -288,8 +288,8 @@
   else
     {
       if ((connection->read_close == MHD_NO) &&
-          ((connection->headersReceived == MHD_YES) &&
-           (connection->readLoc == connection->read_buffer_size)))
+          ((connection->have_received_headers == MHD_YES) &&
+           (connection->read_buffer_offset == connection->read_buffer_size)))
         {
           /* try growing the read buffer, just in case */
           buf = MHD_pool_reallocate (connection->pool,
@@ -342,8 +342,8 @@
 
   /* die, header far too long to be reasonable */
   connection->read_close = MHD_YES;
-  connection->headersReceived = MHD_YES;
-  connection->bodyReceived = MHD_YES;
+  connection->have_received_headers = MHD_YES;
+  connection->have_received_body = MHD_YES;
 #if HAVE_MESSAGES
   MHD_DLOG (connection->daemon,
             "Received excessively long header, closing connection.\n");
@@ -368,17 +368,17 @@
   char *rbuf;
   size_t pos;
 
-  if (connection->readLoc == 0)
+  if (connection->read_buffer_offset == 0)
     return NULL;
   pos = 0;
   rbuf = connection->read_buffer;
-  while ((pos < connection->readLoc - 1) &&
+  while ((pos < connection->read_buffer_offset - 1) &&
          (rbuf[pos] != '\r') && (rbuf[pos] != '\n'))
     pos++;
-  if (pos == connection->readLoc - 1)
+  if (pos == connection->read_buffer_offset - 1)
     {
       /* not found, consider growing... */
-      if (connection->readLoc == connection->read_buffer_size)
+      if (connection->read_buffer_offset == connection->read_buffer_size)
         {
           rbuf = MHD_pool_reallocate (connection->pool,
                                       connection->read_buffer,
@@ -407,7 +407,7 @@
   rbuf[pos++] = '\0';
   connection->read_buffer += pos;
   connection->read_buffer_size -= pos;
-  connection->readLoc -= pos;
+  connection->read_buffer_offset -= pos;
   return rbuf;
 }
 
@@ -586,14 +586,16 @@
 
 
 /**
- * This function is designed to parse the input buffer of a given connection.
+ * This function is designed to parse the input buffer of a given
+ * connection for HTTP headers -- and in the case of chunked encoding,
+ * also for HTTP "footers".
  *
  * Once the header is complete, it should have set the
  * headers_received, url and method values and set
- * headersReceived to MHD_YES.  If no body is expected, it should
- * also set "bodyReceived" to MHD_YES.  Otherwise, it should
- * set "uploadSize" to the expected size of the body.  If the
- * size of the body is unknown, it should be set to -1.
+ * have_received_headers to MHD_YES.  If no body is expected, it
+ * should also set "have_received_body" to MHD_YES.  Otherwise, it
+ * should set "remaining_upload_size" to the expected size of the
+ * body.  If the size of the body is unknown, it should be set to -1.
  */
 static void
 MHD_parse_connection_headers (struct MHD_Connection *connection)
@@ -606,8 +608,9 @@
   unsigned long long cval;
   struct MHD_Response *response;
 
-  if ( (connection->bodyReceived == MHD_YES) ||
-       (connection->headersReceived == MHD_YES) )
+  if ( ( (connection->have_received_body == MHD_YES) &&
+        (connection->have_chunked_upload == MHD_NO) ) ||
+       (connection->have_received_headers == MHD_YES) )
     abort ();
   colon = NULL;                 /* make gcc happy */
   last = NULL;
@@ -656,7 +659,7 @@
       if (strlen (line) == 0)
         {
           /* end of header */
-          connection->headersReceived = MHD_YES;
+          connection->have_received_headers = MHD_YES;
           clen = MHD_lookup_connection_value (connection,
                                               MHD_HEADER_KIND,
                                               MHD_HTTP_HEADER_CONTENT_LENGTH);
@@ -671,8 +674,8 @@
 #endif
                   goto DIE;
                 }
-              connection->uploadSize = cval;
-              connection->bodyReceived = cval == 0 ? MHD_YES : MHD_NO;
+              connection->remaining_upload_size = cval;
+              connection->have_received_body = cval == 0 ? MHD_YES : MHD_NO;
             }
           else
             {
@@ -681,14 +684,29 @@
                                                        
MHD_HTTP_HEADER_TRANSFER_ENCODING))
                 {
                   /* this request does not have a body */
-                  connection->uploadSize = 0;
-                  connection->bodyReceived = MHD_YES;
+                  connection->remaining_upload_size = 0;
+                  connection->have_received_body = MHD_YES;
                 }
               else
                 {
-                  connection->uploadSize = -1;  /* unknown size */
-                  connection->bodyReceived = MHD_NO;
-                }
+                 if (connection->have_chunked_upload == MHD_NO) 
+                   {
+                     connection->remaining_upload_size = -1;  /* unknown size 
*/
+                     if (0 == 
strcasecmp(MHD_lookup_connection_value(connection,
+                                                                     
MHD_HEADER_KIND,
+                                                                     
MHD_HTTP_HEADER_TRANSFER_ENCODING),
+                                         "chunked"))
+                       connection->have_chunked_upload = MHD_YES;
+                   }
+                 else
+                   {
+                     /* we were actually processing the footers at the
+                        END of a chunked encoding; give connection 
+                        handler an extra chance... */
+                     connection->have_chunked_upload = MHD_NO; /* no more! */
+                     MHD_call_connection_handler(connection);
+                   }
+               }
             }
           if ((0 != (MHD_USE_PEDANTIC_CHECKS & connection->daemon->options))
               && (NULL != connection->version)
@@ -698,7 +716,7 @@
                                                MHD_HTTP_HEADER_HOST)))
             {
               /* die, http 1.1 request without host and we are pedantic */
-              connection->bodyReceived = MHD_YES;
+              connection->have_received_body = MHD_YES;
               connection->read_close = MHD_YES;
 #if HAVE_MESSAGES
               MHD_DLOG (connection->daemon,
@@ -780,54 +798,177 @@
 {
   struct MHD_Access_Handler *ah;
   unsigned int processed;
+  unsigned int available;
+  unsigned int used;
+  int instant_retry;
+  unsigned int i;
 
   if (connection->response != NULL)
     return;                     /* already queued a response */
-  if (connection->headersReceived == MHD_NO)
+  if (connection->have_received_headers == MHD_NO)
     abort ();                   /* bad timing... */
-  ah = MHD_find_access_handler (connection);
-  processed = connection->readLoc;
-  if (MHD_NO == ah->dh (ah->dh_cls,
-                        connection,
-                        connection->url,
-                        connection->method,
-                        connection->version,
-                        connection->read_buffer, &processed,
-                        &connection->client_context))
+  do 
     {
-      /* serious internal error, close connection */
+      instant_retry = MHD_NO;
+      available = connection->read_buffer_offset;
+      if (connection->have_chunked_upload == MHD_YES) 
+       {
+         if ( (connection->current_chunk_offset == 
connection->current_chunk_size) &&
+              (connection->current_chunk_offset != 0) &&
+              (available >= 2) )
+           {
+             /* skip new line at the *end* of a chunk */
+             i = 0;
+             if ( (connection->read_buffer[i] == '\r') ||
+                  (connection->read_buffer[i] == '\n') )
+               i++; /* skip 1st part of line feed */
+             if ( (connection->read_buffer[i] == '\r') ||
+                  (connection->read_buffer[i] == '\n') )
+               i++; /* skip 2nd part of line feed */
+             if (i == 0)
+               {
+                 /* malformed encoding */
 #if HAVE_MESSAGES
-      MHD_DLOG (connection->daemon,
-                "Internal application error, closing connection.\n");
+                 MHD_DLOG (connection->daemon,
+                           "Received malformed HTTP request (bad chunked 
encoding), closing connection.\n");
 #endif
-      connection_close_error (connection);
-      return;
-    }
-  /* dh left "processed" bytes in buffer for next time... */
-  memmove (connection->read_buffer,
-           &connection->read_buffer[connection->readLoc - processed],
-           processed);
-  if (connection->uploadSize != -1) 
-    connection->uploadSize -= (connection->readLoc - processed);  
-  connection->readLoc = processed;
-  if ((connection->uploadSize == 0) ||
-      ((connection->readLoc == 0) &&
-       (connection->uploadSize == -1) && (connection->socket_fd == -1)))
-    {
-      connection->bodyReceived = MHD_YES;
-      if (connection->read_buffer != NULL)
-        MHD_pool_reallocate (connection->pool,
-                             connection->read_buffer,
-                             (connection->read_buffer ==
-                              NULL) ? 0 : connection->read_buffer_size + 1,
-                             0);
-      connection->readLoc = 0;
-      connection->read_buffer_size = 0;
-      connection->read_buffer = NULL;
-    }
+                 connection_close_error (connection);
+                 return;
+               }
+             connection->read_buffer_offset -= i;
+             available -= i;
+             memmove(connection->read_buffer,
+                     &connection->read_buffer[i],
+                     available);
+             connection->current_chunk_offset = 0;
+             connection->current_chunk_size = 0;
+           }
+         if (connection->current_chunk_offset < connection->current_chunk_size)
+           {
+             /* we are in the middle of a chunk, give
+                as much as possible to the client (without
+                crossing chunk boundaries) */
+             processed = connection->current_chunk_size - 
connection->current_chunk_offset;
+             if (processed > available)
+               processed = available;    
+             available -= processed;
+             if (available > 0)
+               instant_retry = MHD_YES;
+           }
+         else
+           {
+             /* we need to read chunk boundaries */
+             i = 0;
+             while (i < available)
+               {
+                 if ( (connection->read_buffer[i] == '\r') ||
+                      (connection->read_buffer[i] == '\n') )
+                   break;
+                 i++;
+                 if (i >= 6)
+                   break;
+               }
+             if (i >= available)
+               return; /* need more data... */
+             /* The following if-statement is a bit crazy -- we
+                use the second clause only for the side-effect,
+                0-terminating the buffer for the following sscanf
+                attempts; yes, there should be only a single 
+                "="-sign (assignment!) in the read_buffer[i]-line. */
+             if ( (i >= 6) || 
+                  ((connection->read_buffer[i] = '\0')) ||
+                  ( (1 != sscanf(connection->read_buffer,
+                                 "%X",
+                                 &connection->current_chunk_size)) &&
+                    (1 != sscanf(connection->read_buffer,
+                                 "%x",
+                                 &connection->current_chunk_size)) ) )
+               {
+                 /* malformed encoding */
+#if HAVE_MESSAGES
+                 MHD_DLOG (connection->daemon,
+                           "Received malformed HTTP request (bad chunked 
encoding), closing connection.\n");
+#endif
+                 connection_close_error (connection);
+                 return;
+               }
+             i++;
+             if ( (connection->read_buffer[i] == '\r') ||
+                  (connection->read_buffer[i] == '\n') )
+               i++; /* skip 2nd part of line feed */
+             memmove(connection->read_buffer,
+                     &connection->read_buffer[i],
+                     available - i);
+             connection->read_buffer_offset -= i;
+             connection->current_chunk_offset = 0;
+             instant_retry = MHD_YES; 
+             if (connection->current_chunk_size == 0)
+               {
+                 /* we're back to reading HEADERS (footers!) */
+                 connection->have_received_body = MHD_YES;
+                 connection->remaining_upload_size = 0;
+                 connection->have_received_headers = MHD_NO;
+                 MHD_parse_connection_headers(connection);
+                 return;
+               }
+             continue;
+           }      
+       }
+      else
+       {
+         /* no chunked encoding, give all to the client */
+         processed = available;
+         available = 0;
+       }
+      used = processed;
+      ah = MHD_find_access_handler (connection);
+      if (MHD_NO == ah->dh (ah->dh_cls,
+                           connection,
+                           connection->url,
+                           connection->method,
+                           connection->version,
+                           connection->read_buffer, &processed,
+                           &connection->client_context))
+       {
+         /* serious internal error, close connection */
+#if HAVE_MESSAGES
+         MHD_DLOG (connection->daemon,
+                   "Internal application error, closing connection.\n");
+#endif
+         connection_close_error (connection);
+         return;
+       }
+      if (processed != 0)
+       instant_retry = MHD_NO; /* client did not process everything */
+      used -= processed;
+      if (connection->have_chunked_upload == MHD_YES) 
+       connection->current_chunk_offset += used;
+      /* dh left "processed" bytes in buffer for next time... */
+      if (used > 0)
+       memmove (connection->read_buffer,
+                &connection->read_buffer[used],
+                processed + available);
+      if (connection->remaining_upload_size != -1) 
+       connection->remaining_upload_size -= used;
+      connection->read_buffer_offset = processed + available;
+      if ((connection->remaining_upload_size == 0) ||
+         ((connection->read_buffer_offset == 0) &&
+          (connection->remaining_upload_size == -1) && (connection->socket_fd 
== -1)))
+       {
+         connection->have_received_body = MHD_YES;
+         if (connection->read_buffer != NULL)
+           MHD_pool_reallocate (connection->pool,
+                                connection->read_buffer,
+                                (connection->read_buffer ==
+                                 NULL) ? 0 : connection->read_buffer_size + 1,
+                                0);
+         connection->read_buffer_offset = 0;
+         connection->read_buffer_size = 0;
+         connection->read_buffer = NULL;
+       }
+    } while (instant_retry == MHD_YES);
 }
 
-
 /**
  * This function handles a particular connection when it has been
  * determined that there is data to be read off a socket. All implementations
@@ -850,8 +991,8 @@
       connection_close_error (connection);
       return MHD_NO;
     }
-  if ((connection->readLoc >= connection->read_buffer_size) &&
-      (connection->headersReceived == MHD_NO))
+  if ((connection->read_buffer_offset >= connection->read_buffer_size) &&
+      (connection->have_received_headers == MHD_NO))
     {
       /* need to grow read buffer */
       tmp = MHD_pool_reallocate (connection->pool,
@@ -873,7 +1014,7 @@
       connection->read_buffer_size =
         connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;
     }
-  if (connection->readLoc >= connection->read_buffer_size)
+  if (connection->read_buffer_offset >= connection->read_buffer_size)
     {
 #if HAVE_MESSAGES
       MHD_DLOG (connection->daemon, "Unexpected call to %s.\n", __FUNCTION__);
@@ -881,8 +1022,8 @@
       return MHD_NO;
     }
   bytes_read = RECV (connection->socket_fd,
-                     &connection->read_buffer[connection->readLoc],
-                     connection->read_buffer_size - connection->readLoc, 
+                     &connection->read_buffer[connection->read_buffer_offset],
+                     connection->read_buffer_size - 
connection->read_buffer_offset, 
                     MSG_NOSIGNAL);
   if (bytes_read < 0)
     {
@@ -899,7 +1040,7 @@
     {
       /* other side closed connection */
       connection->read_close = MHD_YES;
-      if ((connection->headersReceived == MHD_YES) && (connection->readLoc > 
0))
+      if ((connection->have_received_headers == MHD_YES) && 
(connection->read_buffer_offset > 0))
         MHD_call_connection_handler (connection);
 #if DEBUG_CLOSE
 #if HAVE_MESSAGES
@@ -908,18 +1049,18 @@
 #endif
 #endif
       shutdown (connection->socket_fd, SHUT_RD);
-      if ( (connection->headersReceived == MHD_NO) ||
-          (connection->bodyReceived == MHD_NO) ) {
+      if ( (connection->have_received_headers == MHD_NO) ||
+          (connection->have_received_body == MHD_NO) ) {
        /* no request => no response! */
        CLOSE (connection->socket_fd);
        connection->socket_fd = -1;
       }
       return MHD_YES;
     }
-  connection->readLoc += bytes_read;
-  if (connection->headersReceived == MHD_NO)
+  connection->read_buffer_offset += bytes_read;
+  if (connection->have_received_headers == MHD_NO)
     MHD_parse_connection_headers (connection);
-  if ((connection->headersReceived == MHD_YES) && (connection->method != NULL))
+  if ((connection->have_received_headers == MHD_YES) && (connection->method != 
NULL))
     MHD_call_connection_handler (connection);
   return MHD_YES;
 }
@@ -1035,8 +1176,8 @@
   if (off != size)
     abort ();
   connection->write_buffer = data;
-  connection->writeLoc = size;
-  connection->writePos = 0;
+  connection->write_buffer_append_offset = size;
+  connection->write_buffer_send_offset = 0;
   connection->write_buffer_size = size + 1;
   return MHD_YES;
 }
@@ -1057,8 +1198,8 @@
   if (MHD_need_100_continue (connection))
     {
       ret = SEND (connection->socket_fd,
-                  &HTTP_100_CONTINUE[connection->continuePos],
-                  strlen (HTTP_100_CONTINUE) - connection->continuePos, 
+                  
&HTTP_100_CONTINUE[connection->continue_message_write_offset],
+                  strlen (HTTP_100_CONTINUE) - 
connection->continue_message_write_offset, 
                  MSG_NOSIGNAL);
       if (ret < 0)
         {
@@ -1074,9 +1215,9 @@
 #if DEBUG_SEND_DATA
       fprintf (stderr,
                "Sent 100 continue response: `%.*s'\n",
-               ret, &HTTP_100_CONTINUE[connection->continuePos]);
+               ret, 
&HTTP_100_CONTINUE[connection->continue_message_write_offset]);
 #endif
-      connection->continuePos += ret;
+      connection->continue_message_write_offset += ret;
       return MHD_YES;
     }
   response = connection->response;
@@ -1087,7 +1228,7 @@
 #endif
       return MHD_NO;
     }
-  if (MHD_NO == connection->headersSent)
+  if (MHD_NO == connection->have_sent_headers)
     {
       if ((connection->write_buffer == NULL) &&
           (MHD_NO == MHD_build_header_response (connection)))
@@ -1101,8 +1242,8 @@
           return MHD_NO;
         }
       ret = SEND (connection->socket_fd,
-                  &connection->write_buffer[connection->writePos],
-                  connection->writeLoc - connection->writePos, 
+                  
&connection->write_buffer[connection->write_buffer_send_offset],
+                  connection->write_buffer_append_offset - 
connection->write_buffer_send_offset, 
                  MSG_NOSIGNAL);
       if (ret < 0)
         {
@@ -1118,14 +1259,14 @@
 #if DEBUG_SEND_DATA
       fprintf (stderr,
                "Sent HEADER response: `%.*s'\n",
-               ret, &connection->write_buffer[connection->writePos]);
+               ret, 
&connection->write_buffer[connection->write_buffer_send_offset]);
 #endif
-      connection->writePos += ret;
-      if (connection->writeLoc == connection->writePos)
+      connection->write_buffer_send_offset += ret;
+      if (connection->write_buffer_append_offset == 
connection->write_buffer_send_offset)
         {
-          connection->writeLoc = 0;
-          connection->writePos = 0;
-          connection->headersSent = MHD_YES;
+          connection->write_buffer_append_offset = 0;
+          connection->write_buffer_send_offset = 0;
+          connection->have_sent_headers = MHD_YES;
           MHD_pool_reallocate (connection->pool,
                                connection->write_buffer,
                                connection->write_buffer_size, 0);
@@ -1134,24 +1275,24 @@
         }
       return MHD_YES;
     }
-  if (response->total_size < connection->messagePos)
+  if (response->total_size < connection->response_write_position)
     abort ();                   /* internal error */
   if (response->crc != NULL)
     pthread_mutex_lock (&response->mutex);
 
   /* prepare send buffer */
   if ((response->crc != NULL) &&
-      ((response->data_start > connection->messagePos) ||
+      ((response->data_start > connection->response_write_position) ||
        (response->data_start + response->data_size <=
-        connection->messagePos)) && (MHD_YES != ready_response (connection)))
+        connection->response_write_position)) && (MHD_YES != ready_response 
(connection)))
     {
       pthread_mutex_unlock (&response->mutex);
       return MHD_YES;
     }
   /* transmit */
   ret = SEND (connection->socket_fd,
-              &response->data[connection->messagePos - response->data_start],
-              response->data_size - (connection->messagePos -
+              &response->data[connection->response_write_position - 
response->data_start],
+              response->data_size - (connection->response_write_position -
                                      response->data_start), 
              MSG_NOSIGNAL);
   if (response->crc != NULL)
@@ -1171,15 +1312,15 @@
   fprintf (stderr,
            "Sent DATA response: `%.*s'\n",
            ret,
-           &response->data[connection->messagePos - response->data_start]);
+           &response->data[connection->response_write_position - 
response->data_start]);
 #endif
-  connection->messagePos += ret;
-  if (connection->messagePos > response->total_size)
+  connection->response_write_position += ret;
+  if (connection->response_write_position > response->total_size)
     abort ();                   /* internal error */
-  if (connection->messagePos == response->total_size)
+  if (connection->response_write_position == response->total_size)
     {
-      if ((connection->bodyReceived == MHD_NO) ||
-          (connection->headersReceived == MHD_NO))
+      if ((connection->have_received_body == MHD_NO) ||
+          (connection->have_received_headers == MHD_NO))
         abort ();               /* internal error */
       MHD_destroy_response (response);
       if (connection->daemon->notify_completed != NULL)
@@ -1192,14 +1333,15 @@
                                         MHD_HEADER_KIND,
                                         MHD_HTTP_HEADER_CONNECTION);
       connection->client_context = NULL;
-      connection->continuePos = 0;
+      connection->continue_message_write_offset = 0;
       connection->responseCode = 0;
       connection->response = NULL;
       connection->headers_received = NULL;
-      connection->headersReceived = MHD_NO;
-      connection->headersSent = MHD_NO;
-      connection->bodyReceived = MHD_NO;
-      connection->messagePos = 0;
+      connection->have_received_headers = MHD_NO;
+      connection->have_sent_headers = MHD_NO;
+      connection->have_received_body = MHD_NO;
+      connection->response_write_position = 0;
+      connection->have_chunked_upload = MHD_NO;
       connection->method = NULL;
       connection->url = NULL;      
       if ((end != NULL) && (0 == strcasecmp (end, "close")))
@@ -1230,10 +1372,10 @@
       connection->read_buffer = NULL;
       connection->write_buffer = NULL;
       connection->read_buffer_size = 0;
-      connection->readLoc = 0;
+      connection->read_buffer_offset = 0;
       connection->write_buffer_size = 0;
-      connection->writePos = 0;
-      connection->writeLoc = 0;
+      connection->write_buffer_send_offset = 0;
+      connection->write_buffer_append_offset = 0;
       MHD_pool_destroy (connection->pool);
       connection->pool = NULL;
     }

Modified: libmicrohttpd/src/daemon/daemon.c
===================================================================
--- libmicrohttpd/src/daemon/daemon.c   2007-12-16 05:47:40 UTC (rev 5925)
+++ libmicrohttpd/src/daemon/daemon.c   2007-12-16 10:27:29 UTC (rev 5926)
@@ -227,7 +227,7 @@
            (FD_ISSET (con->socket_fd, &ws)) &&
            (MHD_YES != MHD_connection_handle_write (con))))
         break;
-      if ((con->headersReceived == MHD_YES) && (con->response == NULL))
+      if ((con->have_received_headers == MHD_YES) && (con->response == NULL))
         MHD_call_connection_handler (con);
       if ((con->socket_fd != -1) &&
           ((FD_ISSET (con->socket_fd, &rs)) ||
@@ -438,7 +438,7 @@
         }
 
       if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
-          ((pos->headersReceived == MHD_YES) && (pos->response == NULL)) )
+          ((pos->have_received_headers == MHD_YES) && (pos->response == NULL)) 
)
         MHD_call_connection_handler (pos);
 
       prev = pos;

Added: libmicrohttpd/src/daemon/daemontest_put_chunked.c
===================================================================
--- libmicrohttpd/src/daemon/daemontest_put_chunked.c                           
(rev 0)
+++ libmicrohttpd/src/daemon/daemontest_put_chunked.c   2007-12-16 10:27:29 UTC 
(rev 5926)
@@ -0,0 +1,382 @@
+/*
+     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_put_chunked.c
+ * @brief Testcase for libmicrohttpd PUT operations with chunked encoding
+ *        for the upload data
+ * @author Christian Grothoff
+ */
+
+#include "config.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+struct CBC
+{
+  char *buf;
+  size_t pos;
+  size_t size;
+};
+
+static size_t
+putBuffer (void *stream, size_t size, size_t nmemb, void *ptr)
+{
+  unsigned int *pos = ptr;
+  unsigned int wrt;
+
+  wrt = size * nmemb;
+  if (wrt > 8 - (*pos))
+    wrt = 8 - (*pos);
+  if (wrt > 4)
+    wrt = 4; /* only send half at first => force multiple chunks! */
+  memcpy (stream, &("Hello123"[*pos]), wrt);
+  (*pos) += wrt;
+  return wrt;
+}
+
+static size_t
+copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
+{
+  struct CBC *cbc = ctx;
+
+  if (cbc->pos + size * nmemb > cbc->size)
+    return 0;                   /* overflow */
+  memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+  cbc->pos += size * nmemb;
+  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,
+          void **unused)
+{
+  int *done = cls;
+  struct MHD_Response *response;
+  int ret;
+  int have;
+
+  if (0 != strcmp ("PUT", method))
+    return MHD_NO;              /* unexpected method */
+  if ((*done) < 8)
+    {
+      have = *upload_data_size;
+      if (have + *done > 8)
+       {
+          printf ("Invalid upload data `%8s'!\n", upload_data);
+          return MHD_NO;
+       }
+      if (0 == memcmp(upload_data,
+                     &"Hello123"[*done],
+                     have))
+       {
+         *done += have;
+         *upload_data_size = 0;
+       }
+      else
+       {
+          printf ("Invalid upload data `%8s'!\n", upload_data);
+          return MHD_NO;
+        }
+      return MHD_YES;
+    }
+  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
+testInternalPut ()
+{
+  struct MHD_Daemon *d;
+  CURL *c;
+  char buf[2048];
+  struct CBC cbc;
+  unsigned int pos = 0;
+  int done_flag = 0;
+  CURLcode errornum;
+
+  cbc.buf = buf;
+  cbc.size = 2048;
+  cbc.pos = 0;
+  d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
+                        11080,
+                        NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
+  if (d == NULL)
+    return 1;
+  c = curl_easy_init ();
+  curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world";);
+  curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+  curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+  curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+  curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+  curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+  /*
+    // by not giving the file size, we force chunking!
+    curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+  */
+  curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+  curl_easy_setopt (c, CURLOPT_TIMEOUT, 15L);
+  curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+  curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
+  // 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 != (errornum = curl_easy_perform (c)))
+    {
+      fprintf (stderr,
+               "curl_easy_perform failed: `%s'\n",
+               curl_easy_strerror (errornum));
+      curl_easy_cleanup (c);
+      MHD_stop_daemon (d);
+      return 2;
+    }
+  curl_easy_cleanup (c);
+  MHD_stop_daemon (d);
+  if (cbc.pos != strlen ("/hello_world"))
+    return 4;
+  if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+    return 8;
+  return 0;
+}
+
+static int
+testMultithreadedPut ()
+{
+  struct MHD_Daemon *d;
+  CURL *c;
+  char buf[2048];
+  struct CBC cbc;
+  unsigned int pos = 0;
+  int done_flag = 0;
+  CURLcode errornum;
+
+  cbc.buf = buf;
+  cbc.size = 2048;
+  cbc.pos = 0;
+  d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG,
+                        11081,
+                        NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
+  if (d == NULL)
+    return 16;
+  c = curl_easy_init ();
+  curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world";);
+  curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+  curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+  curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+  curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+  curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+  /*
+    // by not giving the file size, we force chunking!
+    curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+  */
+  curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+  curl_easy_setopt (c, CURLOPT_TIMEOUT, 15L);
+  curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+  curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
+  // 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 != (errornum = curl_easy_perform (c)))
+    {
+      fprintf (stderr,
+               "curl_easy_perform failed: `%s'\n",
+               curl_easy_strerror (errornum));
+      curl_easy_cleanup (c);
+      MHD_stop_daemon (d);
+      return 32;
+    }
+  curl_easy_cleanup (c);
+  MHD_stop_daemon (d);
+  if (cbc.pos != strlen ("/hello_world"))
+    return 64;
+  if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+    return 128;
+
+  return 0;
+}
+
+
+static int
+testExternalPut ()
+{
+  struct MHD_Daemon *d;
+  CURL *c;
+  char buf[2048];
+  struct CBC cbc;
+  CURLM *multi;
+  CURLMcode mret;
+  fd_set rs;
+  fd_set ws;
+  fd_set es;
+  int max;
+  int running;
+  struct CURLMsg *msg;
+  time_t start;
+  struct timeval tv;
+  unsigned int pos = 0;
+  int done_flag = 0;
+
+  multi = NULL;
+  cbc.buf = buf;
+  cbc.size = 2048;
+  cbc.pos = 0;
+  d = MHD_start_daemon (MHD_USE_DEBUG,
+                        11082,
+                        NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END);
+  if (d == NULL)
+    return 256;
+  c = curl_easy_init ();
+  curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11082/hello_world";);
+  curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+  curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+  curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer);
+  curl_easy_setopt (c, CURLOPT_READDATA, &pos);
+  curl_easy_setopt (c, CURLOPT_UPLOAD, 1L);
+  /*
+    // by not giving the file size, we force chunking!
+    curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L);
+  */
+  curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+  curl_easy_setopt (c, CURLOPT_TIMEOUT, 15L);
+  curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+  curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
+  // NOTE: use of CONNECTTIMEOUT without also
+  //   setting NOSIGNAL results in really weird
+  //   crashes on my system!
+  curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+
+
+  multi = curl_multi_init ();
+  if (multi == NULL)
+    {
+      curl_easy_cleanup (c);
+      MHD_stop_daemon (d);
+      return 512;
+    }
+  mret = curl_multi_add_handle (multi, c);
+  if (mret != CURLM_OK)
+    {
+      curl_multi_cleanup (multi);
+      curl_easy_cleanup (c);
+      MHD_stop_daemon (d);
+      return 1024;
+    }
+  start = time (NULL);
+  while ((time (NULL) - start < 5) && (multi != NULL))
+    {
+      max = 0;
+      FD_ZERO (&rs);
+      FD_ZERO (&ws);
+      FD_ZERO (&es);
+      curl_multi_perform (multi, &running);
+      mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+      if (mret != CURLM_OK)
+        {
+          curl_multi_remove_handle (multi, c);
+          curl_multi_cleanup (multi);
+          curl_easy_cleanup (c);
+          MHD_stop_daemon (d);
+          return 2048;
+        }
+      if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+        {
+          curl_multi_remove_handle (multi, c);
+          curl_multi_cleanup (multi);
+          curl_easy_cleanup (c);
+          MHD_stop_daemon (d);
+          return 4096;
+        }
+      tv.tv_sec = 0;
+      tv.tv_usec = 1000;
+      select (max + 1, &rs, &ws, &es, &tv);
+      curl_multi_perform (multi, &running);
+      if (running == 0)
+        {
+          msg = curl_multi_info_read (multi, &running);
+          if (msg == NULL)
+            break;
+          if (msg->msg == CURLMSG_DONE)
+            {
+              if (msg->data.result != CURLE_OK)
+                printf ("%s failed at %s:%d: `%s'\n",
+                        "curl_multi_perform",
+                        __FILE__,
+                        __LINE__, curl_easy_strerror (msg->data.result));
+              curl_multi_remove_handle (multi, c);
+              curl_multi_cleanup (multi);
+              curl_easy_cleanup (c);
+              c = NULL;
+              multi = NULL;
+            }
+        }
+      MHD_run (d);
+    }
+  if (multi != NULL)
+    {
+      curl_multi_remove_handle (multi, c);
+      curl_easy_cleanup (c);
+      curl_multi_cleanup (multi);
+    }
+  MHD_stop_daemon (d);
+  if (cbc.pos != strlen ("/hello_world"))
+    return 8192;
+  if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+    return 16384;
+  return 0;
+}
+
+
+
+int
+main (int argc, char *const *argv)
+{
+  unsigned int errorCount = 0;
+
+  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+    return 2;
+  errorCount += testInternalPut ();
+  if (0)
+    {
+      errorCount += testMultithreadedPut ();
+      errorCount += testExternalPut ();
+    }
+  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_put_chunked.c
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: libmicrohttpd/src/daemon/internal.h
===================================================================
--- libmicrohttpd/src/daemon/internal.h 2007-12-16 05:47:40 UTC (rev 5925)
+++ libmicrohttpd/src/daemon/internal.h 2007-12-16 10:27:29 UTC (rev 5926)
@@ -273,7 +273,7 @@
    * Position where we currently append data in
    * read_buffer (last valid position).
    */
-  size_t readLoc;
+  size_t read_buffer_offset;
 
   /**
    * Size of write_buffer (in bytes).
@@ -283,32 +283,33 @@
   /**
    * Offset where we are with sending from write_buffer.
    */
-  size_t writePos;
+  size_t write_buffer_send_offset;
 
   /**
-   * Last valid location in write_buffer.
+   * Last valid location in write_buffer (where do we
+   * append and up to where is it safe to send?)
    */
-  size_t writeLoc;
+  size_t write_buffer_append_offset;
 
   /**
    * Current write position in the actual response
    * (excluding headers, content only; should be 0
    * while sending headers).
    */
-  size_t messagePos;
+  size_t response_write_position;
 
   /**
    * Remaining (!) number of bytes in the upload.
    * Set to -1 for unknown (connection will close
    * to indicate end of upload).
    */
-  size_t uploadSize;
+  size_t remaining_upload_size;
 
   /**
    * Position in the 100 CONTINUE message that
    * we need to send when receiving http 1.1 requests.
    */
-  size_t continuePos;
+  size_t continue_message_write_offset;
 
   /**
    * Length of the foreign address.
@@ -343,18 +344,18 @@
    * possible that the NEXT request is already
    * (partially) waiting in the read buffer.
    */
-  int headersReceived;
+  int have_received_headers;
 
   /**
    * Have we finished receiving the data from a
    * potential file-upload?
    */
-  int bodyReceived;
+  int have_received_body;
 
   /**
    * Have we finished sending all of the headers yet?
    */
-  int headersSent;
+  int have_sent_headers;
 
   /**
    * HTTP response code.  Only valid if response object
@@ -371,6 +372,29 @@
    */
   int response_unready;
 
+  /**
+   * Are we receiving with chunked encoding?  This will be set to
+   * MHD_YES after we parse the headers and are processing the body
+   * with chunks.  After we are done with the body and we are
+   * processing the footers; once the footers are also done, this will
+   * be set to MHD_NO again (before the final call to the handler).
+   */
+  int have_chunked_upload;
+
+  /**
+   * If we are receiving with chunked encoding, where are we right
+   * now?  Set to 0 if we are waiting to receive the chunk size;
+   * otherwise, this is the size of the current chunk.  A value of
+   * zero is also used when we're at the end of the chunks.
+   */
+  unsigned int current_chunk_size;
+
+  /**
+   * If we are receiving with chunked encoding, where are we currently
+   * with respect to the current chunk (at what offset / position)?
+   */
+  unsigned int current_chunk_offset;
+
 };
 
 





reply via email to

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