An empty ":method" or ":scheme" is never valid, and an empty ":path" or
":authority" is not valid for the "http" and "https" schemes (RFC 9113
Section 8.3.1, RFC 9110 Section 4.2). An undefined pseudo-header makes
the request malformed (RFC 9113 Section 8.3). The library checked
neither and served the requests.

An empty ":method" was also undefined behaviour: its length is a
variable-length array bound in mhd_parse_http_method(), and UBSan
reports "variable length array bound evaluates to non-positive value 0".

The requests are now rejected, as an empty "content-length" is. The
library does not read the value of ":scheme", so the check applies to
every scheme.

Added test_h2_raw: the request must not reach the application, and any
RST_STREAM or GOAWAY must carry PROTOCOL_ERROR.
---
 src/mhd2/h2/h2_conn_streams.h     |   2 +
 src/mhd2/h2/h2_req_fields.c       |   6 +
 src/mhd2/stream_process_request.c |   2 +-
 src/mhd2/stream_process_request.h |   2 +-
 src/tests/raw/Makefile.am         |   5 +
 src/tests/raw/test_h2_raw.c       | 788 ++++++++++++++++++++++++++++++
 6 files changed, 803 insertions(+), 2 deletions(-)
 create mode 100644 src/tests/raw/test_h2_raw.c

diff --git a/src/mhd2/h2/h2_conn_streams.h b/src/mhd2/h2/h2_conn_streams.h
index 943d86b..8384000 100644
--- a/src/mhd2/h2/h2_conn_streams.h
+++ b/src/mhd2/h2/h2_conn_streams.h
@@ -79,6 +79,8 @@ enum mhd_H2RequestProblemType
   ,
   mhd_H2_REQ_PRBLM_PSEUDOHDR_EXTRA
   ,
+  mhd_H2_REQ_PRBLM_PSEUDOHDR_VALUE_WRONG
+  ,
   mhd_H2_REQ_PRBLM_FLOW_CONTROL
   ,

diff --git a/src/mhd2/h2/h2_req_fields.c b/src/mhd2/h2/h2_req_fields.c
index 38ad0d9..8107a31 100644
--- a/src/mhd2/h2/h2_req_fields.c
+++ b/src/mhd2/h2/h2_req_fields.c
@@ -222,6 +222,9 @@ req_pseudoheaders_preprocess (struct mhd_H2Stream
*restrict s,
       break;
     else if (mhd_H2_RIK_PSEUDOHEADER != item->kind)
       break;
+    else if (0u == item->val_len)
+      return mhd_h2_stream_req_problem (s,
+
mhd_H2_REQ_PRBLM_PSEUDOHDR_VALUE_WRONG);
     else if ((item->name_len == ph_method.len)
              && (0 == memcmp (buff + item->offset,
                               ph_method.cstr,
@@ -268,6 +271,9 @@ req_pseudoheaders_preprocess (struct mhd_H2Stream
*restrict s,
                                           mhd_H2_REQ_PRBLM_PSEUDOHDR_DUP);
       have_scheme = true;
     }
+    else
+      return mhd_h2_stream_req_problem (s,
+                                        mhd_H2_REQ_PRBLM_UNKNOWN_PSEUDOHDR);
     mhd_assert (':' == buff[item->offset]);
     ++(*pos);
   }
diff --git a/src/mhd2/stream_process_request.c
b/src/mhd2/stream_process_request.c
index 352c521..5d57ff3 100644
--- a/src/mhd2/stream_process_request.c
+++ b/src/mhd2/stream_process_request.c
@@ -481,7 +481,7 @@

 /**
  * Parse HTTP method string.
- * @param len the length of the @a mtd string
+ * @param len the length of the @a mtd string, must not be zero
  * @param mtd the method string, does not need to be zero-terminated
  * @return enum mhd_HTTP_Method value
  */
diff --git a/src/mhd2/stream_process_request.h
b/src/mhd2/stream_process_request.h
index 22b5eba..acbbc22 100644
--- a/src/mhd2/stream_process_request.h
+++ b/src/mhd2/stream_process_request.h
@@ -77,7 +77,7 @@ typedef bool

 /**
  * Parse HTTP method string.
- * @param len the length of the @a mtd string
+ * @param len the length of the @a mtd string, must not be zero
  * @param mtd the method string, does not need to be zero-terminated
  * @return enum mhd_HTTP_Method value
  */
diff --git a/src/tests/raw/Makefile.am b/src/tests/raw/Makefile.am
index 2d62fca..9f7bdae 100644
--- a/src/tests/raw/Makefile.am
+++ b/src/tests/raw/Makefile.am
@@ -30,4 +30,9 @@ check_PROGRAMS = \
   test_oom \
   test_raw

+if MHD_SUPPORT_HTTP2
+check_PROGRAMS += \
+  test_h2_raw
+endif
+
 TESTS = $(check_PROGRAMS)
diff --git a/src/tests/raw/test_h2_raw.c b/src/tests/raw/test_h2_raw.c
new file mode 100644
index 0000000..a5f1e49
--- /dev/null
+++ b/src/tests/raw/test_h2_raw.c
@@ -0,0 +1,788 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later
WITH eCos-exception-2.0) */
+/*
+  This file is part of GNU libmicrohttpd.
+  Copyright (C) 2025 Christian Grothoff
+  Copyright (C) 2026 Sami Jawhar
+
+  GNU libmicrohttpd is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  GNU 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
+  Lesser General Public License for more details.
+
+  Alternatively, you can redistribute GNU libmicrohttpd and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of
+  the License, or (at your option) any later version, together
+  with the eCos exception, as follows:
+
+    As a special exception, if other files instantiate templates or
+    use macros or inline functions from this file, or you compile this
+    file and link it with other works to produce a work based on this
+    file, this file does not by itself cause the resulting work to be
+    covered by the GNU General Public License. However the source code
+    for this file must still be made available in accordance with
+    section (3) of the GNU General Public License v2.
+
+    This exception does not invalidate any other reasons why a work
+    based on this file might be covered by the GNU General Public
+    License.
+
+  You should have received copies of the GNU Lesser General Public
+  License and the GNU General Public License along with this library;
+  if not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file test_h2_raw.c
+ * @brief tests HTTP/2 requests against server
+ * @author Sami Jawhar
+ */
+#include <stdio.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include "microhttpd2.h"
+
+
+/**
+ * The start of the connection preface sent by the client, RFC 9113,
+ * Section 3.4. It must be followed by a SETTINGS frame.
+ */
+#define H2_PREFACE "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
+
+/**
+ * The size of the frame header, RFC 9113, Section 4.1.
+ */
+#define H2_FRAME_HDR_SIZE 9
+
+/**
+ * The type of the HEADERS frame, RFC 9113, Section 6.2.
+ */
+#define H2_FRAME_HEADERS 0x1
+
+/**
+ * The type of the RST_STREAM frame, RFC 9113, Section 6.4.
+ */
+#define H2_FRAME_RST_STREAM 0x3
+
+/**
+ * The type of the SETTINGS frame, RFC 9113, Section 6.5.
+ */
+#define H2_FRAME_SETTINGS 0x4
+
+/**
+ * The type of the GOAWAY frame, RFC 9113, Section 6.8.
+ */
+#define H2_FRAME_GOAWAY 0x7
+
+/**
+ * The PROTOCOL_ERROR code, RFC 9113, Section 7.
+ */
+#define H2_ERR_PROTOCOL_ERROR 0x1
+
+/**
+ * The END_STREAM flag of the HEADERS frame, RFC 9113, Section 6.2.
+ */
+#define H2_FLAG_END_STREAM 0x1
+
+/**
+ * The END_HEADERS flag of the HEADERS frame, RFC 9113, Section 6.2.
+ */
+#define H2_FLAG_END_HEADERS 0x4
+
+/**
+ * Defines a test.
+ */
+struct Test
+{
+  /**
+   * Human-readable name of the test. NULL to end test array.
+   */
+  const char *name;
+
+  /**
+   * The value of the ":method" pseudo-header.
+   */
+  const char *method;
+
+  /**
+   * The value of the ":scheme" pseudo-header.
+   */
+  const char *scheme;
+
+  /**
+   * The value of the ":path" pseudo-header.
+   */
+  const char *path;
+
+  /**
+   * The value of the ":authority" pseudo-header.
+   */
+  const char *authority;
+
+  /**
+   * The name of an additional pseudo-header to send after the four
+   * above, NULL to send none.
+   */
+  const char *extra_name;
+
+  /**
+   * True if the server must give the request to the application,
+   * false if the server must reject the request.
+   */
+  bool expect_processed;
+};
+
+
+static const struct Test tests[] = {
+  {
+    .name = "Basic HTTP/2 GET",
+    .method = "GET",
+    .scheme = "http",
+    .path = "/",
+    .authority = "localhost",
+    .expect_processed = true,
+  },
+  {
+    /* RFC 9113, Section 8.3.1: exactly one valid value is required,
+       and an empty value is not a valid method, which is a token
+       (RFC 9110, Section 9.1) */
+    .name = "HTTP/2 GET with empty \":method\"",
+    .method = "",
+    .scheme = "http",
+    .path = "/",
+    .authority = "localhost",
+  },
+  {
+    /* RFC 3986, Section 3.1: a scheme starts with a letter */
+    .name = "HTTP/2 GET with empty \":scheme\"",
+    .method = "GET",
+    .scheme = "",
+    .path = "/",
+    .authority = "localhost",
+  },
+  {
+    /* RFC 9113, Section 8.3.1: ":path" must not be empty for
+       "http" and "https" URIs */
+    .name = "HTTP/2 GET with empty \":path\"",
+    .method = "GET",
+    .scheme = "http",
+    .path = "",
+    .authority = "localhost",
+  },
+  {
+    /* RFC 9110, Section 4.2.1: the host of an "http" URI
+       must not be empty */
+    .name = "HTTP/2 GET with empty \":authority\"",
+    .method = "GET",
+    .scheme = "http",
+    .path = "/",
+    .authority = "",
+  },
+  {
+    /* RFC 9113, Section 8.3: an undefined pseudo-header makes
+       the request malformed */
+    .name = "HTTP/2 GET with undefined pseudo-header",
+    .method = "GET",
+    .scheme = "http",
+    .path = "/",
+    .authority = "localhost",
+    .extra_name = ":forbidden",
+  },
+  {
+    .name = NULL,
+  }
+};
+
+
+/**
+ * True if the request has been given to the application.
+ * Set by a daemon thread, read by the main thread only after the reply
+ * has been received.
+ */
+static volatile bool processed;
+
+/**
+ * Our port.
+ */
+static uint16_t port;
+
+
+/**
+ * Records that the request reached the application and replies.
+ *
+ * @param cls closure
+ * @param request the request object
+ * @param path the requested uri
+ * @param method the HTTP method used
+ * @param upload_size the size of the upload content payload
+ * @return action how to proceed
+ */
+static const struct MHD_Action *
+server_req_cb (void *cls,
+               struct MHD_Request *MHD_RESTRICT request,
+               const struct MHD_String *MHD_RESTRICT path,
+               enum MHD_HTTP_Method method,
+               uint_fast64_t upload_size)
+{
+  (void)cls;          /* Unused */
+  (void)path;         /* Unused */
+  (void)method;       /* Unused */
+  (void)upload_size;  /* Unused */
+
+  processed = true;
+  return MHD_action_from_response (
+    request,
+    MHD_response_from_empty (MHD_HTTP_STATUS_NO_CONTENT));
+}
+
+
+/**
+ * Helper function to deal with partial writes.
+ * Fails hard (calls exit() on failures)!
+ *
+ * @param fd where to write to
+ * @param buf what to write
+ * @param buf_size number of bytes in @a buf
+ */
+static void
+write_all (int fd,
+           const void *buf,
+           size_t buf_size)
+{
+  const char *cbuf = buf;
+  size_t off;
+
+  off = 0;
+  while (off < buf_size)
+  {
+    ssize_t ret;
+
+    ret = write (fd,
+                 &cbuf[off],
+                 buf_size - off);
+    if (ret <= 0)
+    {
+      fprintf (stderr,
+               "Writing %u bytes to %d failed: %s\n",
+               (unsigned int)(buf_size - off),
+               fd,
+               strerror (errno));
+      exit (1);
+    }
+    off += ret;
+  }
+}
+
+
+/**
+ * Read the 24-bit value, RFC 9113, Section 4.1.
+ *
+ * @param buf the buffer to read from
+ * @return the value
+ */
+static size_t
+get_u24 (const unsigned char *buf)
+{
+  return (((size_t)buf[0]) << 16) | (((size_t)buf[1]) << 8)
+         | ((size_t)buf[2]);
+}
+
+
+/**
+ * Read the 32-bit value, RFC 9113, Section 2.2.
+ *
+ * @param buf the buffer to read from
+ * @return the value
+ */
+static uint32_t
+get_u32 (const unsigned char *buf)
+{
+  return (((uint32_t)buf[0]) << 24) | (((uint32_t)buf[1]) << 16)
+         | (((uint32_t)buf[2]) << 8) | ((uint32_t)buf[3]);
+}
+
+
+/**
+ * Write the 32-bit value, RFC 9113, Section 2.2.
+ *
+ * @param[out] buf the buffer to write to
+ * @param val the value to write
+ */
+static void
+put_u32 (unsigned char *buf,
+         uint32_t val)
+{
+  buf[0] = (unsigned char)(val >> 24);
+  buf[1] = (unsigned char)(val >> 16);
+  buf[2] = (unsigned char)(val >> 8);
+  buf[3] = (unsigned char)val;
+}
+
+
+/**
+ * Add the frame header, RFC 9113, Section 4.1.
+ *
+ * @param[out] buf the buffer to add the header to
+ * @param type the type of the frame
+ * @param flags the flags of the frame
+ * @param stream_id the stream identifier
+ * @param size the size of the frame payload
+ */
+static void
+put_frame_header (unsigned char buf[H2_FRAME_HDR_SIZE],
+                  unsigned char type,
+                  unsigned char flags,
+                  uint32_t stream_id,
+                  size_t size)
+{
+  buf[0] = (unsigned char)(size >> 16);
+  buf[1] = (unsigned char)(size >> 8);
+  buf[2] = (unsigned char)size;
+  buf[3] = type;
+  buf[4] = flags;
+  put_u32 (buf + 5,
+           stream_id);
+}
+
+
+/**
+ * Add a literal field with incremental indexing, RFC 7541, Section 6.2.1.
+ * The strings are not Huffman-coded.
+ * Fails hard (calls exit() on failures)!
+ * The one-byte forms are used, so @a index must be less than 63 and
+ * the length of @a name and of @a value must be less than 127
+ * (RFC 7541, Sections 5.1 and 5.2).
+ *
+ * @param[out] buf the buffer to add the field to
+ * @param index the index of the name in the static table, zero to add
+ *              @a name as a new name
+ * @param name the name of the field, used only if @a index is zero
+ * @param value the value of the field
+ * @return the number of bytes added
+ */
+static size_t
+put_field (unsigned char *buf,
+           unsigned char index,
+           const char *name,
+           const char *value)
+{
+  const size_t name_len = (0 == index) ? strlen (name) : 0;
+  const size_t value_len = strlen (value);
+  size_t pos = 1;
+
+  if ((63 <= index) || (127 <= name_len) || (127 <= value_len))
+  {
+    fprintf (stderr,
+             "The field with index %u cannot be encoded\n",
+             (unsigned int)index);
+    exit (1);
+  }
+  buf[0] = (unsigned char)(0x40u | index);
+  if (0 == index)
+  {
+    buf[pos++] = (unsigned char)name_len;
+    memcpy (buf + pos,
+            name,
+            name_len);
+    pos += name_len;
+  }
+  buf[pos++] = (unsigned char)value_len;
+  memcpy (buf + pos,
+          value,
+          value_len);
+  return pos + value_len;
+}
+
+
+/**
+ * Send the connection preface, the SETTINGS frame required to complete
+ * it, and the request of the test as a single HEADERS frame on stream 1.
+ *
+ * @param s the socket to send to
+ * @param t the test to send the request of
+ */
+static void
+send_request (int s,
+              const struct Test *t)
+{
+  /* Five fields, each within the limits of put_field(), plus the frame
+     header */
+  unsigned char buf[5 * 256 + H2_FRAME_HDR_SIZE];
+  size_t size;
+
+  write_all (s,
+             H2_PREFACE,
+             strlen (H2_PREFACE));
+  put_frame_header (buf,
+                    H2_FRAME_SETTINGS,
+                    0,
+                    0,
+                    0);
+  write_all (s,
+             buf,
+             H2_FRAME_HDR_SIZE);
+  size = put_field (buf + H2_FRAME_HDR_SIZE,
+                    2 /* ":method" */,
+                    NULL,
+                    t->method);
+  size += put_field (buf + H2_FRAME_HDR_SIZE + size,
+                     6 /* ":scheme" */,
+                     NULL,
+                     t->scheme);
+  size += put_field (buf + H2_FRAME_HDR_SIZE + size,
+                     4 /* ":path" */,
+                     NULL,
+                     t->path);
+  size += put_field (buf + H2_FRAME_HDR_SIZE + size,
+                     1 /* ":authority" */,
+                     NULL,
+                     t->authority);
+  if (NULL != t->extra_name)
+    size += put_field (buf + H2_FRAME_HDR_SIZE + size,
+                       0,
+                       t->extra_name,
+                       "value");
+  put_frame_header (buf,
+                    H2_FRAME_HEADERS,
+                    H2_FLAG_END_HEADERS | H2_FLAG_END_STREAM,
+                    1,
+                    size);
+  write_all (s,
+             buf,
+             H2_FRAME_HDR_SIZE + size);
+}
+
+
+/**
+ * A connection to our server and the data read from it.
+ */
+struct Conn
+{
+  /**
+   * The socket.
+   */
+  int s;
+
+  /**
+   * The data read: one frame of the largest size the client allows,
+   * RFC 9113, Section 4.2.
+   */
+  unsigned char buf[H2_FRAME_HDR_SIZE + 16384];
+
+  /**
+   * The number of bytes in @a buf.
+   */
+  size_t have;
+
+  /**
+   * The size of the frame at the start of @a buf that has been returned
+   * by read_frame(), zero if none.
+   */
+  size_t pos;
+};
+
+
+/**
+ * Open a connection to our server and set the receive timeout.
+ *
+ * @param[out] c the connection
+ * @return 0 if succeed, 1 if the connection cannot be made
+ */
+static int
+connect_to_server (struct Conn *c)
+{
+  int s;
+  struct sockaddr_in sa = {
+    .sin_family = AF_INET,
+    .sin_port = htons (port),
+  };
+  /* Must expire before the timeout of the daemon, so that a server that
+     does not answer fails the test instead of closing the connection */
+  struct timeval tv = {
+    .tv_sec = 5,
+  };
+
+  s = socket (AF_INET, SOCK_STREAM, 0);
+  if (-1 == s)
+  {
+    fprintf (stderr,
+             "socket() failed: %s\n",
+             strerror (errno));
+    return 1;
+  }
+  inet_pton (AF_INET,
+             "127.0.0.1",
+             &sa.sin_addr);
+  if (0 != connect (s,
+                    (struct sockaddr *)&sa,
+                    sizeof (sa)))
+  {
+    fprintf (stderr,
+             "connect() failed: %s\n",
+             strerror (errno));
+    close (s);
+    return 1;
+  }
+  if (0 != setsockopt (s,
+                       SOL_SOCKET,
+                       SO_RCVTIMEO,
+                       &tv,
+                       sizeof (tv)))
+  {
+    fprintf (stderr,
+             "setsockopt() failed: %s\n",
+             strerror (errno));
+    close (s);
+    return 1;
+  }
+  c->s = s;
+  c->have = 0;
+  c->pos = 0;
+  return 0;
+}
+
+
+/**
+ * Read the next complete frame. Its payload follows the frame header
+ * and stays in the buffer until the next call.
+ *
+ * @param c the connection to read from
+ * @return the frame header, NULL if the server closed the connection
+ *         (errno is zero) or the read failed
+ */
+static const unsigned char *
+read_frame (struct Conn *c)
+{
+  memmove (c->buf,
+           c->buf + c->pos,
+           c->have - c->pos);
+  c->have -= c->pos;
+  c->pos = 0;
+  while ((H2_FRAME_HDR_SIZE > c->have)
+         || (H2_FRAME_HDR_SIZE + get_u24 (c->buf) > c->have))
+  {
+    ssize_t ret;
+
+    if (sizeof (c->buf) == c->have)
+    {
+      errno = EMSGSIZE;
+      return NULL;
+    }
+    ret = read (c->s,
+                c->buf + c->have,
+                sizeof (c->buf) - c->have);
+    if (0 == ret)
+      errno = 0;
+    if (0 >= ret)
+    {
+      if (ECONNRESET == errno)
+        errno = 0;
+      return NULL;
+    }
+    c->have += (size_t)ret;
+  }
+  c->pos = H2_FRAME_HDR_SIZE + get_u24 (c->buf);
+  return c->buf;
+}
+
+
+/**
+ * Read the reply until the server answers the request on stream 1,
+ * resets stream 1, sends GOAWAY or closes the connection.
+ *
+ * @param c the connection to read from
+ * @param[out] answer set to the type of the frame that decided the request,
+ *                    zero if the server closed the connection without one
+ * @param[out] err_code set to the error code of RST_STREAM or GOAWAY
+ * @return 0 if succeed, 1 if the server did not answer in time or the
+ *         read failed
+ */
+static int
+read_reply (struct Conn *c,
+            unsigned char *answer,
+            uint32_t *err_code)
+{
+  const unsigned char *f;
+
+  *answer = 0;
+  *err_code = 0;
+  while (NULL != (f = read_frame (c)))
+  {
+    const size_t size = get_u24 (f);
+    const uint32_t stream_id = get_u32 (f + 5) & 0x7fffffffu;
+
+    if ((H2_FRAME_HEADERS == f[3]) && (1 == stream_id))
+    {
+      *answer = f[3];
+      return 0;
+    }
+    if ((H2_FRAME_RST_STREAM == f[3]) && (1 == stream_id)
+        && (4u <= size))
+    {
+      *answer = f[3];
+      *err_code = get_u32 (f + H2_FRAME_HDR_SIZE);
+      return 0;
+    }
+    if ((H2_FRAME_GOAWAY == f[3]) && (8u <= size))
+    {
+      *answer = f[3];
+      *err_code = get_u32 (f + H2_FRAME_HDR_SIZE + 4);
+      return 0;
+    }
+  }
+  if (0 == errno)
+    return 0;  /* The server closed the connection without a frame */
+  fprintf (stderr,
+           "The server sent no answer: %s\n",
+           strerror (errno));
+  return 1;
+}
+
+
+static int
+run_test (const struct Test *t)
+{
+  struct Conn c;
+  unsigned char answer;
+  uint32_t err_code;
+  bool was_processed;
+  int ret;
+
+  if (0 != connect_to_server (&c))
+    return 1;
+  processed = false;
+  send_request (c.s,
+                t);
+  ret = read_reply (&c,
+                    &answer,
+                    &err_code);
+  close (c.s);
+  if (0 != ret)
+    return ret;
+  was_processed = processed;
+  if (t->expect_processed != was_processed)
+  {
+    fprintf (stderr,
+             "The request has%s been given to the application\n",
+             was_processed ? "" : " not");
+    return 1;
+  }
+  if (!t->expect_processed)
+  {
+    /* A rejected request may get an error reply, RST_STREAM, GOAWAY or
+       a closed connection (RFC 9113, Sections 5.4.1 and 8.1.1): check
+       only the error code, if any. */
+    if ((0 != answer)
+        && (H2_FRAME_HEADERS != answer)
+        && (H2_ERR_PROTOCOL_ERROR != err_code))
+    {
+      fprintf (stderr,
+               "The server has used the error code %u, "
+               "expected PROTOCOL_ERROR\n",
+               (unsigned int)err_code);
+      return 1;
+    }
+  }
+  else if (H2_FRAME_HEADERS != answer)
+  {
+    fprintf (stderr,
+             "The server has not replied on the stream\n");
+    return 1;
+  }
+  return 0;
+}
+
+
+static int
+run_tests (void)
+{
+  for (unsigned int i = 0;
+       NULL != tests[i].name;
+       i++)
+  {
+    if (0 != run_test (&tests[i]))
+    {
+      fprintf (stderr,
+               "Test `%s' failed\n",
+               tests[i].name);
+      return 1;
+    }
+  }
+  return 0;
+}
+
+
+int
+main (void)
+{
+  struct MHD_Daemon *d;
+
+  d = MHD_daemon_create (&server_req_cb,
+                         NULL);
+  if (MHD_SC_OK !=
+      MHD_DAEMON_SET_OPTIONS (
+        d,
+        MHD_D_OPTION_WM_WORKER_THREADS (2),
+        MHD_D_OPTION_DEFAULT_TIMEOUT_MILSEC (30000),
+        MHD_D_OPTION_BIND_PORT (MHD_AF_AUTO,
+                                0)))
+  {
+    fprintf (stderr,
+             "Failed to configure daemon!\n");
+    MHD_daemon_destroy (d);
+    return 1;
+  }
+
+  {
+    enum MHD_StatusCode sc;
+
+    sc = MHD_daemon_start (d);
+    if (MHD_SC_OK != sc)
+    {
+      fprintf (stderr,
+               "Failed to start server: %u\n",
+               (unsigned int)sc);
+      MHD_daemon_destroy (d);
+      return 1;
+    }
+  }
+
+  {
+    union MHD_DaemonInfoFixedData info;
+    enum MHD_StatusCode sc;
+
+    sc = MHD_daemon_get_info_fixed (
+      d,
+      MHD_DAEMON_INFO_FIXED_BIND_PORT,
+      &info);
+    if (MHD_SC_OK != sc)
+    {
+      fprintf (stderr,
+               "Failed to determine our port: %u\n",
+               (unsigned int)sc);
+      MHD_daemon_destroy (d);
+      return 1;
+    }
+    port = info.v_bind_port_uint16;
+  }
+
+  {
+    int result;
+
+    result = run_tests ();
+    MHD_daemon_destroy (d);
+    return result;
+  }
+}
-- 
2.43.0

Reply via email to