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/11/20 16:13:11 UTC

svn commit: r1715371 [6/6] - in /httpd/httpd/branches/2.4.x: ./ docs/manual/mod/ modules/http2/

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_task_queue.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_task_queue.h?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_task_queue.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_task_queue.h Fri Nov 20 15:13:11 2015
@@ -19,29 +19,38 @@
 struct h2_task;
 
 /**
- * A simple ring of rings that keeps a list of h2_tasks and can
- * be ringed itself, using the APR RING macros.
+ * h2_task_queue keeps a list of sorted h2_task* in ascending order.
  */
 typedef struct h2_task_queue h2_task_queue;
 
 struct h2_task_queue {
-    APR_RING_ENTRY(h2_task_queue) link;
-    APR_RING_HEAD(h2_tasks, h2_task) tasks;
-    long id;
+    int *elts;
+    int head;
+    int nelts;
+    int nalloc;
+    apr_pool_t *pool;
 };
 
 /**
- * Allocate a new queue from the pool and initialize.
- * @param id the identifier of the queue
- * @param pool the memory pool
+ * Comparator for two task to determine their order.
+ *
+ * @param s1 stream id to compare
+ * @param s2 stream id to compare
+ * @param ctx provided user data
+ * @return value is the same as for strcmp() and has the effect:
+ *    == 0: s1 and s2 are treated equal in ordering
+ *     < 0: s1 should be sorted before s2
+ *     > 0: s2 should be sorted before s1
  */
-h2_task_queue *h2_tq_create(long id, apr_pool_t *pool);
+typedef int h2_tq_cmp(int s1, int s2, void *ctx);
+
 
 /**
- * Release all queue tasks.
- * @param q the queue to destroy
+ * Allocate a new queue from the pool and initialize.
+ * @param id the identifier of the queue
+ * @param pool the memory pool
  */
-void h2_tq_destroy(h2_task_queue *q);
+h2_task_queue *h2_tq_create(apr_pool_t *pool, int capacity);
 
 /**
  * Return != 0 iff there are no tasks in the queue.
@@ -50,99 +59,41 @@ void h2_tq_destroy(h2_task_queue *q);
 int h2_tq_empty(h2_task_queue *q);
 
 /**
- * Append the task to the end of the queue.
+ * Add a stream idto the queue. 
+ *
  * @param q the queue to append the task to
- * @param task the task to append
-  */
-void h2_tq_append(h2_task_queue *q, struct h2_task *task);
-
-/**
- * Remove a task from the queue. Return APR_SUCCESS if the task
- * was indeed queued, APR_NOTFOUND otherwise.
- * @param q the queue to remove from
- * @param task the task to remove
- */
-apr_status_t h2_tq_remove(h2_task_queue *q, struct h2_task *task);
-
-/**
- * Get the first task from the queue or NULL if the queue is empty. The
- * task will be removed.
- * @param q the queue to pop the first task from
- */
-h2_task *h2_tq_pop_first(h2_task_queue *q);
-
-/*******************************************************************************
- * Queue Manipulation.
- ******************************************************************************/
-
-/**
- * The magic pointer value that indicates the head of a h2_task_queue list
- * @param  b The queue list
- * @return The magic pointer value
+ * @param sid the stream id to add
+ * @param cmp the comparator for sorting
+ * @param ctx user data for comparator 
  */
-#define H2_TQ_LIST_SENTINEL(b)	APR_RING_SENTINEL((b), h2_task_queue, link)
+void h2_tq_add(h2_task_queue *q, int sid, h2_tq_cmp *cmp, void *ctx);
 
 /**
- * Determine if the queue list is empty
- * @param b The list to check
- * @return true or false
+ * Remove the stream id from the queue. Return != 0 iff task
+ * was found in queue.
+ * @param q the task queue
+ * @param sid the stream id to remove
+ * @return != 0 iff task was found in queue
  */
-#define H2_TQ_LIST_EMPTY(b)	APR_RING_EMPTY((b), h2_task_queue, link)
+int h2_tq_remove(h2_task_queue *q, int sid);
 
 /**
- * Return the first queue in a list
- * @param b The list to query
- * @return The first queue in the list
+ * Sort the stream idqueue again. Call if the task ordering
+ * has changed.
+ *
+ * @param q the queue to sort
+ * @param cmp the comparator for sorting
+ * @param ctx user data for the comparator 
  */
-#define H2_TQ_LIST_FIRST(b)	APR_RING_FIRST(b)
+void h2_tq_sort(h2_task_queue *q, h2_tq_cmp *cmp, void *ctx);
 
 /**
- * Return the last queue in a list
- * @param b The list to query
- * @return The last queue int he list
+ * Get the first stream id from the queue or NULL if the queue is empty. 
+ * The task will be removed.
+ *
+ * @param q the queue to get the first task from
+ * @return the first stream id of the queue, 0 if empty
  */
-#define H2_TQ_LIST_LAST(b)	APR_RING_LAST(b)
-
-/**
- * Insert a single queue at the front of a list
- * @param b The list to add to
- * @param e The queue to insert
- */
-#define H2_TQ_LIST_INSERT_HEAD(b, e) do {				\
-h2_task_queue *ap__b = (e);                                        \
-APR_RING_INSERT_HEAD((b), ap__b, h2_task_queue, link);	\
-} while (0)
-
-/**
- * Insert a single queue at the end of a list
- * @param b The list to add to
- * @param e The queue to insert
- */
-#define H2_TQ_LIST_INSERT_TAIL(b, e) do {				\
-h2_task_queue *ap__b = (e);					\
-APR_RING_INSERT_TAIL((b), ap__b, h2_task_queue, link);	\
-} while (0)
-
-/**
- * Get the next queue in the list
- * @param e The current queue
- * @return The next queue
- */
-#define H2_TQ_NEXT(e)	APR_RING_NEXT((e), link)
-/**
- * Get the previous queue in the list
- * @param e The current queue
- * @return The previous queue
- */
-#define H2_TQ_PREV(e)	APR_RING_PREV((e), link)
-
-/**
- * Remove a queue from its list
- * @param e The queue to remove
- */
-#define H2_TQ_REMOVE(e)	APR_RING_REMOVE((e), link)
-
-
-#define H2_TQ_EMPTY(e)	H2_TASK_LIST_EMPTY(&(e)->tasks)
+int h2_tq_shift(h2_task_queue *q);
 
 #endif /* defined(__mod_h2__h2_task_queue__) */

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_util.c?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_util.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_util.c Fri Nov 20 15:13:11 2015
@@ -20,10 +20,12 @@
 #include <httpd.h>
 #include <http_core.h>
 #include <http_log.h>
+#include <http_request.h>
 
 #include <nghttp2/nghttp2.h>
 
 #include "h2_private.h"
+#include "h2_request.h"
 #include "h2_util.h"
 
 size_t h2_util_hex_dump(char *buffer, size_t maxlen,
@@ -204,6 +206,10 @@ const char *h2_util_first_token_match(ap
     return NULL;
 }
 
+/*******************************************************************************
+ * h2_util for bucket brigades
+ ******************************************************************************/
+
 /* DEEP_COPY==0 crashes under load. I think the setaside is fine, 
  * however buckets moved to another thread will still be
  * free'd against the old bucket_alloc. *And* if the old
@@ -214,7 +220,7 @@ static const int DEEP_COPY = 1;
 static const int FILE_MOVE = 1;
 
 static apr_status_t last_not_included(apr_bucket_brigade *bb, 
-                                      apr_size_t maxlen, 
+                                      apr_off_t maxlen, 
                                       int same_alloc,
                                       int *pfile_buckets_allowed,
                                       apr_bucket **pend)
@@ -223,7 +229,7 @@ static apr_status_t last_not_included(ap
     apr_status_t status = APR_SUCCESS;
     int files_allowed = pfile_buckets_allowed? *pfile_buckets_allowed : 0;
     
-    if (maxlen > 0) {
+    if (maxlen >= 0) {
         /* Find the bucket, up to which we reach maxlen/mem bytes */
         for (b = APR_BRIGADE_FIRST(bb); 
              (b != APR_BRIGADE_SENTINEL(bb));
@@ -274,7 +280,7 @@ static apr_status_t last_not_included(ap
 #define LOG_LEVEL APLOG_INFO
 
 apr_status_t h2_util_move(apr_bucket_brigade *to, apr_bucket_brigade *from, 
-                          apr_size_t maxlen, int *pfile_handles_allowed, 
+                          apr_off_t maxlen, int *pfile_handles_allowed, 
                           const char *msg)
 {
     apr_status_t status = APR_SUCCESS;
@@ -406,7 +412,7 @@ apr_status_t h2_util_move(apr_bucket_bri
 }
 
 apr_status_t h2_util_copy(apr_bucket_brigade *to, apr_bucket_brigade *from, 
-                          apr_size_t maxlen, const char *msg)
+                          apr_off_t maxlen, const char *msg)
 {
     apr_status_t status = APR_SUCCESS;
     int same_alloc;
@@ -482,7 +488,7 @@ int h2_util_has_flush_or_eos(apr_bucket_
     return 0;
 }
 
-int h2_util_has_eos(apr_bucket_brigade *bb, apr_size_t len)
+int h2_util_has_eos(apr_bucket_brigade *bb, apr_off_t len)
 {
     apr_bucket *b, *end;
     
@@ -536,7 +542,7 @@ int h2_util_bb_has_data_or_eos(apr_bucke
 }
 
 apr_status_t h2_util_bb_avail(apr_bucket_brigade *bb, 
-                              apr_size_t *plen, int *peos)
+                              apr_off_t *plen, int *peos)
 {
     apr_status_t status;
     apr_off_t blen = 0;
@@ -549,36 +555,29 @@ apr_status_t h2_util_bb_avail(apr_bucket
     else if (blen == 0) {
         /* empty brigade, does it have an EOS bucket somwhere? */
         *plen = 0;
-        *peos = h2_util_has_eos(bb, 0);
+        *peos = h2_util_has_eos(bb, -1);
     }
-    else if (blen > 0) {
+    else {
         /* data in the brigade, limit the length returned. Check for EOS
          * bucket only if we indicate data. This is required since plen == 0
          * means "the whole brigade" for h2_util_hash_eos()
          */
-        if (blen < (apr_off_t)*plen) {
+        if (blen < *plen || *plen < 0) {
             *plen = blen;
         }
-        *peos = (*plen > 0)? h2_util_has_eos(bb, *plen) : 0;
-    }
-    else if (blen < 0) {
-        /* famous SHOULD NOT HAPPEN, sinc we told apr_brigade_length to readall
-         */
-        *plen = 0;
-        *peos = h2_util_has_eos(bb, 0);
-        return APR_EINVAL;
+        *peos = h2_util_has_eos(bb, *plen);
     }
     return APR_SUCCESS;
 }
 
 apr_status_t h2_util_bb_readx(apr_bucket_brigade *bb, 
                               h2_util_pass_cb *cb, void *ctx, 
-                              apr_size_t *plen, int *peos)
+                              apr_off_t *plen, int *peos)
 {
     apr_status_t status = APR_SUCCESS;
     int consume = (cb != NULL);
-    apr_size_t written = 0;
-    apr_size_t avail = *plen;
+    apr_off_t written = 0;
+    apr_off_t avail = *plen;
     apr_bucket *next, *b;
     
     /* Pass data in our brigade through the callback until the length
@@ -606,8 +605,7 @@ apr_status_t h2_util_bb_readx(apr_bucket
             
             if (b->length == ((apr_size_t)-1)) {
                 /* read to determine length */
-                status = apr_bucket_read(b, &data, &data_len, 
-                                         APR_NONBLOCK_READ);
+                status = apr_bucket_read(b, &data, &data_len, APR_NONBLOCK_READ);
             }
             else {
                 data_len = b->length;
@@ -647,3 +645,343 @@ apr_status_t h2_util_bb_readx(apr_bucket
     return status;
 }
 
+void h2_util_bb_log(conn_rec *c, int stream_id, int level, 
+                    const char *tag, apr_bucket_brigade *bb)
+{
+    char buffer[16 * 1024];
+    const char *line = "(null)";
+    apr_size_t bmax = sizeof(buffer)/sizeof(buffer[0]);
+    int off = 0;
+    apr_bucket *b;
+    
+    if (bb) {
+        memset(buffer, 0, bmax--);
+        for (b = APR_BRIGADE_FIRST(bb); 
+             bmax && (b != APR_BRIGADE_SENTINEL(bb));
+             b = APR_BUCKET_NEXT(b)) {
+            
+            if (APR_BUCKET_IS_METADATA(b)) {
+                if (APR_BUCKET_IS_EOS(b)) {
+                    off += apr_snprintf(buffer+off, bmax-off, "eos ");
+                }
+                else if (APR_BUCKET_IS_FLUSH(b)) {
+                    off += apr_snprintf(buffer+off, bmax-off, "flush ");
+                }
+                else if (AP_BUCKET_IS_EOR(b)) {
+                    off += apr_snprintf(buffer+off, bmax-off, "eor ");
+                }
+                else {
+                    off += apr_snprintf(buffer+off, bmax-off, "meta(unknown) ");
+                }
+            }
+            else {
+                const char *btype = "data";
+                if (APR_BUCKET_IS_FILE(b)) {
+                    btype = "file";
+                }
+                else if (APR_BUCKET_IS_PIPE(b)) {
+                    btype = "pipe";
+                }
+                else if (APR_BUCKET_IS_SOCKET(b)) {
+                    btype = "socket";
+                }
+                else if (APR_BUCKET_IS_HEAP(b)) {
+                    btype = "heap";
+                }
+                else if (APR_BUCKET_IS_TRANSIENT(b)) {
+                    btype = "transient";
+                }
+                else if (APR_BUCKET_IS_IMMORTAL(b)) {
+                    btype = "immortal";
+                }
+#if APR_HAS_MMAP
+                else if (APR_BUCKET_IS_MMAP(b)) {
+                    btype = "mmap";
+                }
+#endif
+                else if (APR_BUCKET_IS_POOL(b)) {
+                    btype = "pool";
+                }
+                
+                off += apr_snprintf(buffer+off, bmax-off, "%s[%ld] ", 
+                                    btype, 
+                                    (long)(b->length == ((apr_size_t)-1)? 
+                                           -1 : b->length));
+            }
+        }
+        line = *buffer? buffer : "(empty)";
+    }
+    ap_log_cerror(APLOG_MARK, level, 0, c, "bb_dump(%ld-%d)-%s: %s", 
+                  c->id, stream_id, tag, line);
+
+}
+
+apr_status_t h2_transfer_brigade(apr_bucket_brigade *to,
+                                 apr_bucket_brigade *from, 
+                                 apr_pool_t *p,
+                                 apr_off_t *plen,
+                                 int *peos)
+{
+    apr_bucket *e;
+    apr_off_t len = 0, remain = *plen;
+    apr_status_t rv;
+
+    *peos = 0;
+    
+    while (!APR_BRIGADE_EMPTY(from)) {
+        e = APR_BRIGADE_FIRST(from);
+        
+        if (APR_BUCKET_IS_METADATA(e)) {
+            if (APR_BUCKET_IS_EOS(e)) {
+                *peos = 1;
+            }
+        }
+        else {        
+            if (remain > 0 && e->length == ((apr_size_t)-1)) {
+                const char *ign;
+                apr_size_t ilen;
+                rv = apr_bucket_read(e, &ign, &ilen, APR_BLOCK_READ);
+                if (rv != APR_SUCCESS) {
+                    return rv;
+                }
+            }
+            
+            if (remain < e->length) {
+                if (remain <= 0) {
+                    return APR_SUCCESS;
+                }
+                apr_bucket_split(e, remain);
+            }
+        }
+        
+        rv = apr_bucket_setaside(e, p);
+        
+        /* If the bucket type does not implement setaside, then
+         * (hopefully) morph it into a bucket type which does, and set
+         * *that* aside... */
+        if (rv == APR_ENOTIMPL) {
+            const char *s;
+            apr_size_t n;
+            
+            rv = apr_bucket_read(e, &s, &n, APR_BLOCK_READ);
+            if (rv == APR_SUCCESS) {
+                rv = apr_bucket_setaside(e, p);
+            }
+        }
+        
+        if (rv != APR_SUCCESS) {
+            /* Return an error but still save the brigade if
+             * ->setaside() is really not implemented. */
+            if (rv != APR_ENOTIMPL) {
+                return rv;
+            }
+        }
+        
+        APR_BUCKET_REMOVE(e);
+        APR_BRIGADE_INSERT_TAIL(to, e);
+        len += e->length;
+        remain -= e->length;
+    }
+    
+    *plen = len;
+    return APR_SUCCESS;
+}
+
+/*******************************************************************************
+ * h2_ngheader
+ ******************************************************************************/
+ 
+int h2_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 (!h2_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(h2_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 (!h2_util_ignore_header(key)) {
+        add_header(ctx, key, strlen(key), value, strlen(value));
+    }
+    return 1;
+}
+
+
+h2_ngheader *h2_util_ngheader_make(apr_pool_t *p, apr_table_t *header)
+{
+    h2_ngheader *ngh;
+    size_t n;
+    
+    n = 0;
+    apr_table_do(count_header, &n, header, NULL);
+    
+    ngh = apr_pcalloc(p, sizeof(h2_ngheader));
+    ngh->nv =  apr_pcalloc(p, n * sizeof(nghttp2_nv));
+    apr_table_do(add_table_header, ngh, header, NULL);
+
+    return ngh;
+}
+
+h2_ngheader *h2_util_ngheader_make_res(apr_pool_t *p, 
+                                       int http_status, 
+                                       apr_table_t *header)
+{
+    h2_ngheader *ngh;
+    size_t n;
+    
+    n = 1;
+    apr_table_do(count_header, &n, header, NULL);
+    
+    ngh = apr_pcalloc(p, sizeof(h2_ngheader));
+    ngh->nv =  apr_pcalloc(p, n * sizeof(nghttp2_nv));
+    NV_ADD_LIT_CS(ngh, ":status", apr_psprintf(p, "%d", http_status));
+    apr_table_do(add_table_header, ngh, header, NULL);
+
+    return ngh;
+}
+
+h2_ngheader *h2_util_ngheader_make_req(apr_pool_t *p, 
+                                       const struct h2_request *req)
+{
+    
+    h2_ngheader *ngh;
+    size_t n;
+    
+    AP_DEBUG_ASSERT(req);
+    AP_DEBUG_ASSERT(req->scheme);
+    AP_DEBUG_ASSERT(req->authority);
+    AP_DEBUG_ASSERT(req->path);
+    AP_DEBUG_ASSERT(req->method);
+
+    n = 4;
+    apr_table_do(count_header, &n, req->headers, NULL);
+    
+    ngh = apr_pcalloc(p, sizeof(h2_ngheader));
+    ngh->nv =  apr_pcalloc(p, n * sizeof(nghttp2_nv));
+    NV_ADD_LIT_CS(ngh, ":scheme", req->scheme);
+    NV_ADD_LIT_CS(ngh, ":authority", req->authority);
+    NV_ADD_LIT_CS(ngh, ":path", req->path);
+    NV_ADD_LIT_CS(ngh, ":method", req->method);
+    apr_table_do(add_table_header, ngh, req->headers, NULL);
+
+    return ngh;
+}
+
+/*******************************************************************************
+ * header HTTP/1 <-> HTTP/2 conversions
+ ******************************************************************************/
+ 
+
+typedef struct {
+    const char *name;
+    size_t len;
+} literal;
+
+#define H2_DEF_LITERAL(n)   { (n), (sizeof(n)-1) }
+#define H2_ALEN(a)          (sizeof(a)/sizeof((a)[0]))
+#define H2_LIT_ARGS(a)      (a),H2_ALEN(a)
+
+static literal IgnoredRequestHeaders[] = {
+    H2_DEF_LITERAL("host"),
+    H2_DEF_LITERAL("expect"),
+    H2_DEF_LITERAL("upgrade"),
+    H2_DEF_LITERAL("connection"),
+    H2_DEF_LITERAL("keep-alive"),
+    H2_DEF_LITERAL("http2-settings"),
+    H2_DEF_LITERAL("proxy-connection"),
+    H2_DEF_LITERAL("transfer-encoding"),
+};
+static literal IgnoredRequestTrailers[] = { /* Ignore, see rfc7230, ch. 4.1.2 */
+    H2_DEF_LITERAL("te"),
+    H2_DEF_LITERAL("host"),
+    H2_DEF_LITERAL("range"),
+    H2_DEF_LITERAL("cookie"),
+    H2_DEF_LITERAL("expect"),
+    H2_DEF_LITERAL("pragma"),
+    H2_DEF_LITERAL("max-forwards"),
+    H2_DEF_LITERAL("cache-control"),
+    H2_DEF_LITERAL("authorization"),
+    H2_DEF_LITERAL("content-length"),       
+    H2_DEF_LITERAL("proxy-authorization"),
+};    
+static literal IgnoredResponseTrailers[] = {
+    H2_DEF_LITERAL("age"),
+    H2_DEF_LITERAL("date"),
+    H2_DEF_LITERAL("vary"),
+    H2_DEF_LITERAL("cookie"),
+    H2_DEF_LITERAL("expires"),
+    H2_DEF_LITERAL("warning"),
+    H2_DEF_LITERAL("location"),
+    H2_DEF_LITERAL("retry-after"),
+    H2_DEF_LITERAL("cache-control"),
+    H2_DEF_LITERAL("www-authenticate"),
+    H2_DEF_LITERAL("proxy-authenticate"),
+};
+
+static int ignore_header(const literal *lits, size_t llen,
+                         const char *name, size_t nlen)
+{
+    const literal *lit;
+    int i;
+    
+    for (i = 0; i < llen; ++i) {
+        lit = &lits[i];
+        if (lit->len == nlen && !apr_strnatcasecmp(lit->name, name)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+int h2_req_ignore_header(const char *name, size_t len)
+{
+    return ignore_header(H2_LIT_ARGS(IgnoredRequestHeaders), name, len);
+}
+
+int h2_req_ignore_trailer(const char *name, size_t len)
+{
+    return (h2_req_ignore_header(name, len) 
+            || ignore_header(H2_LIT_ARGS(IgnoredRequestTrailers), name, len));
+}
+
+int h2_res_ignore_trailer(const char *name, size_t len)
+{
+    return ignore_header(H2_LIT_ARGS(IgnoredResponseTrailers), name, len);
+}
+
+void h2_req_strip_ignored_header(apr_table_t *headers)
+{
+    int i;
+    for (i = 0; i < H2_ALEN(IgnoredRequestHeaders); ++i) {
+        apr_table_unset(headers, IgnoredRequestHeaders[i].name);
+    }
+}
+
+

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_util.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_util.h?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_util.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_util.h Fri Nov 20 15:13:11 2015
@@ -16,6 +16,7 @@
 #ifndef __mod_h2__h2_util__
 #define __mod_h2__h2_util__
 
+struct h2_request;
 struct nghttp2_frame;
 
 size_t h2_util_hex_dump(char *buffer, size_t maxlen,
@@ -29,6 +30,11 @@ char *h2_strlwr(char *s);
 
 void h2_util_camel_case_header(char *s, size_t len);
 
+int h2_req_ignore_header(const char *name, size_t len);
+int h2_req_ignore_trailer(const char *name, size_t len);
+void h2_req_strip_ignored_header(apr_table_t *headers);
+int h2_res_ignore_trailer(const char *name, size_t len);
+
 /**
  * Return != 0 iff the string s contains the token, as specified in
  * HTTP header syntax, rfc7230.
@@ -67,19 +73,33 @@ apr_size_t h2_util_base64url_decode(cons
                                             nv->value = (uint8_t *)VALUE;     \
                                             nv->valuelen = strlen(VALUE)
 
+int h2_util_ignore_header(const char *name);
+
+typedef struct h2_ngheader {
+    nghttp2_nv *nv;
+    apr_size_t nvlen;
+} h2_ngheader;
+
+h2_ngheader *h2_util_ngheader_make(apr_pool_t *p, apr_table_t *header);
+h2_ngheader *h2_util_ngheader_make_res(apr_pool_t *p, 
+                                       int http_status, 
+                                       apr_table_t *header);
+h2_ngheader *h2_util_ngheader_make_req(apr_pool_t *p, 
+                                       const struct h2_request *req);
+
 /**
  * Moves data from one brigade into another. If maxlen > 0, it only
  * moves up to maxlen bytes into the target brigade, making bucket splits
  * if needed.
  * @param to the brigade to move the data to
  * @param from the brigade to get the data from
- * @param maxlen of bytes to move, 0 for all
+ * @param maxlen of bytes to move, <= 0 for all
  * @param pfile_buckets_allowed how many file buckets may be moved, 
  *        may be 0 or NULL
  * @param msg message for use in logging
  */
 apr_status_t h2_util_move(apr_bucket_brigade *to, apr_bucket_brigade *from, 
-                          apr_size_t maxlen, int *pfile_buckets_allowed, 
+                          apr_off_t maxlen, int *pfile_buckets_allowed, 
                           const char *msg);
 
 /**
@@ -88,11 +108,11 @@ apr_status_t h2_util_move(apr_bucket_bri
  * if needed.
  * @param to the brigade to copy the data to
  * @param from the brigade to get the data from
- * @param maxlen of bytes to copy, 0 for all
+ * @param maxlen of bytes to copy, <= 0 for all
  * @param msg message for use in logging
  */
 apr_status_t h2_util_copy(apr_bucket_brigade *to, apr_bucket_brigade *from, 
-                          apr_size_t maxlen, const char *msg);
+                          apr_off_t maxlen, const char *msg);
 
 /**
  * Return != 0 iff there is a FLUSH or EOS bucket in the brigade.
@@ -100,7 +120,7 @@ apr_status_t h2_util_copy(apr_bucket_bri
  * @return != 0 iff brigade holds FLUSH or EOS bucket (or both)
  */
 int h2_util_has_flush_or_eos(apr_bucket_brigade *bb);
-int h2_util_has_eos(apr_bucket_brigade *bb, apr_size_t len);
+int h2_util_has_eos(apr_bucket_brigade *bb, apr_off_t len);
 int h2_util_bb_has_data(apr_bucket_brigade *bb);
 int h2_util_bb_has_data_or_eos(apr_bucket_brigade *bb);
 
@@ -112,13 +132,52 @@ int h2_util_bb_has_data_or_eos(apr_bucke
  * @param on return, if eos has been reached
  */
 apr_status_t h2_util_bb_avail(apr_bucket_brigade *bb, 
-                              apr_size_t *plen, int *peos);
+                              apr_off_t *plen, int *peos);
 
 typedef apr_status_t h2_util_pass_cb(void *ctx, 
-                                       const char *data, apr_size_t len);
+                                     const char *data, apr_off_t len);
 
+/**
+ * Read at most *plen bytes from the brigade and pass them into the
+ * given callback. If cb is NULL, just return the amount of data that
+ * could have been read.
+ * If an EOS was/would be encountered, set *peos != 0.
+ * @param bb the brigade to read from
+ * @param cb the callback to invoke for the read data
+ * @param ctx optional data passed to callback
+ * @param plen inout, as input gives the maximum number of bytes to read,
+ *    on return specifies the actual/would be number of bytes
+ * @param peos != 0 iff an EOS bucket was/would be encountered.
+ */
 apr_status_t h2_util_bb_readx(apr_bucket_brigade *bb, 
                               h2_util_pass_cb *cb, void *ctx, 
-                              apr_size_t *plen, int *peos);
+                              apr_off_t *plen, int *peos);
+
+/**
+ * Logs the bucket brigade (which bucket types with what length)
+ * to the log at the given level.
+ * @param c the connection to log for
+ * @param stream_id the stream identifier this brigade belongs to
+ * @param level the log level (as in APLOG_*)
+ * @param tag a short message text about the context
+ * @param bb the brigade to log
+ */
+void h2_util_bb_log(conn_rec *c, int stream_id, int level, 
+                    const char *tag, apr_bucket_brigade *bb);
+
+/**
+ * Transfer buckets from one brigade to another with a limit on the 
+ * maximum amount of bytes transfered.
+ * @param to   brigade to transfer buckets to
+ * @param from brigades to remove buckets from
+ * @param p    pool that buckets should be setaside to
+ * @param plen maximum bytes to transfer, actual bytes transferred
+ * @param peos if an EOS bucket was transferred
+ */
+apr_status_t h2_transfer_brigade(apr_bucket_brigade *to,
+                                 apr_bucket_brigade *from, 
+                                 apr_pool_t *p,
+                                 apr_off_t *plen,
+                                 int *peos);
 
 #endif /* defined(__mod_h2__h2_util__) */

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_version.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_version.h?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_version.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_version.h Fri Nov 20 15:13:11 2015
@@ -20,7 +20,7 @@
  * @macro
  * Version number of the h2 module as c string
  */
-#define MOD_HTTP2_VERSION "1.0.0"
+#define MOD_HTTP2_VERSION "1.0.5-DEV"
 
 /**
  * @macro
@@ -28,7 +28,7 @@
  * 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 MOD_HTTP2_VERSION_NUM 0x010000
+#define MOD_HTTP2_VERSION_NUM 0x010005
 
 
 #endif /* mod_h2_h2_version_h */

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_worker.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_worker.c?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_worker.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_worker.c Fri Nov 20 15:13:11 2015
@@ -22,7 +22,9 @@
 #include <http_log.h>
 
 #include "h2_private.h"
+#include "h2_conn.h"
 #include "h2_mplx.h"
+#include "h2_request.h"
 #include "h2_task.h"
 #include "h2_worker.h"
 
@@ -55,7 +57,7 @@ static void* APR_THREAD_FUNC execute(apr
         if (worker->task) {            
             h2_task_do(worker->task, worker);
             worker->task = NULL;
-            apr_thread_cond_signal(h2_worker_get_cond(worker));
+            apr_thread_cond_signal(worker->io);
         }
     }
 
@@ -71,6 +73,19 @@ static void* APR_THREAD_FUNC execute(apr
     return NULL;
 }
 
+static apr_status_t cleanup_join_thread(void *ctx)
+{
+    h2_worker *w = ctx;
+    /* do the join only when the worker is aborted. Otherwise,
+     * we are probably in a process shutdown.
+     */
+    if (w->thread && w->aborted) {
+        apr_status_t rv;
+        apr_thread_join(&rv, w->thread);
+    }
+    return APR_SUCCESS;
+}
+
 h2_worker *h2_worker_create(int id,
                             apr_pool_t *parent_pool,
                             apr_threadattr_t *attr,
@@ -99,7 +114,6 @@ h2_worker *h2_worker_create(int id,
         
         w->id = id;
         w->pool = pool;
-        w->bucket_alloc = apr_bucket_alloc_create(pool);
 
         w->get_next = get_next;
         w->worker_done = worker_done;
@@ -110,7 +124,9 @@ h2_worker *h2_worker_create(int id,
             return NULL;
         }
         
-        apr_thread_create(&w->thread, attr, execute, w, pool);
+        apr_pool_pre_cleanup_register(w->pool, w, cleanup_join_thread);
+        apr_thread_create(&w->thread, attr, execute, w, w->pool);
+        apr_pool_create(&w->task_pool, w->pool);
     }
     return w;
 }
@@ -143,28 +159,42 @@ int h2_worker_is_aborted(h2_worker *work
     return worker->aborted;
 }
 
-apr_thread_t *h2_worker_get_thread(h2_worker *worker)
+h2_task *h2_worker_create_task(h2_worker *worker, h2_mplx *m, 
+                               const h2_request *req, int eos)
 {
-    return worker->thread;
+    h2_task *task;
+    
+    /* Create a subpool from the worker one to be used for all things
+     * with life-time of this task execution.
+     */
+    task = h2_task_create(m->id, req, worker->task_pool, m, eos);
+    /* Link the task to the worker which provides useful things such
+     * as mutex, a socket etc. */
+    task->io = worker->io;
+    
+    return task;
 }
 
-apr_thread_cond_t *h2_worker_get_cond(h2_worker *worker)
-{
-    return worker->io;
+apr_status_t h2_worker_setup_task(h2_worker *worker, h2_task *task) {
+    apr_status_t status;
+    
+    
+    status = h2_conn_setup(task, apr_bucket_alloc_create(task->pool),
+                           worker->thread, worker->socket);
+    
+    return status;
 }
 
-apr_socket_t *h2_worker_get_socket(h2_worker *worker)
+void h2_worker_release_task(h2_worker *worker, struct h2_task *task)
 {
-    return worker->socket;
+    task->io = NULL;
+    task->pool = NULL;
+    apr_pool_clear(worker->task_pool);
 }
 
-apr_pool_t *h2_worker_get_pool(h2_worker *worker)
+apr_socket_t *h2_worker_get_socket(h2_worker *worker)
 {
-    return worker->pool;
+    return worker->socket;
 }
 
-apr_bucket_alloc_t *h2_worker_get_bucket_alloc(h2_worker *worker)
-{
-    return worker->bucket_alloc;
-}
 

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_worker.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_worker.h?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_worker.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_worker.h Fri Nov 20 15:13:11 2015
@@ -18,6 +18,7 @@
 
 struct apr_thread_cond_t;
 struct h2_mplx;
+struct h2_request;
 struct h2_task;
 
 /* h2_worker is a basically a apr_thread_t that reads fromt he h2_workers
@@ -44,7 +45,7 @@ struct h2_worker {
     int id;
     apr_thread_t *thread;
     apr_pool_t *pool;
-    apr_bucket_alloc_t *bucket_alloc;
+    apr_pool_t *task_pool;
     struct apr_thread_cond_t *io;
     apr_socket_t *socket;
     
@@ -142,14 +143,11 @@ int h2_worker_get_id(h2_worker *worker);
 
 int h2_worker_is_aborted(h2_worker *worker);
 
-apr_pool_t *h2_worker_get_pool(h2_worker *worker);
-
-apr_bucket_alloc_t *h2_worker_get_bucket_alloc(h2_worker *worker);
+struct h2_task *h2_worker_create_task(h2_worker *worker, struct h2_mplx *m, 
+                                      const struct h2_request *req, int eos);
+apr_status_t h2_worker_setup_task(h2_worker *worker, struct h2_task *task);
+void h2_worker_release_task(h2_worker *worker, struct h2_task *task);
 
 apr_socket_t *h2_worker_get_socket(h2_worker *worker);
 
-apr_thread_t *h2_worker_get_thread(h2_worker *worker);
-
-struct apr_thread_cond_t *h2_worker_get_cond(h2_worker *worker);
-
 #endif /* defined(__mod_h2__h2_worker__) */

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_workers.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_workers.c?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_workers.c (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_workers.c Fri Nov 20 15:13:11 2015
@@ -42,6 +42,22 @@ static int in_list(h2_workers *workers,
     return 0;
 }
 
+static void cleanup_zombies(h2_workers *workers, int lock) {
+    if (lock) {
+        apr_thread_mutex_lock(workers->lock);
+    }
+    while (!H2_WORKER_LIST_EMPTY(&workers->zombies)) {
+        h2_worker *zombie = H2_WORKER_LIST_FIRST(&workers->zombies);
+        H2_WORKER_REMOVE(zombie);
+        ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, workers->s,
+                      "h2_workers: cleanup zombie %d", zombie->id);
+        h2_worker_destroy(zombie);
+    }
+    if (lock) {
+        apr_thread_mutex_unlock(workers->lock);
+    }
+}
+
 
 /**
  * Get the next task for the given worker. Will block until a task arrives
@@ -63,7 +79,7 @@ static apr_status_t get_mplx_next(h2_wor
     if (*pm && ptask != NULL) {
         /* We have a h2_mplx instance and the worker wants the next task. 
          * Try to get one from the given mplx. */
-        *ptask = h2_mplx_pop_task(*pm, &has_more);
+        *ptask = h2_mplx_pop_task(*pm, worker, &has_more);
         if (*ptask) {
             return APR_SUCCESS;
         }
@@ -108,7 +124,7 @@ static apr_status_t get_mplx_next(h2_wor
                 m = H2_MPLX_LIST_FIRST(&workers->mplxs);
                 H2_MPLX_REMOVE(m);
                 
-                task = h2_mplx_pop_task(m, &has_more);
+                task = h2_mplx_pop_task(m, worker, &has_more);
                 if (task) {
                     if (has_more) {
                         H2_MPLX_LIST_INSERT_TAIL(&workers->mplxs, m);
@@ -123,23 +139,12 @@ static apr_status_t get_mplx_next(h2_wor
             if (!task) {
                 /* Need to wait for either a new mplx to arrive.
                  */
+                cleanup_zombies(workers, 0);
+                
                 if (workers->worker_count > workers->min_size) {
                     apr_time_t now = apr_time_now();
                     if (now >= (start_wait + max_wait)) {
                         /* waited long enough without getting a task. */
-                        status = APR_TIMEUP;
-                    }
-                    else {
-                        ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, workers->s,
-                                     "h2_worker(%d): waiting signal, "
-                                     "worker_count=%d", worker->id, 
-                                     (int)workers->worker_count);
-                        status = apr_thread_cond_timedwait(workers->mplx_added,
-                                                           workers->lock, max_wait);
-                    }
-                    
-                    if (status == APR_TIMEUP) {
-                        /* waited long enough */
                         if (workers->worker_count > workers->min_size) {
                             ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, 
                                          workers->s,
@@ -148,6 +153,12 @@ static apr_status_t get_mplx_next(h2_wor
                             break;
                         }
                     }
+                    ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, workers->s,
+                                 "h2_worker(%d): waiting signal, "
+                                 "worker_count=%d", worker->id, 
+                                 (int)workers->worker_count);
+                    apr_thread_cond_timedwait(workers->mplx_added,
+                                              workers->lock, max_wait);
                 }
                 else {
                     ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, workers->s,
@@ -163,7 +174,7 @@ static apr_status_t get_mplx_next(h2_wor
          * needed to give up with more than enough workers.
          */
         if (task) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, workers->s,
+            ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, workers->s,
                          "h2_worker(%d): start task(%s)",
                          h2_worker_get_id(worker), task->id);
             /* Since we hand out a reference to the worker, we increase
@@ -194,11 +205,11 @@ static void worker_done(h2_worker *worke
     h2_workers *workers = (h2_workers *)ctx;
     apr_status_t status = apr_thread_mutex_lock(workers->lock);
     if (status == APR_SUCCESS) {
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, workers->s,
+        ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, workers->s,
                      "h2_worker(%d): done", h2_worker_get_id(worker));
         H2_WORKER_REMOVE(worker);
         --workers->worker_count;
-        h2_worker_destroy(worker);
+        H2_WORKER_LIST_INSERT_TAIL(&workers->zombies, worker);
         
         apr_thread_mutex_unlock(workers->lock);
     }
@@ -213,7 +224,7 @@ static apr_status_t add_worker(h2_worker
     if (!w) {
         return APR_ENOMEM;
     }
-    ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, workers->s,
+    ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, workers->s,
                  "h2_workers: adding worker(%d)", h2_worker_get_id(w));
     ++workers->worker_count;
     H2_WORKER_LIST_INSERT_TAIL(&workers->workers, w);
@@ -235,15 +246,22 @@ static apr_status_t h2_workers_start(h2_
     return status;
 }
 
-h2_workers *h2_workers_create(server_rec *s, apr_pool_t *pool,
+h2_workers *h2_workers_create(server_rec *s, apr_pool_t *server_pool,
                               int min_size, int max_size)
 {
     apr_status_t status;
     h2_workers *workers;
+    apr_pool_t *pool;
+
     AP_DEBUG_ASSERT(s);
-    AP_DEBUG_ASSERT(pool);
-    status = APR_SUCCESS;
+    AP_DEBUG_ASSERT(server_pool);
 
+    /* let's have our own pool that will be parent to all h2_worker
+     * instances we create. This happens in various threads, but always
+     * guarded by our lock. Without this pool, all subpool creations would
+     * happen on the pool handed to us, which we do not guard.
+     */
+    apr_pool_create(&pool, server_pool);
     workers = apr_pcalloc(pool, sizeof(h2_workers));
     if (workers) {
         workers->s = s;
@@ -255,6 +273,7 @@ h2_workers *h2_workers_create(server_rec
         apr_threadattr_create(&workers->thread_attr, workers->pool);
         
         APR_RING_INIT(&workers->workers, h2_worker, link);
+        APR_RING_INIT(&workers->zombies, h2_worker, link);
         APR_RING_INIT(&workers->mplxs, h2_mplx, link);
         
         status = apr_thread_mutex_create(&workers->lock,
@@ -278,6 +297,9 @@ h2_workers *h2_workers_create(server_rec
 
 void h2_workers_destroy(h2_workers *workers)
 {
+    /* before we go, cleanup any zombie workers that may have accumulated */
+    cleanup_zombies(workers, 1);
+    
     if (workers->mplx_added) {
         apr_thread_cond_destroy(workers->mplx_added);
         workers->mplx_added = NULL;
@@ -294,13 +316,17 @@ void h2_workers_destroy(h2_workers *work
         h2_worker *w = H2_WORKER_LIST_FIRST(&workers->workers);
         H2_WORKER_REMOVE(w);
     }
+    if (workers->pool) {
+        apr_pool_destroy(workers->pool);
+        /* workers is gone */
+    }
 }
 
 apr_status_t h2_workers_register(h2_workers *workers, struct h2_mplx *m)
 {
     apr_status_t status = apr_thread_mutex_lock(workers->lock);
     if (status == APR_SUCCESS) {
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, status, workers->s,
+        ap_log_error(APLOG_MARK, APLOG_TRACE2, status, workers->s,
                      "h2_workers: register mplx(%ld)", m->id);
         if (in_list(workers, m)) {
             status = APR_EAGAIN;
@@ -320,6 +346,9 @@ apr_status_t h2_workers_register(h2_work
             add_worker(workers);
         }
         
+        /* cleanup any zombie workers that may have accumulated */
+        cleanup_zombies(workers, 0);
+        
         apr_thread_mutex_unlock(workers->lock);
     }
     return status;
@@ -334,6 +363,9 @@ apr_status_t h2_workers_unregister(h2_wo
             H2_MPLX_REMOVE(m);
             status = APR_SUCCESS;
         }
+        /* cleanup any zombie workers that may have accumulated */
+        cleanup_zombies(workers, 0);
+        
         apr_thread_mutex_unlock(workers->lock);
     }
     return status;

Modified: httpd/httpd/branches/2.4.x/modules/http2/h2_workers.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/h2_workers.h?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/h2_workers.h (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/h2_workers.h Fri Nov 20 15:13:11 2015
@@ -42,6 +42,7 @@ struct h2_workers {
     apr_threadattr_t *thread_attr;
     
     APR_RING_HEAD(h2_worker_list, h2_worker) workers;
+    APR_RING_HEAD(h2_worker_zombies, h2_worker) zombies;
     APR_RING_HEAD(h2_mplx_list, h2_mplx) mplxs;
     
     int worker_count;

Modified: httpd/httpd/branches/2.4.x/modules/http2/mod_http2.dsp
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/http2/mod_http2.dsp?rev=1715371&r1=1715370&r2=1715371&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/http2/mod_http2.dsp (original)
+++ httpd/httpd/branches/2.4.x/modules/http2/mod_http2.dsp Fri Nov 20 15:13:11 2015
@@ -105,6 +105,14 @@ SOURCE=./h2_alt_svc.c
 # End Source File
 # Begin Source File
 
+SOURCE=./h2_bucket_eoc.c
+# End Source File
+# Begin Source File
+
+SOURCE=./h2_bucket_eos.c
+# End Source File
+# Begin Source File
+
 SOURCE=./h2_config.c
 # End Source File
 # Begin Source File
@@ -141,6 +149,10 @@ SOURCE=./h2_mplx.c
 # End Source File
 # Begin Source File
 
+SOURCE=./h2_push.c
+# End Source File
+# Begin Source File
+
 SOURCE=./h2_request.c
 # End Source File
 # Begin Source File
@@ -181,10 +193,6 @@ SOURCE=./h2_task_queue.c
 # End Source File
 # Begin Source File
 
-SOURCE=./h2_to_h1.c
-# End Source File
-# Begin Source File
-
 SOURCE=./h2_util.c
 # End Source File
 # Begin Source File