Ver Fonte

adding MHD_OPTION_ARRAY

Christian Grothoff há 16 anos atrás
pai
commit
bf1d64a78d
3 ficheiros alterados com 298 adições e 78 exclusões
  1. 39 0
      doc/microhttpd.texi
  2. 209 77
      src/daemon/daemon.c
  3. 50 1
      src/include/microhttpd.h

+ 39 - 0
doc/microhttpd.texi

@@ -384,10 +384,49 @@ Note that MHD will not generate any log messages
 if it was compiled without the "--enable-messages"
 flag being set and the MHD_USE_DEBUG flag being set, 
 even if this argument is used.
+
+@item MHD_OPTION_ARRAY
+@cindex options
+This option can be used for initializing MHD using options from an
+array.  A common use for this is writing an FFI for MHD.  The actual
+options given are in an array of 'struct MHD_OptionItem', so this
+option requires a single argument of type 'struct MHD_OptionItem'.
+The array must be terminated with an entry @code{MHD_OPTION_END}.
+
+An example for code using MHD_OPTION_ARRAY is:
+@example
+struct MHD_OptionItem ops[] = @{
+ @{ MHD_OPTION_CONNECTION_LIMIT, 100, NULL @},
+ @{ MHD_OPTION_CONNECTION_TIMEOUT, 10, NULL @},
+ @{ MHD_OPTION_END, 0, NULL @}
+@};
+d = MHD_start_daemon(0, 8080, NULL, NULL, dh, NULL,
+                     MHD_OPTION_ARRAY, ops,
+                     MHD_OPTION_END);
+@end example
+For options that expect a single pointer argument, the
+second member of the @code{struct MHD_OptionItem} is ignored.
+For options that expect two pointer arguments, the first
+argument must be cast to @code{intptr_t}.
 @end table
 @end deftp
 
 
+@deftp {C Struct} MHD_OptionItem
+Entry in an MHD_OPTION_ARRAY.  See the @code{MHD_OPTION_ARRAY} option
+argument for its use. 
+
+The @code{option} member is used to specify which option is specified
+in the array.  The other members specify the respective argument.
+
+Note that for options taking only a single pointer, the
+@code{ptr_value} member should be set.  For options taking two pointer
+arguments, the first pointer must be cast to @code{intptr_t} and both
+the @code{value} and the @code{ptr_value} members should be used to
+pass the two pointers.
+@end deftp
+
+
 @deftp {Enumeration} MHD_ValueKind
 The @code{MHD_ValueKind} specifies the source of the key-value pairs in
 the @http{} protocol.

+ 209 - 77
src/daemon/daemon.c

@@ -1141,6 +1141,212 @@ MHD_start_daemon (unsigned int options,
 
 typedef void (*VfprintfFunctionPointerType)(void *, const char *, va_list);
 
+
+/**
+ * Parse a list of options given as varargs.
+ * 
+ * @param daemon the daemon to initialize
+ * @param ap the options
+ * @return MHD_YES on success, MHD_NO on error
+ */
+static int
+parse_options_va (struct MHD_Daemon *daemon,
+		  const struct sockaddr **servaddr,
+		  va_list ap);
+
+
+/**
+ * Parse a list of options given as varargs.
+ * 
+ * @param daemon the daemon to initialize
+ * @param ... the options
+ * @return MHD_YES on success, MHD_NO on error
+ */
+static int
+parse_options (struct MHD_Daemon *daemon,
+	       const struct sockaddr **servaddr,
+	       ...)
+{
+  va_list ap;
+  int ret;
+
+  va_start (ap, servaddr);
+  ret = parse_options_va (daemon, servaddr, ap);
+  va_end (ap);
+  return ret;
+}
+
+
+/**
+ * Parse a list of options given as varargs.
+ * 
+ * @param daemon the daemon to initialize
+ * @param ap the options
+ * @return MHD_YES on success, MHD_NO on error
+ */
+static int
+parse_options_va (struct MHD_Daemon *daemon,
+		  const struct sockaddr **servaddr,
+		  va_list ap)
+{
+  enum MHD_OPTION opt;
+  struct MHD_OptionItem *oa;
+  unsigned int i;
+  
+  while (MHD_OPTION_END != (opt = va_arg (ap, enum MHD_OPTION)))
+    {
+      switch (opt)
+        {
+        case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
+          daemon->pool_size = va_arg (ap, size_t);
+          break;
+        case MHD_OPTION_CONNECTION_LIMIT:
+          daemon->max_connections = va_arg (ap, unsigned int);
+          break;
+        case MHD_OPTION_CONNECTION_TIMEOUT:
+          daemon->connection_timeout = va_arg (ap, unsigned int);
+          break;
+        case MHD_OPTION_NOTIFY_COMPLETED:
+          daemon->notify_completed =
+            va_arg (ap, MHD_RequestCompletedCallback);
+          daemon->notify_completed_cls = va_arg (ap, void *);
+          break;
+        case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
+          daemon->per_ip_connection_limit = va_arg (ap, unsigned int);
+          break;
+        case MHD_OPTION_SOCK_ADDR:
+          *servaddr = va_arg (ap, const struct sockaddr *);
+          break;
+        case MHD_OPTION_URI_LOG_CALLBACK:
+          daemon->uri_log_callback =
+            va_arg (ap, LogCallback);
+          daemon->uri_log_callback_cls = va_arg (ap, void *);
+          break;
+        case MHD_OPTION_THREAD_POOL_SIZE:
+          daemon->worker_pool_size = va_arg (ap, unsigned int);
+          break;
+#if HTTPS_SUPPORT
+        case MHD_OPTION_PROTOCOL_VERSION:
+          _set_priority (&daemon->priority_cache->protocol,
+                         va_arg (ap, const int *));
+          break;
+        case MHD_OPTION_HTTPS_MEM_KEY:
+          daemon->https_mem_key = va_arg (ap, const char *);
+          break;
+        case MHD_OPTION_HTTPS_MEM_CERT:
+          daemon->https_mem_cert = va_arg (ap, const char *);
+          break;
+        case MHD_OPTION_CIPHER_ALGORITHM:
+          _set_priority (&daemon->priority_cache->cipher,
+                         va_arg (ap, const int *));
+          break;
+#endif
+        case MHD_OPTION_EXTERNAL_LOGGER:
+#if HAVE_MESSAGES
+          daemon->custom_error_log =
+            va_arg (ap, VfprintfFunctionPointerType);
+          daemon->custom_error_log_cls = va_arg (ap, void *);
+#else
+          va_arg (ap, VfprintfFunctionPointerType);
+          va_arg (ap, void *);
+#endif
+          break;
+	case MHD_OPTION_ARRAY:
+	  oa = va_arg (ap, struct MHD_OptionItem*);
+	  i = 0;
+	  while (MHD_OPTION_END != (opt = oa[i].option))
+	    {
+	      switch (opt)
+		{
+		case MHD_OPTION_END:
+		  abort ();
+		  break;
+		  /* all options taking 'size_t' */
+		case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
+		  if (MHD_YES != parse_options (daemon,
+						servaddr,
+						opt,
+						(size_t) oa[i].value,
+						MHD_OPTION_END))
+		    return MHD_NO;
+		  break;
+		  /* all options taking 'unsigned int' */
+		case MHD_OPTION_CONNECTION_LIMIT:
+		case MHD_OPTION_CONNECTION_TIMEOUT:
+		case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
+		case MHD_OPTION_THREAD_POOL_SIZE:
+		  if (MHD_YES != parse_options (daemon,
+						servaddr,
+						opt,
+						(unsigned int) oa[i].value,
+						MHD_OPTION_END))
+		    return MHD_NO;
+		  break;
+		  /* all options taking 'int' or 'enum' */
+		case MHD_OPTION_CRED_TYPE:
+		  if (MHD_YES != parse_options (daemon,
+						servaddr,
+						opt,
+						(int) oa[i].value,
+						MHD_OPTION_END))
+		    return MHD_NO;
+		  break;
+		  /* all options taking one pointer */
+		case MHD_OPTION_SOCK_ADDR:
+		case MHD_OPTION_HTTPS_MEM_KEY:
+		case MHD_OPTION_HTTPS_MEM_CERT:
+		case MHD_OPTION_PROTOCOL_VERSION:
+		case MHD_OPTION_CIPHER_ALGORITHM:
+		case MHD_OPTION_ARRAY:
+		  if (MHD_YES != parse_options (daemon,
+						servaddr,
+						opt,
+						oa[i].ptr_value,
+						MHD_OPTION_END))
+		    return MHD_NO;
+		  break;
+		  /* all options taking two pointers */
+		case MHD_OPTION_NOTIFY_COMPLETED:
+		case MHD_OPTION_URI_LOG_CALLBACK:
+		case MHD_OPTION_EXTERNAL_LOGGER:
+		  if (MHD_YES != parse_options (daemon,
+						servaddr,
+						opt,
+						(void *) oa[i].value,
+						oa[i].ptr_value,
+						MHD_OPTION_END))
+		    return MHD_NO;
+		  break;
+		  
+		default:
+		  return MHD_NO;
+		}
+	      i++;
+	    }
+	  break;
+        default:
+#if HAVE_MESSAGES
+          if ((opt >= MHD_OPTION_HTTPS_MEM_KEY) &&
+              (opt <= MHD_OPTION_CIPHER_ALGORITHM))
+            {
+              FPRINTF (stderr,
+                       "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n",
+                       opt);
+            }
+          else
+            {
+              FPRINTF (stderr,
+                       "Invalid option %d! (Did you terminate the list with MHD_OPTION_END?)\n",
+                       opt);
+            }
+#endif
+	  return MHD_NO;
+        }
+    }  
+  return MHD_YES;
+}
+
+
 /**
  * Start a webserver on the given port.
  *
@@ -1168,7 +1374,6 @@ MHD_start_daemon_va (unsigned int options,
 #endif
   const struct sockaddr *servaddr = NULL;
   socklen_t addrlen;
-  enum MHD_OPTION opt;
   unsigned int i;
 
   if ((port == 0) || (dh == NULL))
@@ -1215,83 +1420,10 @@ MHD_start_daemon_va (unsigned int options,
     }
 #endif
 
-  while (MHD_OPTION_END != (opt = va_arg (ap, enum MHD_OPTION)))
+  if (MHD_YES != parse_options_va (retVal, &servaddr, ap))
     {
-      switch (opt)
-        {
-        case MHD_OPTION_CONNECTION_MEMORY_LIMIT:
-          retVal->pool_size = va_arg (ap, size_t);
-          break;
-        case MHD_OPTION_CONNECTION_LIMIT:
-          retVal->max_connections = va_arg (ap, unsigned int);
-          break;
-        case MHD_OPTION_CONNECTION_TIMEOUT:
-          retVal->connection_timeout = va_arg (ap, unsigned int);
-          break;
-        case MHD_OPTION_NOTIFY_COMPLETED:
-          retVal->notify_completed =
-            va_arg (ap, MHD_RequestCompletedCallback);
-          retVal->notify_completed_cls = va_arg (ap, void *);
-          break;
-        case MHD_OPTION_PER_IP_CONNECTION_LIMIT:
-          retVal->per_ip_connection_limit = va_arg (ap, unsigned int);
-          break;
-        case MHD_OPTION_SOCK_ADDR:
-          servaddr = va_arg (ap, struct sockaddr *);
-          break;
-        case MHD_OPTION_URI_LOG_CALLBACK:
-          retVal->uri_log_callback =
-            va_arg (ap, LogCallback);
-          retVal->uri_log_callback_cls = va_arg (ap, void *);
-          break;
-        case MHD_OPTION_THREAD_POOL_SIZE:
-          retVal->worker_pool_size = va_arg (ap, unsigned int);
-          break;
-#if HTTPS_SUPPORT
-        case MHD_OPTION_PROTOCOL_VERSION:
-          _set_priority (&retVal->priority_cache->protocol,
-                         va_arg (ap, const int *));
-          break;
-        case MHD_OPTION_HTTPS_MEM_KEY:
-          retVal->https_mem_key = va_arg (ap, const char *);
-          break;
-        case MHD_OPTION_HTTPS_MEM_CERT:
-          retVal->https_mem_cert = va_arg (ap, const char *);
-          break;
-        case MHD_OPTION_CIPHER_ALGORITHM:
-          _set_priority (&retVal->priority_cache->cipher,
-                         va_arg (ap, const int *));
-          break;
-#endif
-        case MHD_OPTION_EXTERNAL_LOGGER:
-#if HAVE_MESSAGES
-          retVal->custom_error_log =
-            va_arg (ap, VfprintfFunctionPointerType);
-          retVal->custom_error_log_cls = va_arg (ap, void *);
-#else
-          va_arg (ap, VfprintfFunctionPointerType);
-          va_arg (ap, void *);
-#endif
-          break;
-        default:
-#if HAVE_MESSAGES
-          if ((opt >= MHD_OPTION_HTTPS_MEM_KEY) &&
-              (opt <= MHD_OPTION_CIPHER_ALGORITHM))
-            {
-              FPRINTF (stderr,
-                       "MHD HTTPS option %d passed to MHD compiled without HTTPS support\n",
-                       opt);
-            }
-          else
-            {
-              FPRINTF (stderr,
-                       "Invalid option %d! (Did you terminate the list with MHD_OPTION_END?)\n",
-                       opt);
-            }
-#endif
-	  free (retVal);
-	  return NULL;
-        }
+      free (retVal);
+      return NULL;
     }
 
   /* poll support currently only works with MHD_USE_THREAD_PER_CONNECTION */

+ 50 - 1
src/include/microhttpd.h

@@ -453,9 +453,58 @@ enum MHD_OPTION
    * (MHD_start_daemon returns NULL for an unsupported thread
    * model).
    */
-  MHD_OPTION_THREAD_POOL_SIZE = 14
+  MHD_OPTION_THREAD_POOL_SIZE = 14,
+
+  /**
+   * Additional options given in an array of "struct MHD_OptionItem".
+   * The array must be terminated with an entry '{MHD_OPTION_END, 0, NULL}'.
+   * An example for code using MHD_OPTION_ARRAY is:
+   * <code>
+   * struct MHD_OptionItem ops[] = {
+   * { MHD_OPTION_CONNECTION_LIMIT, 100, NULL },
+   * { MHD_OPTION_CONNECTION_TIMEOUT, 10, NULL },
+   * { MHD_OPTION_END, 0, NULL }
+   * };
+   * d = MHD_start_daemon(0, 8080, NULL, NULL, dh, NULL,
+   *                      MHD_OPTION_ARRAY, ops,
+   *                      MHD_OPTION_END);
+   * </code>
+   * For options that expect a single pointer argument, the
+   * second member of the struct MHD_OptionItem is ignored.
+   * For options that expect two pointer arguments, the first
+   * argument must be cast to 'intptr_t'.
+   */
+  MHD_OPTION_ARRAY = 15
 };
 
+
+/**
+ * Entry in an MHD_OPTION_ARRAY.
+ */
+struct MHD_OptionItem
+{
+  /**
+   * Which option is being given.  Use MHD_OPTION_END
+   * to terminate the array.
+   */
+  enum MHD_OPTION option;
+
+  /**
+   * Option value (for integer arguments, and for options requiring
+   * two pointer arguments); should be 0 for options that take no
+   * arguments or only a single pointer argument.
+   */
+  intptr_t value;
+
+  /**
+   * Pointer option value (use NULL for options taking no arguments
+   * or only an integer option).
+   */
+  void *ptr_value;
+
+};
+
+
 /**
  * The MHD_ValueKind specifies the source of
  * the key-value pairs in the HTTP protocol.