You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2015/12/29 16:30:10 UTC

svn commit: r1722149 - in /httpd/test/mod_h2/trunk: ./ mh2fuzz/

Author: icing
Date: Tue Dec 29 15:30:09 2015
New Revision: 1722149

URL: http://svn.apache.org/viewvc?rev=1722149&view=rev
Log:
own http2 test client with multiple threads/connection/requests, using nghttp2+apr, tls+POST support lacking, fuzzing tests to be done

Added:
    httpd/test/mod_h2/trunk/mh2fuzz/   (with props)
    httpd/test/mod_h2/trunk/mh2fuzz/Makefile.am
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_conn.c
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_conn.h
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_feed.c
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_feed.h
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_request.c
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_request.h
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_session.c
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_session.h
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_stream.c
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_stream.h
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_util.c
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_util.h
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_worker.c
    httpd/test/mod_h2/trunk/mh2fuzz/h2c_worker.h
    httpd/test/mod_h2/trunk/mh2fuzz/mh2f_main.c
    httpd/test/mod_h2/trunk/mh2fuzz/mh2f_main.h
    httpd/test/mod_h2/trunk/mh2fuzz/mh2f_version.h
    httpd/test/mod_h2/trunk/mh2fuzz/mh2f_version.h.in
Modified:
    httpd/test/mod_h2/trunk/   (props changed)
    httpd/test/mod_h2/trunk/Makefile.am
    httpd/test/mod_h2/trunk/configure.ac

Propchange: httpd/test/mod_h2/trunk/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Tue Dec 29 15:30:09 2015
@@ -12,6 +12,7 @@ install-sh
 libtool
 ltmain.sh
 missing
+depcomp
 
 gen
 

Modified: httpd/test/mod_h2/trunk/Makefile.am
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/Makefile.am?rev=1722149&r1=1722148&r2=1722149&view=diff
==============================================================================
--- httpd/test/mod_h2/trunk/Makefile.am (original)
+++ httpd/test/mod_h2/trunk/Makefile.am Tue Dec 29 15:30:09 2015
@@ -13,7 +13,7 @@
 # limitations under the License.
 #
 SUBDIRS         = @BUILD_SUBDIRS@
-DIST_SUBDIRS    = nghttp2 test clients bin conf htdocs
+DIST_SUBDIRS    = nghttp2 test clients bin conf htdocs mh2fuzz
 
 ACLOCAL_AMFLAGS = -I m4
 
@@ -102,7 +102,10 @@ install-nghttp2:
 install-client: 
 	@make -C clients install
 
-install: @INSTALL_DEP@
+install-mh2fuzz: 
+	@make -C mh2fuzz install
+
+install: install-mh2fuzz @INSTALL_DEP@
 
 ################################################################################
 # Test the local httpd

Modified: httpd/test/mod_h2/trunk/configure.ac
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/configure.ac?rev=1722149&r1=1722148&r2=1722149&view=diff
==============================================================================
--- httpd/test/mod_h2/trunk/configure.ac (original)
+++ httpd/test/mod_h2/trunk/configure.ac Tue Dec 29 15:30:09 2015
@@ -14,7 +14,7 @@
 #
 
 AC_PREREQ([2.67])
-AC_INIT([mod_h2_test], [0.0.2], [stefan.eissing@greenbytes.de])
+AC_INIT([mod_h2_test], [1.0.15-DEV], [stefan.eissing@greenbytes.de])
 
 LT_PREREQ([2.2.6])
 LT_INIT()
@@ -59,7 +59,7 @@ AC_ARG_WITH([nghttp2-version], [AS_HELP_
     [NGHTTP2_VERSION_EXACT=$withval], [NGHTTP2_VERSION_EXACT=])
 
 
-export BUILD_SUBDIRS="clients"
+export BUILD_SUBDIRS="clients mh2fuzz"
 
 AC_MSG_NOTICE("configuring build")
 
@@ -92,7 +92,8 @@ if test -x "${APXS}"; then
     APACHECTL="$ap_bindir/apachectl"
     HTTPD="$ap_bindir/httpd"
 
-    LDFLAGS="$LDFLAGS -L$($APXS -q libdir)"
+    LIB_DIR="$($APXS -q libdir)"
+    LDFLAGS="$LDFLAGS -L$LIB_DIR"
     CPPFLAGS="$CPPFLAGS -I$($APXS -q includedir) -I$($APXS -q APR_INCLUDEDIR)"
     export SYSCONF_DIR="$($APXS -q sysconfdir)"
     export LIBEXEC_DIR="$($APXS -q LIBEXECDIR)"
@@ -107,7 +108,8 @@ else
     APACHECTL="${ap_bindir}/apachectl"
     HTTPD="${ap_bindir}/httpd"
 
-    LDFLAGS="$LDFLAGS -L${ap_prefix}/lib"
+    LIB_DIR="${ap_prefix}/lib"
+    LDFLAGS="$LDFLAGS -L$LIB_DIR"
     CPPFLAGS="$CPPFLAGS -I${ap_prefix}/include"
     export SYSCONF_DIR="${ap_prefix}/conf"
     export LIBEXEC_DIR="$MODULES"
@@ -330,6 +332,7 @@ fi
 # substitution in generated files
 AC_SUBST(BUILD_SUBDIRS)
 AC_SUBST(SYSCONF_DIR)
+AC_SUBST(LIB_DIR)
 AC_SUBST(LIBEXEC_DIR)
 AC_SUBST(SERVER_NAME)
 AC_SUBST(ABS_PWD)
@@ -359,6 +362,8 @@ AC_CONFIG_FILES([
     Makefile
     nghttp2/Makefile
     clients/Makefile
+    mh2fuzz/Makefile
+    mh2fuzz/mh2f_version.h
 ])
 
 AC_OUTPUT

Propchange: httpd/test/mod_h2/trunk/mh2fuzz/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Dec 29 15:30:09 2015
@@ -0,0 +1,4 @@
+mh2fuzz
+Makefile
+Makefile.in
+.deps

Added: httpd/test/mod_h2/trunk/mh2fuzz/Makefile.am
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/Makefile.am?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/Makefile.am (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/Makefile.am Tue Dec 29 15:30:09 2015
@@ -0,0 +1,33 @@
+# Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+ACLOCAL_AMFLAGS = -I m4
+
+AUTOMAKE_OPTIONS = foreign
+
+CFLAGS= -g
+LDFLAGS=-L@LIB_DIR@ -lapr-1 -laprutil-1
+
+bin_PROGRAMS = mh2fuzz
+
+mh2fuzz_SOURCES = \
+    mh2f_main.c \
+    h2c_conn.c \
+    h2c_feed.c \
+    h2c_request.c \
+    h2c_util.c \
+    h2c_session.c \
+    h2c_stream.c \
+    h2c_worker.c

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_conn.c
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_conn.c?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_conn.c (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_conn.c Tue Dec 29 15:30:09 2015
@@ -0,0 +1,220 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr.h>
+#include <apr_strings.h>
+#include <apr_poll.h>
+#include <apr_uri.h>
+
+#include <nghttp2/nghttp2.h>
+
+#include "h2c_conn.h"
+#include "h2c_util.h"
+
+static long cid;
+
+static apr_size_t BUF_SIZE = 16 * 1024;
+
+static apr_status_t read_plain(h2c_conn *c)
+{
+    char buffer[16*1024];
+    apr_size_t len = H2_DIM(buffer);
+    apr_status_t status;
+    
+    status = apr_socket_recv(c->socket, buffer, &len);
+    if (len > 0) {
+        apr_status_t s2 = h2c_conn_on_read(c, buffer, len);
+        if (status == APR_SUCCESS) {
+            status = s2;
+        }
+    }
+    return status;
+}
+
+static apr_status_t write_plain(h2c_conn *c)
+{
+    apr_status_t status = APR_SUCCESS;
+    if (c->buf_len > 0) {
+        apr_size_t len = c->buf_len;
+        status = apr_socket_send(c->socket, c->buffer + c->buf_head, &len);
+        if (len > 0) {
+            c->buf_head += len;
+            c->buf_len -= len;
+        }
+    }
+    return status;
+}
+
+apr_status_t h2c_conn_create(h2c_conn **pc, apr_pool_t *parent, apr_uri_t *uri)
+{
+    apr_pool_t *p;
+    apr_status_t status;
+    apr_sockaddr_t *addr;
+    char *ip;
+    h2c_conn *c;
+    
+    status = apr_pool_create(&p, parent);
+    if (status != APR_SUCCESS) {
+        return status;
+    }
+    
+    c = apr_pcalloc(p, sizeof(*c));
+    
+    c->id       = cid++;
+    c->pool     = p;
+    c->uri      = uri;
+    c->authority = apr_psprintf(p, "%s:%d", uri->hostname, uri->port);
+    c->read     = read_plain;
+    c->write    = write_plain;
+    
+    c->buf_size = BUF_SIZE;
+    c->buffer   = apr_pcalloc(p, c->buf_size);
+    c->buf_head = 0;
+    c->buf_len  = 0;
+    
+    status = apr_sockaddr_info_get(&c->addr, uri->hostname, APR_UNSPEC, 
+                                   uri->port, 0, p);
+    if (status != APR_SUCCESS) {
+        return status;
+    }
+    
+    apr_sockaddr_ip_get(&ip, c->addr);
+    c->ip_addr = ip;
+    
+    status = apr_socket_create(&c->socket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, p);
+    if (status != APR_SUCCESS) {
+        return status;
+    }
+    
+    c->pfd = apr_pcalloc(p, sizeof *c->pfd);
+    c->pfd->desc_type   = APR_POLL_SOCKET;
+    c->pfd->desc.s      = c->socket;
+    c->pfd->reqevents   = APR_POLLIN|APR_POLLOUT;
+    c->pfd->client_data = c;
+
+    *pc = c;
+    
+    return APR_SUCCESS;
+}
+
+void h2c_conn_destroy(h2c_conn *c)
+{
+    if (c->pool) {
+        apr_pool_destroy(c->pool);
+    }
+}
+
+void h2c_conn_want_io(h2c_conn *c, int flags)
+{
+    int pf = 0;
+    if (flags & H2C_CONN_READ) {
+        pf |= APR_POLLIN;
+    }
+    if (flags & H2C_CONN_WRITE) {
+        pf |= APR_POLLOUT;
+    }
+    c->pfd->reqevents = pf;
+}
+
+apr_status_t h2c_conn_on_connect(h2c_conn *c)
+{
+    if (c->on_connect) {
+        return c->on_connect(c, c->cb_ctx);
+    }
+    return APR_SUCCESS;
+}
+
+apr_status_t h2c_conn_on_read(h2c_conn *c, const char *data, apr_size_t len)
+{
+    if (c->on_read) {
+        return c->on_read(c, data, len, c->cb_ctx);
+    }
+    return APR_SUCCESS;
+}
+
+apr_status_t h2c_conn_on_write(h2c_conn *c)
+{
+    if (c->on_write) {
+        return c->on_write(c, c->cb_ctx);
+    }
+    return APR_SUCCESS;
+}
+
+void h2c_conn_set_callback(h2c_conn *c, 
+                           h2c_conn_on_connect_cb *on_connect, 
+                           h2c_conn_on_read_cb *on_read, 
+                           h2c_conn_on_write_cb *on_write, 
+                           h2c_conn_before_close *before_close,
+                           void *ctx)
+{
+    c->on_connect = on_connect;
+    c->on_read = on_read;
+    c->on_write = on_write;
+    c->before_close = before_close;
+    c->cb_ctx = ctx;    
+}
+
+apr_status_t h2c_conn_read(h2c_conn *c)
+{
+    if (!c->socket) {
+        return APR_EOF;
+    }
+    return c->read(c);
+}
+
+apr_status_t h2c_conn_write(h2c_conn *c)
+{
+    if (!c->socket) {
+        return APR_EOF;
+    }
+    return c->write(c);
+}
+
+apr_status_t h2c_conn_close(h2c_conn *c)
+{
+    apr_status_t status = APR_SUCCESS;
+    
+    if (c->socket) {
+        if (c->before_close) {
+            c->before_close(c, c->cb_ctx);
+        }
+        status = apr_socket_close(c->socket);
+        c->socket = NULL;
+    }
+    return status;
+}
+
+int h2c_conn_wbuf_empty(h2c_conn *c)
+{
+    return c->buf_len == 0;
+}
+
+apr_size_t h2c_conn_wbuf_left(h2c_conn *c)
+{
+    return c->buf_size - (c->buf_head + c->buf_len);
+}
+
+apr_size_t h2c_conn_wbuf_append(h2c_conn *c, const char *data, apr_size_t len)
+{
+    len = H2_MIN(h2c_conn_wbuf_left(c), len);
+    if (len > 0) {
+        if (c->buf_head && c->buf_len == 0) {
+            c->buf_head = 0;
+        }
+        memcpy(c->buffer + c->buf_head + c->buf_len, data, len);
+        c->buf_len += len;
+    }
+    return len;
+}

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_conn.h
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_conn.h?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_conn.h (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_conn.h Tue Dec 29 15:30:09 2015
@@ -0,0 +1,83 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef h2c_conn_h
+#define h2c_conn_h
+
+struct apr_pollfd_t;
+
+typedef struct h2c_conn h2c_conn;
+
+typedef apr_status_t h2c_conn_on_connect_cb(h2c_conn *c, void *ctx);
+typedef apr_status_t h2c_conn_on_read_cb(h2c_conn *c, const char *data, apr_size_t len, void *ctx);
+typedef apr_status_t h2c_conn_on_write_cb(h2c_conn *c, void *ctx);
+typedef apr_status_t h2c_conn_before_close(h2c_conn *c, void *ctx);
+typedef apr_status_t h2c_conn_action(h2c_conn *c);
+
+#define H2C_CONN_READ   0x01
+#define H2C_CONN_WRITE  0x04
+
+struct h2c_conn {
+    long                   id;
+    apr_pool_t             *pool;
+    apr_uri_t              *uri;
+    struct apr_pollfd_t    *pfd;
+    const char             *authority;
+    apr_sockaddr_t         *addr;
+    const char             *ip_addr;
+    apr_socket_t           *socket;
+    
+    h2c_conn_action        *read;
+    h2c_conn_action        *write;
+    
+    char                   *buffer;
+    apr_size_t             buf_size;
+    apr_size_t             buf_head;
+    apr_size_t             buf_len;
+    
+    void                   *cb_ctx;
+    h2c_conn_on_connect_cb *on_connect;
+    h2c_conn_on_read_cb    *on_read;
+    h2c_conn_on_write_cb   *on_write;
+    h2c_conn_before_close  *before_close;
+};
+
+apr_status_t h2c_conn_create(h2c_conn **pc, apr_pool_t *parent, apr_uri_t *uri);
+
+void h2c_conn_destroy(h2c_conn *c);
+
+void h2c_conn_set_callback(h2c_conn *c, 
+                           h2c_conn_on_connect_cb *on_connect, 
+                           h2c_conn_on_read_cb *on_read, 
+                           h2c_conn_on_write_cb *on_write, 
+                           h2c_conn_before_close *before_close,
+                           void *ctx);
+
+apr_status_t h2c_conn_on_connect(h2c_conn *c);
+apr_status_t h2c_conn_on_read(h2c_conn *c, const char *data, apr_size_t len);
+apr_status_t h2c_conn_on_write(h2c_conn *c);
+
+void h2c_conn_want_io(h2c_conn *c, int flags);
+
+apr_status_t h2c_conn_read(h2c_conn *c);
+apr_status_t h2c_conn_write(h2c_conn *c);
+
+apr_status_t h2c_conn_close(h2c_conn *c);
+
+apr_size_t h2c_conn_wbuf_left(h2c_conn *c);
+int h2c_conn_wbuf_empty(h2c_conn *c);
+
+apr_size_t h2c_conn_wbuf_append(h2c_conn *c, const char *data, apr_size_t len);
+
+#endif /* h2c_conn_h */

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_feed.c
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_feed.c?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_feed.c (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_feed.c Tue Dec 29 15:30:09 2015
@@ -0,0 +1,53 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr.h>
+#include <apr_strings.h>
+#include <apr_uri.h>
+
+#include "h2c_request.h"
+#include "h2c_session.h"
+#include "h2c_feed.h"
+
+static apr_status_t repeat_next(h2c_request **pr, h2c_feed *feed, h2c_session *s)
+{
+    if (feed->x.repeat.n > 0) {
+        --feed->x.repeat.n;
+        *pr = feed->x.repeat.r;
+        return APR_SUCCESS;
+    }
+    else {
+        return APR_EOF;
+    }
+}
+
+apr_status_t h2c_feed_repeat_create(h2c_feed **pf, apr_pool_t *p, 
+                                    struct h2c_request *r, int n)
+{
+    h2c_feed *f;
+    
+    f = apr_pcalloc(p, sizeof(*f));
+    f->x.repeat.n = n;
+    f->x.repeat.r = r;
+    f->next_fn = repeat_next;
+    
+    *pf = f;
+    return APR_SUCCESS;
+}
+
+apr_status_t h2c_feed_next(h2c_request **pr, h2c_feed *feed, h2c_session *s)
+{
+    return feed->next_fn(pr, feed, s);
+}

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_feed.h
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_feed.h?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_feed.h (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_feed.h Tue Dec 29 15:30:09 2015
@@ -0,0 +1,44 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef h2c_feed_h
+#define h2c_feed_h
+
+struct h2c_request;
+struct h2c_session;
+
+typedef struct h2c_feed h2c_feed;
+
+typedef apr_status_t h2c_feed_next_fn(struct h2c_request **pr, h2c_feed *feed, 
+                                      struct h2c_session *s);
+
+typedef struct h2c_feed_repeat {
+    int n;
+    struct h2c_request *r;
+} h2c_feed_repeat;
+
+struct h2c_feed {
+    union {
+        h2c_feed_repeat repeat;
+    } x;
+    h2c_feed_next_fn *next_fn;
+};
+
+apr_status_t h2c_feed_repeat_create(h2c_feed **pf, apr_pool_t *p, 
+                                    struct h2c_request *r, int n);
+
+apr_status_t h2c_feed_next(struct h2c_request **pr, h2c_feed *feed, 
+                           struct h2c_session *s);
+
+#endif /* h2c_feed_h */

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_request.c
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_request.c?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_request.c (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_request.c Tue Dec 29 15:30:09 2015
@@ -0,0 +1,47 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr.h>
+#include <apr_strings.h>
+#include <apr_uri.h>
+
+#include "h2c_request.h"
+
+apr_status_t h2c_request_create(h2c_request **pr, apr_pool_t *p,
+                                const char *method, apr_uri_t *uri)
+{
+    h2c_request *r;
+    
+    r = apr_pcalloc(p, sizeof(*r));
+    
+    r->scheme    = uri->scheme;
+    r->method    = method;
+    if (uri->port != apr_uri_port_of_scheme(uri->scheme)) {
+        r->authority = apr_psprintf(p, "%s:%d", uri->hostname, uri->port);
+    }
+    else {
+       r->authority = uri->hostname;
+    }
+    r->path      = apr_uri_unparse(p, uri, APR_URI_UNP_OMITSITEPART);
+    r->headers   = apr_table_make(p, 5);
+    
+    *pr = r;
+    return APR_SUCCESS;
+}
+
+void h2c_request_headers_set(h2c_request *r, const char *name, const char *val)
+{
+    apr_table_set(r->headers, name, val);
+}

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_request.h
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_request.h?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_request.h (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_request.h Tue Dec 29 15:30:09 2015
@@ -0,0 +1,36 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef h2c_request_h
+#define h2c_request_h
+
+struct apr_table_t;
+
+typedef struct h2c_request h2c_request;
+
+struct h2c_request {
+    const char *method;
+    const char *scheme;
+    const char *authority;
+    const char *path;
+    
+    struct apr_table_t *headers;
+};
+
+apr_status_t h2c_request_create(h2c_request **pr, apr_pool_t *p,
+                                const char *method, apr_uri_t *uri);
+
+void h2c_request_headers_set(h2c_request *r, const char *name, const char *val);
+
+#endif /* h2c_request_h */

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_session.c
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_session.c?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_session.c (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_session.c Tue Dec 29 15:30:09 2015
@@ -0,0 +1,399 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr.h>
+#include <apr_uri.h>
+
+#include <nghttp2/nghttp2.h>
+
+#include "h2c_conn.h"
+#include "h2c_feed.h"
+#include "h2c_request.h"
+#include "h2c_session.h"
+#include "h2c_stream.h"
+#include "h2c_util.h"
+
+static apr_status_t on_conn_connect(h2c_conn *c, void *ctx);
+static apr_status_t on_conn_read(h2c_conn *c, const char *data, size_t len, void *ctx);
+static apr_status_t on_conn_write(h2c_conn *c, void *ctx);
+static apr_status_t on_conn_close(h2c_conn *c, void *ctx);
+
+apr_status_t h2c_session_create(h2c_session **ps, h2c_conn *c, int max_streams)
+{
+    apr_pool_t *p;
+    apr_status_t status;
+    h2c_session *s;
+    
+    s = apr_pcalloc(c->pool, sizeof(h2c_session));
+    
+    s->c                      = c;
+    s->state                  = H2C_SESSION_ST_INIT;
+    s->output                 = stdout;
+    s->window_bits_default    = 30;
+    s->window_bits_connection = 30;
+
+    s->max_streams            = max_streams;
+    
+    h2c_conn_set_callback(c, on_conn_connect, on_conn_read, on_conn_write, 
+                          on_conn_close, s);
+    *ps = s;
+    
+    return APR_SUCCESS;
+}
+
+apr_status_t h2c_session_close(h2c_session *s)
+{
+    if (!s->closed) {
+        if (!s->goaway_recvd) {
+            nghttp2_submit_goaway(s->ngh2, NGHTTP2_FLAG_NONE, 
+                                  s->max_stream_recv, 0, NULL, 0);
+            nghttp2_session_send(s->ngh2);
+        }
+        s->closed = 1;
+    }
+    return APR_SUCCESS;
+}
+
+void h2c_session_verbose_set(h2c_session *s, int verbose)
+{
+    s->verbose = verbose;
+}
+
+static ssize_t raw_send(nghttp2_session *session, const uint8_t *data,
+                        size_t length, int flags, void *user_data)
+{
+    h2c_session *s = user_data;
+
+    if (h2c_conn_wbuf_left(s->c) == 0) {
+        return NGHTTP2_ERR_WOULDBLOCK;
+    }
+    return h2c_conn_wbuf_append(s->c, (const char*)data, length);
+}
+
+static void log_frame(h2c_session *s, const char *msg, const nghttp2_frame *frame)
+{
+    char scratch[128];
+    size_t s_len = sizeof(scratch)/sizeof(scratch[0]);
+    size_t len;
+    
+    switch (frame->hd.type) {
+        case NGHTTP2_DATA:
+            fprintf(stderr, "%ld: %s DATA[length=%d, flags=%d, stream=%d, padlen=%d]\n",
+                    s->c->id, msg, (int)frame->hd.length, frame->hd.flags,
+                    frame->hd.stream_id, (int)frame->data.padlen);
+            break;
+            
+        case NGHTTP2_HEADERS:
+            fprintf(stderr, "%ld: %s HEADERS[length=%d, hend=%d, stream=%d, eos=%d]\n",
+                    s->c->id, msg, (int)frame->hd.length,
+                    !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS),
+                    frame->hd.stream_id,
+                    !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM));
+            break;
+        case NGHTTP2_PRIORITY:
+            fprintf(stderr, "%ld: %s PRIORITY[length=%d, flags=%d, stream=%d]\n",
+                    s->c->id, msg, (int)frame->hd.length,
+                    frame->hd.flags, frame->hd.stream_id);
+            break;
+        case NGHTTP2_RST_STREAM:
+            fprintf(stderr, "%ld: %s RST_STREAM[length=%d, flags=%d, stream=%d]\n",
+                    s->c->id, msg, (int)frame->hd.length,
+                    frame->hd.flags, frame->hd.stream_id);
+            break;
+        case NGHTTP2_SETTINGS:
+            if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
+                fprintf(stderr, "%ld: %s SETTINGS[ack=1, stream=%d]\n",
+                        s->c->id, msg, frame->hd.stream_id);
+                return;
+            }
+            fprintf(stderr, "%ld: %s SETTINGS[length=%d, stream=%d]\n",
+                    s->c->id, msg, (int)frame->hd.length, frame->hd.stream_id);
+            break;
+        case NGHTTP2_PUSH_PROMISE:
+            fprintf(stderr, "%ld: %s PUSH_PROMISE[length=%d, hend=%d, stream=%d]\n",
+                    s->c->id, msg, (int)frame->hd.length,
+                    !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS),
+                    frame->hd.stream_id);
+            break;
+        case NGHTTP2_PING:
+            fprintf(stderr, "%ld: %s PING[length=%d, ack=%d, stream=%d]\n",
+                    s->c->id, msg, (int)frame->hd.length,
+                    frame->hd.flags&NGHTTP2_FLAG_ACK,
+                    frame->hd.stream_id);
+            break;
+        case NGHTTP2_GOAWAY:
+            len = ((frame->goaway.opaque_data_len < s_len)?
+                   frame->goaway.opaque_data_len : s_len-1);
+            memcpy(scratch, frame->goaway.opaque_data, len);
+            scratch[len+1] = '\0';
+            fprintf(stderr, "%ld: %s GOAWAY[error=%d, reason='%s']\n",
+                    s->c->id, msg, frame->goaway.error_code, scratch);
+            break;
+        case NGHTTP2_WINDOW_UPDATE:
+            fprintf(stderr, "%ld: %s WINDOW_UPDATE[length=%d, stream=%d]\n",
+                    s->c->id, msg, (int)frame->hd.length, frame->hd.stream_id);
+            break;
+        default:
+            fprintf(stderr, "%ld: %s type=%d[length=%d, flags=%d, stream=%d]\n",
+                    s->c->id, msg, frame->hd.type, (int)frame->hd.length,
+                    frame->hd.flags, frame->hd.stream_id);
+            break;
+    }
+}
+
+static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
+                         void *user_data) 
+{
+    h2c_session *s = user_data;
+    
+    if (s->verbose > 0) {
+        log_frame(s, "recv", frame);
+    }
+    switch (frame->hd.type) {
+        case NGHTTP2_GOAWAY:
+            s->goaway_recvd = 1;
+            h2c_session_close(s);
+            break;
+        default:
+            break;
+    }
+    return 0;
+}
+
+static int before_frame_send(nghttp2_session *session,
+                             const nghttp2_frame *frame, void *user_data)
+{
+    h2c_session *s = user_data;
+    
+    if (s->verbose > 0) {
+        log_frame(s, "send", frame);
+    }
+    return 0;
+}
+
+static int on_data_chunk_recv(nghttp2_session *ngh2, uint8_t flags,
+                              int32_t stream_id, const uint8_t *data,
+                              size_t len, void *user_data) 
+{
+    h2c_session *s = user_data;
+    h2c_stream *stream = nghttp2_session_get_stream_user_data(ngh2, stream_id);
+
+    nghttp2_session_consume(ngh2, stream_id, len);
+
+    if (!stream) {
+        fprintf(stderr, "stream %d not found", stream_id);
+        return 0;
+    }
+    
+    h2c_stream_resp_append(stream, (const char *)data, len);
+    return 0;
+}
+
+static int on_stream_close(nghttp2_session *ngh2, int32_t stream_id,
+                           uint32_t error_code, void *user_data) 
+{
+    h2c_session *s = user_data;
+    h2c_stream *stream;
+    
+    if (s->verbose > 0) {
+        fprintf(stderr, "closed STREAM[%d]\n", stream_id);
+    }
+    
+    --s->open_streams;
+    if (!s->closed && s->open_streams <= 0) {
+        s->state = H2C_SESSION_ST_IDLE;
+    }
+    
+    stream = nghttp2_session_get_stream_user_data(ngh2, stream_id);
+    if (!stream) {
+        fprintf(stderr, "stream %d not found", stream_id);
+        return 0;
+    }
+    
+    h2c_stream_close(stream);
+    
+    return 0;
+}
+
+static int on_header(nghttp2_session *ngh2, const nghttp2_frame *frame,
+                     const uint8_t *name, size_t namelen,
+                     const uint8_t *value, size_t valuelen, uint8_t flags,
+                     void *user_data) 
+{
+    h2c_session *s = user_data;
+    h2c_stream *stream = nghttp2_session_get_stream_user_data(ngh2, frame->hd.stream_id);
+    
+    if (!stream) {
+        fprintf(stderr, "stream %d not found", frame->hd.stream_id);
+        return 0;
+    }
+    h2c_stream_resp_add(stream, (const char *)name, namelen, 
+                        (const char *)value, valuelen);
+    
+    return 0;
+}
+
+static apr_status_t check_io_sense(h2c_session *s, apr_status_t status)
+{
+    int io_sense = 0;
+
+    if (s->feed && s->max_streams > s->open_streams) {
+        h2c_request *r;
+        
+        status = h2c_feed_next(&r, s->feed, s);
+        if (status == APR_SUCCESS) {
+            status = h2c_session_submit(s, r, NULL);
+        }
+        else if (APR_STATUS_IS_EOF(status) && s->state == H2C_SESSION_ST_IDLE) {
+            h2c_session_close(s);
+        }
+    }
+
+    if (nghttp2_session_want_read(s->ngh2)) {
+        io_sense |= H2C_CONN_READ;
+    }
+    if (nghttp2_session_want_write(s->ngh2) || !h2c_conn_wbuf_empty(s->c)) {
+        io_sense |= H2C_CONN_WRITE;
+    }
+    if (!io_sense) {
+        return APR_EOF;
+    }
+    
+    h2c_conn_want_io(s->c, io_sense);
+    return status;
+}
+
+static apr_status_t on_conn_read(h2c_conn *c, const char *data, size_t len, void *ctx)
+{
+    h2c_session *s = ctx;
+    
+    ssize_t rv = nghttp2_session_mem_recv(s->ngh2, (const uint8_t*)data, len);
+    if (rv < 0) {
+        return APR_ECONNRESET;
+    }
+    
+    return check_io_sense(s, APR_SUCCESS);
+}
+
+static apr_status_t on_conn_write(h2c_conn *c, void *ctx)
+{
+    h2c_session *s = ctx;
+    apr_status_t status = APR_SUCCESS;
+    int rv = nghttp2_session_send(s->ngh2);
+    
+    if (rv != 0) {
+        return APR_ECONNRESET;
+    }
+    
+    return check_io_sense(s, status);
+}
+
+static apr_status_t on_conn_connect(h2c_conn *c, void *ctx)
+{
+    h2c_session *s = ctx;
+    nghttp2_session_callbacks *cbs;
+    nghttp2_settings_entry settings[2];
+    int add_conn_window;
+    int rv;
+
+    nghttp2_session_callbacks_new(&cbs);
+    
+    nghttp2_session_callbacks_set_on_frame_recv_callback(cbs, on_frame_recv);
+    nghttp2_session_callbacks_set_on_data_chunk_recv_callback(cbs, on_data_chunk_recv);
+    nghttp2_session_callbacks_set_on_stream_close_callback(cbs, on_stream_close);
+    nghttp2_session_callbacks_set_on_header_callback(cbs, on_header);
+    nghttp2_session_callbacks_set_before_frame_send_callback(cbs, before_frame_send);
+    nghttp2_session_callbacks_set_send_callback(cbs, raw_send);
+    
+    nghttp2_session_client_new(&s->ngh2, cbs, s);
+    
+    nghttp2_session_callbacks_del(cbs);
+
+    settings[0].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
+    settings[0].value = 0;
+    settings[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
+    settings[1].value = (1 << s->window_bits_default) - 1;
+    
+    rv = nghttp2_submit_settings(s->ngh2, NGHTTP2_FLAG_NONE, settings, H2_DIM(settings));
+
+    /* If the connection window is larger than our default, trigger a WINDOW_UPDATE */
+    add_conn_window = ((1 << s->window_bits_connection) - 1 -
+                   NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE);
+    if (!rv && add_conn_window != 0) {
+        rv = nghttp2_submit_window_update(s->ngh2, NGHTTP2_FLAG_NONE, 0, add_conn_window);
+    }
+
+    s->state = H2C_SESSION_ST_IDLE;
+    
+    h2c_conn_want_io(c, H2C_CONN_READ|H2C_CONN_WRITE);
+    return rv? APR_EGENERAL : APR_SUCCESS;
+}
+
+static apr_status_t on_conn_close(h2c_conn *c, void *ctx)
+{
+    return h2c_session_close(ctx);
+}
+
+
+apr_status_t h2c_session_submit(h2c_session *s, struct h2c_request *r, int *pid)
+{
+    nghttp2_nv *nva;
+    size_t nvlen = 0;
+    h2c_ngheader *ngh;
+    h2c_stream *stream;
+    int stream_id;
+    apr_status_t status;
+    
+    if (s->closed) {
+        return APR_EOF;
+    }
+    
+    if (s->open_streams >= s->max_streams) {
+        return APR_EAGAIN;
+    }
+    
+    status = h2c_stream_create(&stream, s->c->pool, s, r, s->output);
+    if (status != APR_SUCCESS) {
+        return status;
+    }
+    
+    ngh = h2c_util_ngheader_make_req(s->c->pool, r->headers, r->scheme, 
+                                     r->method, r->authority, r->path);
+    stream_id = nghttp2_submit_request(s->ngh2, NULL, ngh->nv, ngh->nvlen, 
+                                       NULL, stream);
+    if (stream_id < 0) {
+        return APR_EGENERAL;
+    }
+    
+    s->state = H2C_SESSION_ST_BUSY;
+    s->max_stream_sent = H2_MAX(s->max_stream_sent, stream_id);
+    ++s->open_streams;
+    stream->id = stream_id;
+    
+    if (pid) {
+        *pid =  stream_id;
+    }
+    return check_io_sense(s, APR_SUCCESS);
+}
+
+void h2c_session_output_set(h2c_session *s, FILE *output)
+{
+    s->output = output;
+}
+
+void h2c_session_feed_set(h2c_session *s, h2c_feed *feed)
+{
+    s->feed = feed;
+}

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_session.h
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_session.h?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_session.h (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_session.h Tue Dec 29 15:30:09 2015
@@ -0,0 +1,78 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef h2c_session_h
+#define h2c_session_h
+
+#include <apr_uri.h>
+
+struct h2c_conn;
+struct h2c_feed;
+struct h2c_request;
+struct h2c_stream;
+struct nghttp2_session;
+
+typedef struct h2c_session h2c_session;
+
+typedef enum {
+    H2C_SESSION_ST_INIT,             /* send initial SETTINGS, etc. */
+    H2C_SESSION_ST_IDLE,             /* nothing submitted */
+    H2C_SESSION_ST_BUSY,             /* read/write without stop */
+    H2C_SESSION_ST_BUSY_READ,        /* waiting for data from server */
+    H2C_SESSION_ST_KEEPALIVE,        /* IDLE passed, hanging around */
+    H2C_SESSION_ST_CLOSING,          /* shutting down */
+} h2c_session_state;
+
+struct h2c_session {
+    struct h2c_conn *c;
+    struct nghttp2_session *ngh2;
+    
+    h2c_session_state state;
+    unsigned int closed : 1;
+    unsigned int goaway_recvd : 1;
+    int verbose;
+    
+    int max_stream_recv;
+    int max_stream_sent;
+    
+    int max_streams;
+    int open_streams;
+    
+    int window_bits_default;
+    int window_bits_connection;
+    
+    FILE *output;
+    
+    struct h2c_feed *feed;
+};
+
+
+apr_status_t h2c_session_create(h2c_session **psession, struct h2c_conn *c, 
+                                int max_streams);
+
+apr_status_t h2c_session_add_request(h2c_session *session, struct h2c_request *r);
+
+apr_status_t h2c_session_close(h2c_session *session);
+
+void h2c_session_verbose_set(h2c_session *s, int verbose);
+
+apr_status_t h2c_session_on_read(h2c_session *s, const uint8_t *data, size_t len);
+apr_status_t h2c_session_on_write(h2c_session *session);
+                                
+apr_status_t h2c_session_submit(h2c_session *s, struct h2c_request *r, int *pid);
+
+void h2c_session_feed_set(h2c_session *s, struct h2c_feed *feed);
+void h2c_session_output_set(h2c_session *s, FILE *output);
+
+#endif /* h2c_session_h */

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_stream.c
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_stream.c?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_stream.c (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_stream.c Tue Dec 29 15:30:09 2015
@@ -0,0 +1,83 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr.h>
+#include <apr_strings.h>
+#include <apr_uri.h>
+
+#include "h2c_conn.h"
+#include "h2c_request.h"
+#include "h2c_session.h"
+#include "h2c_stream.h"
+
+apr_status_t h2c_stream_create(h2c_stream **pstream, apr_pool_t *p,
+                               h2c_session *s, const h2c_request *r, 
+                               FILE *output)
+{
+    h2c_stream *stream;
+    
+    stream = apr_pcalloc(p, sizeof(*stream));
+    
+    stream->p = p;
+    stream->s = s;
+    stream->r = r;
+    stream->output = output;
+    stream->response = apr_pcalloc(p, sizeof(h2c_response));
+    stream->response->headers = apr_table_make(p, 5);
+    
+    *pstream = stream;
+    return APR_SUCCESS;
+}
+
+apr_status_t h2c_stream_resp_add(h2c_stream *stream, 
+                                 const char *name, apr_size_t nlen, 
+                                 const char *value, apr_size_t vlen)
+{
+    name = apr_pstrndup(stream->p, name, nlen);
+    value = apr_pstrndup(stream->p, value, vlen);
+    
+    if (!apr_strnatcasecmp(":status", name)) {
+        stream->response->status = (int)apr_atoi64(value);
+    }
+    else {
+        apr_table_setn(stream->response->headers, name, value);
+    }
+    return APR_SUCCESS;
+}
+                                 
+apr_status_t h2c_stream_resp_append(h2c_stream *stream, 
+                                    const char *data, apr_size_t len)
+{
+    stream->response->recv_bytes += len;
+    if (stream->output) {
+        return fwrite(data, 1, len, stream->output);
+    }
+    return APR_SUCCESS;
+}
+                                    
+apr_status_t h2c_stream_close(h2c_stream *stream)
+{
+    if (!stream->closed) {
+        stream->closed = 1;
+        if (stream->s->verbose >= 0) {
+            fprintf(stderr, "%5ld:%05d %s %s -> %d %ld\n", 
+                    stream->s->c->id, stream->id, 
+                    stream->r->method, stream->r->path,
+                    stream->response->status, (long)stream->response->recv_bytes);
+        }
+    }
+    return APR_SUCCESS;
+}
+                                    

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_stream.h
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_stream.h?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_stream.h (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_stream.h Tue Dec 29 15:30:09 2015
@@ -0,0 +1,55 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef h2c_stream_h
+#define h2c_stream_h
+
+struct h2c_session;
+
+typedef struct h2c_stream h2c_stream;
+typedef struct h2c_response h2c_response;
+
+struct h2c_response {
+    apr_table_t *headers;
+    int status;
+    apr_off_t content_length;
+    apr_off_t recv_bytes;
+};
+
+struct h2c_stream {
+    int id;
+    struct h2c_session *s;
+    apr_pool_t *p;
+    
+    const h2c_request *r;
+    h2c_response *response;
+    
+    unsigned int closed :1;
+    FILE *output;
+};
+
+apr_status_t h2c_stream_create(h2c_stream **pstream, apr_pool_t *p,
+                               struct h2c_session *s, const h2c_request *r, 
+                               FILE *output);
+                    
+apr_status_t h2c_stream_resp_add(h2c_stream *stream, 
+                                 const char *name, apr_size_t nlen, 
+                                 const char *value, apr_size_t vlen);
+                                 
+apr_status_t h2c_stream_resp_append(h2c_stream *stream, 
+                                    const char *data, apr_size_t len);
+                                    
+apr_status_t h2c_stream_close(h2c_stream *stream);
+                                    
+#endif /* h2c_stream_h */

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_util.c
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_util.c?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_util.c (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_util.c Tue Dec 29 15:30:09 2015
@@ -0,0 +1,111 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr.h> 
+#include <apr_strings.h>
+#include <apr_uri.h>
+ 
+#include <nghttp2/nghttp2.h>
+
+#include "h2c_util.h"
+
+
+/*******************************************************************************
+ * h2c_ngheader
+ ******************************************************************************/
+
+#define H2_HD_MATCH_LIT_CS(l, name)  \
+    ((strlen(name) == sizeof(l) - 1) && !apr_strnatcasecmp(l, name))
+
+int h2c_util_ignore_header(const char *name) 
+{
+    /* never forward, ch. 8.1.2.2 */
+    return (H2_HD_MATCH_LIT_CS("connection", name)
+            || H2_HD_MATCH_LIT_CS("proxy-connection", name)
+            || H2_HD_MATCH_LIT_CS("upgrade", name)
+            || H2_HD_MATCH_LIT_CS("keep-alive", name)
+            || H2_HD_MATCH_LIT_CS("transfer-encoding", name));
+}
+
+static int count_header(void *ctx, const char *key, const char *value)
+{
+    if (!h2c_util_ignore_header(key)) {
+        (*((size_t*)ctx))++;
+    }
+    return 1;
+}
+
+#define NV_ADD_LIT_CS(nv, k, v)     add_header(nv, k, sizeof(k) - 1, v, strlen(v))
+#define NV_ADD_CS_CS(nv, k, v)      add_header(nv, k, strlen(k), v, strlen(v))
+
+static int add_header(h2c_ngheader *ngh, 
+                      const char *key, size_t key_len,
+                      const char *value, size_t val_len)
+{
+    nghttp2_nv *nv = &ngh->nv[ngh->nvlen++];
+    
+    nv->name = (uint8_t*)key;
+    nv->namelen = key_len;
+    nv->value = (uint8_t*)value;
+    nv->valuelen = val_len;
+    return 1;
+}
+
+static int add_table_header(void *ctx, const char *key, const char *value)
+{
+    if (!h2c_util_ignore_header(key)) {
+        add_header(ctx, key, strlen(key), value, strlen(value));
+    }
+    return 1;
+}
+
+
+h2c_ngheader *h2c_util_ngheader_make(apr_pool_t *p, apr_table_t *header)
+{
+    h2c_ngheader *ngh;
+    size_t n;
+    
+    n = 0;
+    apr_table_do(count_header, &n, header, NULL);
+    
+    ngh = apr_pcalloc(p, sizeof(h2c_ngheader));
+    ngh->nv =  apr_pcalloc(p, n * sizeof(nghttp2_nv));
+    apr_table_do(add_table_header, ngh, header, NULL);
+
+    return ngh;
+}
+
+h2c_ngheader *h2c_util_ngheader_make_req(apr_pool_t *p, apr_table_t *headers,
+                                         const char *scheme, const char *method,
+                                         const char *authority, const char *path)
+{
+    
+    h2c_ngheader *ngh;
+    size_t n;
+    
+    n = 4;
+    apr_table_do(count_header, &n, headers, NULL);
+    
+    ngh = apr_pcalloc(p, sizeof(h2c_ngheader));
+    ngh->nv =  apr_pcalloc(p, n * sizeof(nghttp2_nv));
+    NV_ADD_LIT_CS(ngh, ":scheme", scheme);
+    NV_ADD_LIT_CS(ngh, ":authority", authority);
+    NV_ADD_LIT_CS(ngh, ":path", path);
+    NV_ADD_LIT_CS(ngh, ":method", method);
+    apr_table_do(add_table_header, ngh, headers, NULL);
+
+    return ngh;
+}
+

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_util.h
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_util.h?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_util.h (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_util.h Tue Dec 29 15:30:09 2015
@@ -0,0 +1,35 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef h2c_util_h
+#define h2c_util_h
+
+#define H2_DIM(a)   (sizeof(a)/sizeof((a)[0]))
+
+#define H2_MIN(a,b) (((a) < (b))? (a) : (b))
+#define H2_MAX(a,b) (((a) > (b))? (a) : (b))
+
+
+typedef struct h2c_ngheader {
+    nghttp2_nv *nv;
+    apr_size_t nvlen;
+} h2c_ngheader;
+
+h2c_ngheader *h2c_util_ngheader_make(apr_pool_t *p, apr_table_t *header);
+h2c_ngheader *h2c_util_ngheader_make_req(apr_pool_t *p, apr_table_t *headers,
+                                         const char *scheme, const char *method,
+                                         const char *authority, const char *path);
+
+
+#endif /* h2c_util_h */

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_worker.c
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_worker.c?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_worker.c (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_worker.c Tue Dec 29 15:30:09 2015
@@ -0,0 +1,185 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <apr.h>
+#include <apr_strings.h>
+#include <apr_poll.h>
+#include <apr_uri.h>
+
+#include "h2c_conn.h"
+#include "h2c_feed.h"
+#include "h2c_session.h"
+#include "h2c_worker.h"
+
+static int nid;
+
+apr_status_t h2c_worker_create(h2c_worker **pw, apr_pool_t *p, apr_uri_t *uri, 
+                               h2c_feed *feed, int num_conns, int max_streams, int verbose)
+{
+    h2c_worker *w;
+    
+    w = apr_pcalloc(p, sizeof(*w));
+    
+    w->id = nid++;
+    w->p = p;
+    w->uri = uri;
+    w->feed = feed;
+    w->max_streams = max_streams;
+    w->verbose = verbose;
+    
+    w->num_conns = num_conns;
+    w->connections = apr_pcalloc(w->p, sizeof(h2c_conn*)*w->num_conns);
+    
+    *pw = w;
+    return APR_SUCCESS;
+}
+
+static void conn_destroy(h2c_worker *w, h2c_conn *c) 
+{
+    int i;
+    for (i = 0; i < w->num_conns; ++i) {
+        if (w->connections[i] == c) {
+            w->connections[i] = NULL;
+            break;
+        }
+    }
+    h2c_conn_destroy(c);
+}
+
+apr_status_t h2c_worker_run(h2c_worker *w) 
+{
+    apr_pollset_t *pollset;
+    apr_status_t status;
+    int i, live_conns = 0;
+    
+    status = apr_pollset_create(&pollset, w->num_conns, w->p, APR_POLLSET_NOCOPY);
+    if (status != APR_SUCCESS) {
+        fprintf(stderr, "error %d creating poll set\n", status);
+        return status;
+    }
+    
+    for (i = 0; i < w->num_conns; ++i) {
+        h2c_conn *conn;
+        h2c_session *session;
+        
+        status = h2c_conn_create(&conn, w->p, w->uri);
+        if (status != APR_SUCCESS) {
+            fprintf(stderr, "error %d creating conn %s\n", status, w->uri->hostname);
+            return status;
+        }
+        
+        w->connections[i] = conn;
+        
+        status = apr_pollset_add(pollset, conn->pfd);
+        if (status != APR_SUCCESS) {
+            fprintf(stderr, "error %d adding to poll set\n", status);
+            return status;
+        }
+
+        status = h2c_session_create(&session, conn, w->max_streams);
+        if (status != APR_SUCCESS) {
+            fprintf(stderr, "error %d creating session\n", status);
+            return status;
+        }
+        
+        h2c_session_feed_set(session, w->feed);
+        h2c_session_output_set(session, NULL);
+        
+        h2c_session_verbose_set(session, w->verbose);
+        if (w->verbose > 0) {
+            printf("connecting to %s (%s %d)...", conn->addr->hostname, conn->ip_addr, w->uri->port);
+        }
+        
+        status = apr_socket_connect(conn->socket, conn->addr);
+        if (status != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(status)) {
+            fprintf(stderr, "error %d connecting to %s\n", status, conn->addr->hostname);
+            return status;
+        }
+        
+        if (w->verbose > 0) {
+            printf("done.\n");
+        }
+        
+        apr_socket_opt_set(conn->socket, APR_SO_NONBLOCK, 1);
+    
+        ++live_conns;
+        h2c_conn_on_connect(conn);
+    }
+    
+    
+    while (live_conns > 0) {
+        apr_int32_t numdesc;
+        const apr_pollfd_t *pdesc;
+        const char *op;
+
+        status = apr_pollset_poll(pollset, apr_time_from_sec(10),
+                                  &numdesc, &pdesc);
+                                  
+        if (status != APR_SUCCESS) {
+            if (APR_STATUS_IS_TIMEUP(status)) {
+                fprintf(stderr, "timeup polling\n");
+                continue;
+            }
+            else if (APR_STATUS_IS_EINTR(status)) {
+                continue;
+            }
+            fprintf(stderr, "error %d on poll()\n", status);
+            return status;
+        }
+        
+        for (i = 0; i < numdesc; ++i) {
+            const apr_pollfd_t *pfd = &pdesc[i];
+            h2c_conn *c = pfd->client_data;
+            
+            if (pfd->rtnevents & APR_POLLIN) {
+                op = "reading";
+                status = h2c_conn_read(c);
+            }
+            if (pfd->rtnevents & APR_POLLOUT) {
+                op = "writing";
+                h2c_conn_on_write(c);
+                status = h2c_conn_write(c);
+            }
+            if (pfd->rtnevents & APR_POLLHUP) {
+                op = "closed";
+                status = APR_EOF;
+            }
+            if (pfd->rtnevents & APR_POLLNVAL) {
+                op = "reading";
+                status = APR_EOF;
+            }
+            
+            if (status != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(status)) {
+                if (status != APR_EOF) {
+                    fprintf(stderr, "error %d %s\n", status, op);
+                }
+                h2c_conn_close(c);
+            }
+            
+            if (!c->socket) {
+                apr_pollset_remove(pollset, pfd);
+                --live_conns;
+                conn_destroy(w, c);
+            }
+            else if (pfd->reqevents != c->pfd->reqevents) {
+                /* change in events this connection waits for */
+                apr_pollset_remove(pollset, pfd);
+                apr_pollset_add(pollset, c->pfd);
+            }
+        }
+    }
+    
+    return APR_SUCCESS;
+}
\ No newline at end of file

Added: httpd/test/mod_h2/trunk/mh2fuzz/h2c_worker.h
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/h2c_worker.h?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/h2c_worker.h (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/h2c_worker.h Tue Dec 29 15:30:09 2015
@@ -0,0 +1,42 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+#ifndef h2c_worker_h
+#define h2c_worker_h
+
+struct h2c_conn;
+struct h2c_feed;
+
+typedef struct h2c_worker h2c_worker;
+
+struct h2c_worker {
+    int id;
+    apr_pool_t *p;
+    apr_uri_t *uri;
+    h2c_feed *feed;
+    
+    int num_conns;
+    struct h2c_conn **connections;
+    int max_streams;
+    int verbose;
+};
+
+apr_status_t h2c_worker_create(h2c_worker **pw, apr_pool_t *p, apr_uri_t *uri,
+                               struct h2c_feed *feed, int num_conns, 
+                               int max_streams, int verbose);
+
+apr_status_t h2c_worker_run(h2c_worker *w);
+
+#endif /* h2c_worker_h */

Added: httpd/test/mod_h2/trunk/mh2fuzz/mh2f_main.c
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/mh2f_main.c?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/mh2f_main.c (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/mh2f_main.c Tue Dec 29 15:30:09 2015
@@ -0,0 +1,233 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <getopt.h>
+
+#include <apr.h>
+#include <apr_uri.h>
+#include <apr_strings.h>
+#include <apr_thread_proc.h>
+
+#include "h2c_conn.h"
+#include "h2c_feed.h"
+#include "h2c_request.h"
+#include "h2c_session.h"
+#include "h2c_worker.h"
+
+#include "mh2f_version.h"
+#include "mh2f_main.h"
+
+static int usage(const char *cmd, const char *msg) 
+{
+    if (msg) {
+        fprintf(stderr, "%s\n", msg);
+    }
+    fprintf(stderr, "usage: %s [options] url\n"
+           "  run http2 fuzz tests against url. \n  options are:\n"
+           "    -v   verbose\n"
+           "    -V   version\n"
+           , cmd);
+    
+    return 2;
+}
+
+static struct option long_options[] = {
+    { "connections",           required_argument, NULL, 'c'},
+    {"max-concurrent-streams", required_argument, NULL, 'm'},
+    { "quiet",                 no_argument,       NULL, 'q'},
+    { "requests",              required_argument, NULL, 'n'},
+    { "threads",               required_argument, NULL, 't'},
+    { "verbose",               no_argument,       NULL, 'v'},
+    { "version",               no_argument,       NULL, 'V'},
+    { NULL,                    0,                 NULL, 0}
+};
+
+static apr_thread_t *worker_create(apr_pool_t *parent, apr_uri_t *uri, 
+                                   h2c_feed *feed, apr_threadattr_t *attr,
+                                   int num_conns, int max_streams, int verbose);
+
+int main(int argc, char **argv)
+{
+    apr_pool_t *pool;
+    apr_uri_t uri;
+    apr_status_t status;
+    char c;
+    int option_index;
+    int verbose = 0;
+    int null_out = 1;
+    int max_streams = 1;
+    int repeats = 0;
+    int repeats_rem = 0;
+    int thread_count = 1;
+    int connections = -1;
+    int connections_rem = 0;
+    int i;
+    h2c_conn *conn;
+    h2c_session *session;
+    h2c_request *r;
+    apr_thread_t **threads;
+    apr_threadattr_t *thread_attr;
+    
+    apr_pool_initialize();
+    apr_pool_create_core(&pool);
+    
+    while (1) {
+        c = getopt_long(argc, argv, "c:m:n:qt:vV",
+                        long_options, &option_index);
+        
+        if (c == -1) {
+            break;
+        }
+        switch (c) {
+            case 'c':
+                connections = (int)apr_atoi64(optarg);
+                break;
+            case 'm':
+                  if (!apr_strnatcasecmp("auto", optarg)) {
+                      max_streams = -1;
+                  } 
+                  else {
+                      max_streams = (int)apr_atoi64(optarg);
+                  }
+                break;
+            case 'n':
+                repeats = (int)apr_atoi64(optarg);
+                break;
+            case 'q':
+                verbose = -1;
+                break;
+            case 't':
+                thread_count = (int)apr_atoi64(optarg);
+                break;
+            case 'v':
+                ++verbose;
+                break;
+            case 'V':
+                printf("%s version %s\n", argv[0], MH2F_VERSION);
+                return 2;
+            default:
+                return usage(argv[0], "unknown option");   
+        }
+    }
+    
+    if (argc == optind) {
+        return usage(argv[0], "no URL specified.");
+    }
+    else if (argc > optind+1) {
+        return usage(argv[0], "too many arguments.");
+    }
+    
+    status = apr_uri_parse(pool, argv[optind], &uri);
+    if (status != APR_SUCCESS) {
+        fprintf(stderr, "error=%d, not an uri: %s\n", status, argv[optind]);
+        return 1;
+    }
+
+    if (!uri.hostname) {
+        return usage(argv[0], "no host name found in uri.");
+    }
+    
+    if (uri.scheme) {
+        if (apr_strnatcasecmp("http", uri.scheme) 
+            && apr_strnatcasecmp("https", uri.scheme)) {
+            fprintf(stderr, "uri scheme %s not supported\n", uri.scheme);
+            return 1;
+        }
+    }
+    else {
+        uri.scheme = "https";
+    }
+    
+        
+    if (!uri.port_str) {
+        uri.port = apr_uri_port_of_scheme(uri.scheme);
+    }
+    
+    h2c_request_create(&r, pool, "GET", &uri);
+    apr_threadattr_create(&thread_attr, pool);
+    apr_threadattr_detach_set(thread_attr, 0);
+
+    threads = apr_pcalloc(pool, sizeof(apr_thread_t*) * thread_count);
+
+    if (connections <= 0) {
+        connections = thread_count;
+    }
+    connections_rem = connections % thread_count;
+    
+    if (repeats <= 0) {
+        repeats = connections;
+    }
+    repeats_rem = repeats % thread_count;
+    
+    for (i = 0; i < thread_count; ++i) {
+        h2c_feed *feed;
+        h2c_worker *w;
+        apr_thread_t *t;
+        int n, num_conns;
+        
+        num_conns = (connections / thread_count) + (connections_rem > 0? 1 : 0);
+        --connections_rem;
+        n = (repeats / thread_count) + ((repeats_rem > 0)? 1 : 0);
+        --repeats_rem;
+        
+        h2c_feed_repeat_create(&feed, pool, r, n);
+        threads[i] = worker_create(pool, &uri, feed, thread_attr,
+                                   num_conns, max_streams, verbose);
+    }
+    
+    
+    for (i = 0; i < thread_count; ++i) {
+        if (threads[i]) {
+            apr_thread_join(&status, threads[i]);
+        }
+    }
+    
+    return (status == APR_SUCCESS)? 0 : 1;
+}
+
+static void* APR_THREAD_FUNC execute(apr_thread_t *thread, void *ctx)
+{
+    h2c_worker *w = ctx;
+    apr_status_t status;
+    
+    status = h2c_worker_run(w);
+    apr_thread_exit(thread, status);
+    return NULL;
+}
+
+static apr_thread_t *worker_create(apr_pool_t *parent, apr_uri_t *uri, 
+                                   h2c_feed *feed, apr_threadattr_t *attr,
+                                   int num_conns, int max_streams, int verbose)
+{
+    apr_allocator_t *allocator;
+    apr_pool_t *pool;
+    apr_thread_t *t;
+    apr_status_t status;
+    h2c_worker *w;
+
+    apr_allocator_create(&allocator);
+    apr_pool_create_ex(&pool, parent, NULL, allocator);
+    apr_allocator_owner_set(allocator, pool);
+
+    status = h2c_worker_create(&w, pool, uri, feed, num_conns, max_streams, verbose);
+    if (status != APR_SUCCESS) {
+        fprintf(stderr, "error %d creating worker\n", status);
+        return NULL;
+    }
+
+    apr_thread_create(&t, attr, execute, w, pool);
+    return t;
+}
+

Added: httpd/test/mod_h2/trunk/mh2fuzz/mh2f_main.h
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/mh2f_main.h?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/mh2f_main.h (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/mh2f_main.h Tue Dec 29 15:30:09 2015
@@ -0,0 +1,20 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef mh2f_main_h
+#define mh2f_main_h
+
+#include <stdio.h>
+
+#endif /* mh2f_main_h */

Added: httpd/test/mod_h2/trunk/mh2fuzz/mh2f_version.h
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/mh2f_version.h?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/mh2f_version.h (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/mh2f_version.h Tue Dec 29 15:30:09 2015
@@ -0,0 +1,40 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef mh2f_version_h
+#define mh2f_version_h
+
+#undef PACKAGE_VERSION
+#undef PACKAGE_TARNAME
+#undef PACKAGE_STRING
+#undef PACKAGE_NAME
+#undef PACKAGE_BUGREPORT
+
+/**
+ * @macro
+ * Version number of the http2 module as c string
+ */
+#define MH2F_VERSION "1.0.15-DEV"
+
+/**
+ * @macro
+ * Numerical representation of the version number of the http2 module
+ * release. This is a 24 bit number with 8 bits for major number, 8 bits
+ * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
+ */
+#define MH2F_VERSION_NUM 0x01000f
+
+
+#endif /* mh2f_version_h */

Added: httpd/test/mod_h2/trunk/mh2fuzz/mh2f_version.h.in
URL: http://svn.apache.org/viewvc/httpd/test/mod_h2/trunk/mh2fuzz/mh2f_version.h.in?rev=1722149&view=auto
==============================================================================
--- httpd/test/mod_h2/trunk/mh2fuzz/mh2f_version.h.in (added)
+++ httpd/test/mod_h2/trunk/mh2fuzz/mh2f_version.h.in Tue Dec 29 15:30:09 2015
@@ -0,0 +1,40 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef mh2f_version_h
+#define mh2f_version_h
+
+#undef PACKAGE_VERSION
+#undef PACKAGE_TARNAME
+#undef PACKAGE_STRING
+#undef PACKAGE_NAME
+#undef PACKAGE_BUGREPORT
+
+/**
+ * @macro
+ * Version number of the http2 module as c string
+ */
+#define MH2F_VERSION "@PACKAGE_VERSION@"
+
+/**
+ * @macro
+ * Numerical representation of the version number of the http2 module
+ * release. This is a 24 bit number with 8 bits for major number, 8 bits
+ * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
+ */
+#define MH2F_VERSION_NUM @PACKAGE_VERSION_NUM@
+
+
+#endif /* mh2f_version_h */