gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r37859 - libmicrohttpd/src/microhttpd


From: gnunet
Subject: [GNUnet-SVN] r37859 - libmicrohttpd/src/microhttpd
Date: Sun, 4 Sep 2016 00:32:29 +0200

Author: grothoff
Date: 2016-09-04 00:32:29 +0200 (Sun, 04 Sep 2016)
New Revision: 37859

Added:
   libmicrohttpd/src/microhttpd/test_upgrade_ssl.c
Modified:
   libmicrohttpd/src/microhttpd/Makefile.am
   libmicrohttpd/src/microhttpd/connection.c
   libmicrohttpd/src/microhttpd/daemon.c
   libmicrohttpd/src/microhttpd/mhd_sockets.c
   libmicrohttpd/src/microhttpd/response.c
   libmicrohttpd/src/microhttpd/test_upgrade.c
Log:
-first, crazy-pants version of test and implementation of HTTPS upgrade; FLUSH 
API still needs to change dramatically, neither the ioctl nor the busy waiting 
are really acceptable here

Modified: libmicrohttpd/src/microhttpd/Makefile.am
===================================================================
--- libmicrohttpd/src/microhttpd/Makefile.am    2016-09-03 09:56:30 UTC (rev 
37858)
+++ libmicrohttpd/src/microhttpd/Makefile.am    2016-09-03 22:32:29 UTC (rev 
37859)
@@ -146,6 +146,10 @@
   test_daemon \
   test_upgrade
 
+if ENABLE_HTTPS
+  check_PROGRAMS += test_upgrade_ssl
+endif
+
 if HAVE_POSTPROCESSOR
 check_PROGRAMS += \
   test_postprocessor \
@@ -171,6 +175,11 @@
 test_upgrade_LDADD = \
   $(top_builddir)/src/microhttpd/libmicrohttpd.la
 
+test_upgrade_ssl_SOURCES = \
+  test_upgrade_ssl.c
+test_upgrade_ssl_LDADD = \
+  $(top_builddir)/src/microhttpd/libmicrohttpd.la
+
 test_postprocessor_SOURCES = \
   test_postprocessor.c
 test_postprocessor_CPPFLAGS = \

Modified: libmicrohttpd/src/microhttpd/connection.c
===================================================================
--- libmicrohttpd/src/microhttpd/connection.c   2016-09-03 09:56:30 UTC (rev 
37858)
+++ libmicrohttpd/src/microhttpd/connection.c   2016-09-03 22:32:29 UTC (rev 
37859)
@@ -2354,7 +2354,8 @@
               (void) MHD_mutex_unlock_ (&response->mutex);
             if (ret < 0)
               {
-                if (MHD_SCKT_ERR_IS_EINTR_ (err) || MHD_SCKT_ERR_IS_EAGAIN_ 
(err))
+                if (MHD_SCKT_ERR_IS_EINTR_ (err) ||
+                    MHD_SCKT_ERR_IS_EAGAIN_ (err))
                   return MHD_YES;
 #ifdef HAVE_MESSAGES
                 MHD_DLOG (connection->daemon,
@@ -2515,13 +2516,17 @@
                 }
               break;
             }
-          if (MHD_NO == parse_initial_message_line (connection, line, 
line_len))
-            CONNECTION_CLOSE_ERROR (connection, NULL);
+          if (MHD_NO == parse_initial_message_line (connection,
+                                                    line,
+                                                    line_len))
+            CONNECTION_CLOSE_ERROR (connection,
+                                    NULL);
           else
             connection->state = MHD_CONNECTION_URL_RECEIVED;
           continue;
         case MHD_CONNECTION_URL_RECEIVED:
-          line = get_next_header_line (connection, NULL);
+          line = get_next_header_line (connection,
+                                       NULL);
           if (NULL == line)
             {
               if (MHD_CONNECTION_URL_RECEIVED != connection->state)
@@ -2539,7 +2544,8 @@
               connection->state = MHD_CONNECTION_HEADERS_RECEIVED;
               continue;
             }
-          if (MHD_NO == process_header_line (connection, line))
+          if (MHD_NO == process_header_line (connection,
+                                             line))
             {
               transmit_error_response (connection,
                                        MHD_HTTP_BAD_REQUEST,
@@ -2645,7 +2651,8 @@
             }
           break;
         case MHD_CONNECTION_BODY_RECEIVED:
-          line = get_next_header_line (connection, NULL);
+          line = get_next_header_line (connection,
+                                       NULL);
           if (NULL == line)
             {
               if (connection->state != MHD_CONNECTION_BODY_RECEIVED)
@@ -2689,7 +2696,9 @@
               break;
             }
           if (MHD_NO ==
-              process_broken_line (connection, line, MHD_FOOTER_KIND))
+              process_broken_line (connection,
+                                   line,
+                                   MHD_FOOTER_KIND))
             continue;
           if (0 == line[0])
             {
@@ -3057,17 +3066,17 @@
     {
 #if HTTPS_SUPPORT
     case MHD_CONNECTION_INFO_CIPHER_ALGO:
-      if (connection->tls_session == NULL)
+      if (NULL == connection->tls_session)
        return NULL;
       connection->cipher = gnutls_cipher_get (connection->tls_session);
       return (const union MHD_ConnectionInfo *) &connection->cipher;
     case MHD_CONNECTION_INFO_PROTOCOL:
-      if (connection->tls_session == NULL)
+      if (NULL == connection->tls_session)
        return NULL;
       connection->protocol = gnutls_protocol_get_version 
(connection->tls_session);
       return (const union MHD_ConnectionInfo *) &connection->protocol;
     case MHD_CONNECTION_INFO_GNUTLS_SESSION:
-      if (connection->tls_session == NULL)
+      if (NULL == connection->tls_session)
        return NULL;
       return (const union MHD_ConnectionInfo *) &connection->tls_session;
 #endif

Modified: libmicrohttpd/src/microhttpd/daemon.c
===================================================================
--- libmicrohttpd/src/microhttpd/daemon.c       2016-09-03 09:56:30 UTC (rev 
37858)
+++ libmicrohttpd/src/microhttpd/daemon.c       2016-09-03 22:32:29 UTC (rev 
37859)
@@ -659,19 +659,19 @@
                               max_fd,
                               fd_setsize)) )
     return MHD_NO;
-  if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) &&
+  if ( (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->mhd.celi)) &&
        (! MHD_add_to_fd_set_ (urh->mhd.socket,
                               ws,
                               max_fd,
                               fd_setsize)) )
     return MHD_NO;
-  if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) &&
+  if ( (0 == (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) &&
        (! MHD_add_to_fd_set_ (urh->connection->socket_fd,
                               rs,
                               max_fd,
                               fd_setsize)) )
     return MHD_NO;
-  if ( (0 != (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) &&
+  if ( (0 == (MHD_EPOLL_STATE_WRITE_READY & urh->app.celi)) &&
        (! MHD_add_to_fd_set_ (urh->connection->socket_fd,
                               ws,
                               max_fd,
@@ -2639,10 +2639,17 @@
         may_block = MHD_NO;
 
       /* single-threaded, go over everything */
-      if (MHD_NO == MHD_get_fdset2 (daemon, &rs, &ws, &es, &maxsock, 
FD_SETSIZE))
+      if (MHD_NO ==
+          MHD_get_fdset2 (daemon,
+                          &rs,
+                          &ws,
+                          &es,
+                          &maxsock,
+                          FD_SETSIZE))
         {
 #ifdef HAVE_MESSAGES
-        MHD_DLOG (daemon, "Could not obtain daemon fdsets");
+        MHD_DLOG (daemon,
+                  "Could not obtain daemon fdsets");
 #endif
           err_state = MHD_YES;
         }
@@ -2657,7 +2664,8 @@
                                   FD_SETSIZE)) )
         {
 #ifdef HAVE_MESSAGES
-          MHD_DLOG (daemon, "Could not add listen socket to fdset");
+          MHD_DLOG (daemon,
+                    "Could not add listen socket to fdset");
 #endif
           return MHD_NO;
         }
@@ -2726,7 +2734,11 @@
         timeout.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE)(ltimeout / 1000);
       tv = &timeout;
     }
-  num_ready = MHD_SYS_select_ (maxsock + 1, &rs, &ws, &es, tv);
+  num_ready = MHD_SYS_select_ (maxsock + 1,
+                               &rs,
+                               &ws,
+                               &es,
+                               tv);
   if (MHD_YES == daemon->shutdown)
     return MHD_NO;
   if (num_ready < 0)

Modified: libmicrohttpd/src/microhttpd/mhd_sockets.c
===================================================================
--- libmicrohttpd/src/microhttpd/mhd_sockets.c  2016-09-03 09:56:30 UTC (rev 
37858)
+++ libmicrohttpd/src/microhttpd/mhd_sockets.c  2016-09-03 22:32:29 UTC (rev 
37859)
@@ -337,16 +337,21 @@
                     MHD_socket *max_fd,
                     unsigned int fd_setsize)
 {
-  if (NULL == set || MHD_INVALID_SOCKET == fd)
+  if ( (NULL == set) ||
+       (MHD_INVALID_SOCKET == fd) )
     return 0;
-  if (!MHD_SCKT_FD_FITS_FDSET_SETSIZE_(fd, set, fd_setsize))
+  if (! MHD_SCKT_FD_FITS_FDSET_SETSIZE_ (fd,
+                                         set,
+                                         fd_setsize))
     return 0;
-  MHD_SCKT_ADD_FD_TO_FDSET_SETSIZE_(fd, set, fd_setsize);
+  MHD_SCKT_ADD_FD_TO_FDSET_SETSIZE_(fd,
+                                    set,
+                                    fd_setsize);
   if ( (NULL != max_fd) &&
-       ((fd > *max_fd) || (MHD_INVALID_SOCKET == *max_fd)) )
+       ( (fd > *max_fd) ||
+         (MHD_INVALID_SOCKET == *max_fd) ) )
     *max_fd = fd;
-
-  return !0;
+  return ! 0;
 }
 
 

Modified: libmicrohttpd/src/microhttpd/response.c
===================================================================
--- libmicrohttpd/src/microhttpd/response.c     2016-09-03 09:56:30 UTC (rev 
37858)
+++ libmicrohttpd/src/microhttpd/response.c     2016-09-03 22:32:29 UTC (rev 
37859)
@@ -16,7 +16,6 @@
      License along with this library; if not, write to the Free Software
      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 
 USA
 */
-
 /**
  * @file response.c
  * @brief  Methods for managing response objects
@@ -34,6 +33,7 @@
 #include "connection.h"
 #include "memorypool.h"
 
+#include <sys/ioctl.h>
 
 #if defined(_WIN32) && defined(MHD_W32_MUTEX_)
 #ifndef WIN32_LEAN_AND_MEAN
@@ -202,7 +202,9 @@
       numHeaders++;
       if ((NULL != iterator) &&
           (MHD_YES != iterator (iterator_cls,
-                                pos->kind, pos->header, pos->value)))
+                                pos->kind,
+                                pos->header,
+                                pos->value)))
         break;
     }
   return numHeaders;
@@ -337,16 +339,23 @@
     return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is 
not possible */
 
 #if defined(HAVE_LSEEK64)
-  if (lseek64 (response->fd, offset64, SEEK_SET) != offset64)
+  if (lseek64 (response->fd,
+               offset64,
+               SEEK_SET) != offset64)
     return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required 
position */
 #elif defined(HAVE___LSEEKI64)
-  if (_lseeki64 (response->fd, offset64, SEEK_SET) != offset64)
+  if (_lseeki64 (response->fd,
+                 offset64,
+                 SEEK_SET) != offset64)
     return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required 
position */
 #else /* !HAVE___LSEEKI64 */
-  if (sizeof(off_t) < sizeof(uint64_t) && offset64 > (uint64_t)INT32_MAX)
+  if ( (sizeof(off_t) < sizeof (uint64_t)) &&
+       (offset64 > (uint64_t)INT32_MAX) )
     return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is 
not possible */
 
-  if (lseek (response->fd, (off_t)offset64, SEEK_SET) != (off_t)offset64)
+  if (lseek (response->fd,
+             (off_t) offset64,
+             SEEK_SET) != (off_t) offset64)
     return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required 
position */
 #endif
 
@@ -354,12 +363,16 @@
   if (max > SSIZE_MAX)
     max = SSIZE_MAX;
 
-  n = read (response->fd, buf, max);
+  n = read (response->fd,
+            buf,
+            max);
 #else  /* _WIN32 */
   if (max > INT32_MAX)
     max = INT32_MAX;
 
-  n = read (response->fd, buf, (unsigned int)max);
+  n = read (response->fd,
+            buf,
+            (unsigned int)max);
 #endif /* _WIN32 */
 
   if (0 == n)
@@ -438,8 +451,10 @@
   struct MHD_Response *response;
 
 #if !defined(HAVE___LSEEKI64) && !defined(HAVE_LSEEK64)
-  if (sizeof(uint64_t) > sizeof(off_t) &&
-      (size > (uint64_t)INT32_MAX || offset > (uint64_t)INT32_MAX || (size + 
offset) >= (uint64_t)INT32_MAX))
+  if ( (sizeof(uint64_t) > sizeof(off_t)) &&
+       ( (size > (uint64_t)INT32_MAX) ||
+         (offset > (uint64_t)INT32_MAX) ||
+         ((size + offset) >= (uint64_t)INT32_MAX) ) )
     return NULL;
 #endif
   if ( ((int64_t)size < 0) ||
@@ -530,7 +545,9 @@
     return NULL;
   if (NULL == (response = malloc (sizeof (struct MHD_Response))))
     return NULL;
-  memset (response, 0, sizeof (struct MHD_Response));
+  memset (response,
+          0,
+          sizeof (struct MHD_Response));
   response->fd = -1;
   if (! MHD_mutex_init_ (&response->mutex))
     {
@@ -675,8 +692,30 @@
     /* FIXME: not implemented */
     return MHD_NO;
   case MHD_UPGRADE_ACTION_FLUSH:
-    /* FIXME: not implemented */
-    return MHD_NO;
+#if HTTPS_SUPPORT
+    if (0 != (daemon->options & MHD_USE_SSL))
+      {
+        int avail;
+
+        /* First, check that our pipe is empty, to be sure we do
+           have it all in the buffer. */
+        if ( (0 ==
+#if WINDOWS
+              ioctlsocket
+#else
+              ioctl
+#endif
+              (urh->mhd.socket,
+               FIONREAD,
+               &avail)) &&
+             (0 != avail) )
+          return MHD_NO;
+        /* then, refuse 'flush' unless our buffer is empty */
+        if (0 != urh->out_buffer_off)
+          return MHD_NO;
+      }
+#endif
+    return MHD_YES;
   default:
     /* we don't understand this one */
     return MHD_NO;

Modified: libmicrohttpd/src/microhttpd/test_upgrade.c
===================================================================
--- libmicrohttpd/src/microhttpd/test_upgrade.c 2016-09-03 09:56:30 UTC (rev 
37858)
+++ libmicrohttpd/src/microhttpd/test_upgrade.c 2016-09-03 22:32:29 UTC (rev 
37859)
@@ -298,7 +298,9 @@
   sa.sin_family = AF_INET;
   sa.sin_port = htons (1080);
   sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-  if (0 != connect (sock, (struct sockaddr *) &sa, sizeof (sa)))
+  if (0 != connect (sock,
+                    (struct sockaddr *) &sa,
+                    sizeof (sa)))
     abort ();
   send_all (sock,
             "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n");
@@ -316,12 +318,15 @@
 
 
 int
-main (int argc, char *const *argv)
+main (int argc,
+      char *const *argv)
 {
   int errorCount = 0;
 
   errorCount += test_upgrade_internal_select ();
   if (errorCount != 0)
-    fprintf (stderr, "Error (code: %u)\n", errorCount);
+    fprintf (stderr,
+             "Error (code: %u)\n",
+             errorCount);
   return errorCount != 0;       /* 0 == pass */
 }

Added: libmicrohttpd/src/microhttpd/test_upgrade_ssl.c
===================================================================
--- libmicrohttpd/src/microhttpd/test_upgrade_ssl.c                             
(rev 0)
+++ libmicrohttpd/src/microhttpd/test_upgrade_ssl.c     2016-09-03 22:32:29 UTC 
(rev 37859)
@@ -0,0 +1,472 @@
+/*
+     This file is part of libmicrohttpd
+     Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file test_upgrade_ssl.c
+ * @brief  Testcase for libmicrohttpd upgrading a connection
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "microhttpd.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef WINDOWS
+#include <unistd.h>
+#endif
+
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <pthread.h>
+#include "mhd_sockets.h"
+
+#include "../testcurl/https/tls_test_keys.h"
+
+
+/**
+ * Thread we use to run the interaction with the upgraded socket.
+ */
+static pthread_t pt;
+
+/**
+ * Will be set to the upgraded socket.
+ */
+static MHD_socket usock;
+
+/**
+ * Fork child that connects via OpenSSL to our @a port.  Allows us to
+ * talk to our port over a socket in @a sp without having to worry
+ * about TLS.
+ *
+ * @param location where the socket is returned
+ * @return -1 on error, otherwise PID of SSL child process
+ */
+static pid_t
+openssl_connect (int *sock,
+                 uint16_t port)
+{
+  pid_t chld;
+  int sp[2];
+  char destination[30];
+
+  if (0 != socketpair (AF_UNIX,
+                       SOCK_STREAM,
+                       0,
+                       sp))
+    return -1;
+  chld = fork ();
+  if (0 != chld)
+    {
+      *sock = sp[1];
+      MHD_socket_close_ (sp[0]);
+      return chld;
+    }
+  MHD_socket_close_ (sp[1]);
+  (void) close (0);
+  (void) close (1);
+  dup2 (sp[0], 0);
+  dup2 (sp[0], 1);
+  close (sp[0]);
+  sprintf (destination,
+           "localhost:%u",
+           (unsigned int) port);
+  execlp ("openssl",
+          "openssl",
+          "s_client",
+          "-connect",
+          destination,
+          "-verify",
+          "0",
+          // "-quiet",
+          (char *) NULL);
+  _exit (1);
+}
+
+
+/**
+ * Change itc FD options to be non-blocking.
+ *
+ * @param fd the FD to manipulate
+ * @return non-zero if succeeded, zero otherwise
+ */
+static void
+make_blocking (MHD_socket fd)
+{
+  int flags;
+
+  flags = fcntl (fd, F_GETFL);
+  if (-1 == flags)
+    return;
+  if ((flags & ~O_NONBLOCK) != flags)
+    fcntl (fd, F_SETFL, flags & ~O_NONBLOCK);
+}
+
+
+static void
+send_all (MHD_socket sock,
+          const char *text)
+{
+  size_t len = strlen (text);
+  ssize_t ret;
+
+  make_blocking (sock);
+  for (size_t off = 0; off < len; off += ret)
+    {
+      ret = write (sock,
+                   &text[off],
+                   len - off);
+      if (-1 == ret)
+        {
+          if (EAGAIN == errno)
+            {
+              ret = 0;
+              continue;
+            }
+          abort ();
+        }
+    }
+}
+
+
+/**
+ * Read character-by-character until we
+ * get '\r\n\r\n'.
+ */
+static void
+recv_hdr (MHD_socket sock)
+{
+  unsigned int i;
+  char next;
+  char c;
+  ssize_t ret;
+
+  make_blocking (sock);
+  next = '\r';
+  i = 0;
+  while (i < 4)
+    {
+      ret = read (sock,
+                  &c,
+                  1);
+      if (0 == ret)
+        abort (); /* this is fatal */
+      if (-1 == ret)
+        {
+          if (EAGAIN == errno)
+            {
+              ret = 0;
+              continue;
+            }
+          abort ();
+        }
+      if (0 == ret)
+        continue;
+      if (c == next)
+        {
+          i++;
+          if (next == '\r')
+            next = '\n';
+          else
+            next = '\r';
+          continue;
+        }
+      if (c == '\r')
+        {
+          i = 1;
+          next = '\n';
+          continue;
+        }
+      i = 0;
+      next = '\r';
+    }
+}
+
+
+static void
+recv_all (MHD_socket sock,
+          const char *text)
+{
+  size_t len = strlen (text);
+  char buf[len];
+  ssize_t ret;
+
+  make_blocking (sock);
+  for (size_t off = 0; off < len; off += ret)
+    {
+      ret = read (sock,
+                  &buf[off],
+                  len - off);
+      if (0 == ret)
+        abort (); /* this is fatal */
+      if (-1 == ret)
+        {
+          if (EAGAIN == errno)
+            {
+              ret = 0;
+              continue;
+            }
+          abort ();
+        }
+    }
+  if (0 != strncmp (text, buf, len))
+    abort();
+}
+
+
+/**
+ * Main function for the thread that runs the interaction with
+ * the upgraded socket.
+ *
+ * @param cls the handle for the upgrade
+ */
+static void *
+run_usock (void *cls)
+{
+  struct MHD_UpgradeResponseHandle *urh = cls;
+
+  fprintf (stderr,
+           "Sending `Hello'\n");
+  send_all (usock,
+            "Hello");
+  fprintf (stderr,
+           "Receiving `World'\n");
+  recv_all (usock,
+            "World");
+  fprintf (stderr,
+           "Sending `Finished'\n");
+  send_all (usock,
+            "Finished");
+  fprintf (stderr,
+           "Closing socket\n");
+  while (MHD_NO ==
+         MHD_upgrade_action (urh,
+                             MHD_UPGRADE_ACTION_FLUSH))
+    usleep (1000);
+  MHD_upgrade_action (urh,
+                      MHD_UPGRADE_ACTION_CLOSE);
+  fprintf (stderr,
+           "Thread terminating\n");
+  return NULL;
+}
+
+
+/**
+ * Function called after a protocol "upgrade" response was sent
+ * successfully and the socket should now be controlled by some
+ * protocol other than HTTP.
+ *
+ * Any data received on the socket will be made available in
+ * 'data_in'.  The function should update 'data_in_size' to
+ * reflect the number of bytes consumed from 'data_in' (the remaining
+ * bytes will be made available in the next call to the handler).
+ *
+ * Any data that should be transmitted on the socket should be
+ * stored in 'data_out'.  '*data_out_size' is initially set to
+ * the available buffer space in 'data_out'.  It should be set to
+ * the number of bytes stored in 'data_out' (which can be zero).
+ *
+ * The return value is a BITMASK that indicates how the function
+ * intends to interact with the event loop.  It can request to be
+ * notified for reading, writing, request to UNCORK the send buffer
+ * (which MHD is allowed to ignore, if it is not possible to uncork on
+ * the local platform), to wait for the 'external' select loop to
+ * trigger another round.  It is also possible to specify "no events"
+ * to terminate the connection; in this case, the
+ * #MHD_RequestCompletedCallback will be called and all resources of
+ * the connection will be released.
+ *
+ * Except when in 'thread-per-connection' mode, implementations
+ * of this function should never block (as it will still be called
+ * from within the main event loop).
+ *
+ * @param cls closure, whatever was given to 
#MHD_create_response_for_upgrade().
+ * @param connection original HTTP connection handle,
+ *                   giving the function a last chance
+ *                   to inspect the original HTTP request
+ * @param con_cls last value left in `*con_cls` in the 
`MHD_AccessHandlerCallback`
+ * @param extra_in if we happened to have read bytes after the
+ *                 HTTP header already (because the client sent
+ *                 more than the HTTP header of the request before
+ *                 we sent the upgrade response),
+ *                 these are the extra bytes already read from @a sock
+ *                 by MHD.  The application should treat these as if
+ *                 it had read them from @a sock.
+ * @param extra_in_size number of bytes in @a extra_in
+ * @param sock socket to use for bi-directional communication
+ *        with the client.  For HTTPS, this may not be a socket
+ *        that is directly connected to the client and thus certain
+ *        operations (TCP-specific setsockopt(), getsockopt(), etc.)
+ *        may not work as expected (as the socket could be from a
+ *        socketpair() or a TCP-loopback)
+ * @param urh argument for #MHD_upgrade_action()s on this @a connection.
+ *        Applications must eventually use this function to perform the
+ *        close() action on the @a sock.
+ */
+static void
+upgrade_cb (void *cls,
+            struct MHD_Connection *connection,
+            void *con_cls,
+            const char *extra_in,
+            size_t extra_in_size,
+            MHD_socket sock,
+            struct MHD_UpgradeResponseHandle *urh)
+{
+  usock = sock;
+  if (0 != extra_in_size)
+    abort ();
+  pthread_create (&pt,
+                  NULL,
+                  &run_usock,
+                  urh);
+}
+
+
+/**
+ * A client has requested the given url using the given method
+ * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
+ * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc).  The callback
+ * must call MHD callbacks to provide content to give back to the
+ * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
+ * #MHD_HTTP_NOT_FOUND, etc.).
+ *
+ * @param cls argument given together with the function
+ *        pointer when the handler was registered with MHD
+ * @param url the requested url
+ * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
+ *        #MHD_HTTP_METHOD_PUT, etc.)
+ * @param version the HTTP version string (i.e.
+ *        #MHD_HTTP_VERSION_1_1)
+ * @param upload_data the data being uploaded (excluding HEADERS,
+ *        for a POST that fits into memory and that is encoded
+ *        with a supported encoding, the POST data will NOT be
+ *        given in upload_data and is instead available as
+ *        part of #MHD_get_connection_values; very large POST
+ *        data *will* be made available incrementally in
+ *        @a upload_data)
+ * @param upload_data_size set initially to the size of the
+ *        @a upload_data provided; the method must update this
+ *        value to the number of bytes NOT processed;
+ * @param con_cls pointer that the callback can set to some
+ *        address and that will be preserved by MHD for future
+ *        calls for this request; since the access handler may
+ *        be called many times (i.e., for a PUT/POST operation
+ *        with plenty of upload data) this allows the application
+ *        to easily associate some request-specific state.
+ *        If necessary, this state can be cleaned up in the
+ *        global #MHD_RequestCompletedCallback (which
+ *        can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
+ *        Initially, `*con_cls` will be NULL.
+ * @return #MHD_YES if the connection was handled successfully,
+ *         #MHD_NO if the socket must be closed due to a serios
+ *         error while handling the request
+ */
+static int
+ahc_upgrade (void *cls,
+             struct MHD_Connection *connection,
+             const char *url,
+             const char *method,
+             const char *version,
+             const char *upload_data,
+             size_t *upload_data_size,
+             void **con_cls)
+{
+  struct MHD_Response *resp;
+  int ret;
+
+  resp = MHD_create_response_for_upgrade (&upgrade_cb,
+                                          NULL);
+  MHD_add_response_header (resp,
+                           MHD_HTTP_HEADER_UPGRADE,
+                           "Hello World Protocol");
+  ret = MHD_queue_response (connection,
+                            MHD_HTTP_SWITCHING_PROTOCOLS,
+                            resp);
+  MHD_destroy_response (resp);
+  return ret;
+}
+
+
+static int
+test_upgrade_internal_select ()
+{
+  struct MHD_Daemon *d;
+  MHD_socket sock;
+  pid_t pid;
+
+  d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | 
MHD_USE_SUSPEND_RESUME | MHD_USE_TLS,
+                        1080,
+                        NULL, NULL,
+                        &ahc_upgrade, NULL,
+                        MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
+                        MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
+                        MHD_OPTION_END);
+  if (NULL == d)
+    return 2;
+  if (-1 == (pid = openssl_connect (&sock, 1080)))
+    {
+      MHD_stop_daemon (d);
+      return 4;
+    }
+
+  send_all (sock,
+            "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n");
+  recv_hdr (sock);
+  recv_all (sock,
+            "Hello");
+  fprintf (stderr,
+           "Received `Hello'\n");
+  send_all (sock,
+            "World");
+  fprintf (stderr,
+           "Sent `World'\n");
+  recv_all (sock,
+            "Finished");
+  fprintf (stderr,
+           "Received `Finished'\n");
+  MHD_socket_close_ (sock);
+  pthread_join (pt,
+                NULL);
+  fprintf (stderr,
+           "Joined helper thread\n");
+  waitpid (pid, NULL, 0);
+  MHD_stop_daemon (d);
+  return 0;
+}
+
+
+int
+main (int argc,
+      char *const *argv)
+{
+  int errorCount = 0;
+
+  if (0 != system ("openssl version 1> /dev/null"))
+    return 77; /* openssl not available, can't run the test */
+  errorCount += test_upgrade_internal_select ();
+  if (errorCount != 0)
+    fprintf (stderr,
+             "Error (code: %u)\n",
+             errorCount);
+  return errorCount != 0;       /* 0 == pass */
+}




reply via email to

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