Commit c3aaf225 authored by Stefan Eissing's avatar Stefan Eissing
Browse files

mod_http2: backport of v1.5.5

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1744420 13f79535-47bb-0310-9956-ffa450edef68
parent 64689654
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -2,6 +2,17 @@

Changes with Apache 2.4.21

  *) mod_http2: Fix async write issue that led to selection of wrong timeout
     vs. keepalive timeout selection for idle sessions. [Stefan Eissing]
     
  *) mod_http2: checking LimitRequestLine, LimitRequestFields and 
     LimitRequestFieldSize configurated values for incoming streams. Returning
     HTTP status 431 for too long/many headers fields and 414 for a too long
     pseudo header. [Stefan Eissing]
     
  *) mod_http2: tracking conn_rec->current_thread on slave connections, so
     that mod_lua finds the correct one. Fixes PR 59542. [Stefan Eissing]
     
  *) mod_proxy_http2: new experimental http2 proxy module for h2: and h2c: proxy
     urls. Part of the httpd mod_proxy framework, common settings apply.
     Requests from the same HTTP/2 frontend connection against the same backend
+1 −0
Original line number Diff line number Diff line
@@ -355,6 +355,7 @@ $(OBJDIR)/mod_http2.imp : NWGNUmod_http2
	@echo $(DL)GEN  $@$(DL)
	@echo $(DL) (HTTP2)$(DL) > $@
	@echo $(DL) http2_module,$(DL) >> $@
	@echo $(DL) h2_casecmpstrn,$(DL) >> $@
	@echo $(DL) h2_ihash_add,$(DL) >> $@
	@echo $(DL) h2_ihash_clear,$(DL) >> $@
	@echo $(DL) h2_ihash_count,$(DL) >> $@
+13 −8
Original line number Diff line number Diff line
@@ -291,7 +291,8 @@ static void fix_vary(request_rec *r)
    }
}

static void set_basic_http_header(request_rec *r, apr_table_t *headers)
void h2_from_h1_set_basic_http_header(apr_table_t *headers, request_rec *r,
                                      apr_pool_t *pool)
{
    char *date = NULL;
    const char *proxy_date = NULL;
@@ -302,7 +303,7 @@ static void set_basic_http_header(request_rec *r, apr_table_t *headers)
     * keep the set-by-proxy server and date headers, otherwise
     * generate a new server header / date header
     */
    if (r->proxyreq != PROXYREQ_NONE) {
    if (r && r->proxyreq != PROXYREQ_NONE) {
        proxy_date = apr_table_get(r->headers_out, "Date");
        if (!proxy_date) {
            /*
@@ -310,27 +311,31 @@ static void set_basic_http_header(request_rec *r, apr_table_t *headers)
             * our own Date header and pass it over to proxy_date later to
             * avoid a compiler warning.
             */
            date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
            date = apr_palloc(pool, APR_RFC822_DATE_LEN);
            ap_recent_rfc822_date(date, r->request_time);
        }
        server = apr_table_get(r->headers_out, "Server");
    }
    else {
        date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
        ap_recent_rfc822_date(date, r->request_time);
        date = apr_palloc(pool, APR_RFC822_DATE_LEN);
        ap_recent_rfc822_date(date, r? r->request_time : apr_time_now());
    }
    
    apr_table_setn(headers, "Date", proxy_date ? proxy_date : date );
    if (r) {
        apr_table_unset(r->headers_out, "Date");
    }
    
    if (!server && *us) {
        server = us;
    }
    if (server) {
        apr_table_setn(headers, "Server", server);
        if (r) {
            apr_table_unset(r->headers_out, "Server");
        }
    }
}

static int copy_header(void *ctx, const char *name, const char *value)
{
@@ -445,7 +450,7 @@ static h2_response *create_response(h2_from_h1 *from_h1, request_rec *r)
    
    headers = apr_table_make(r->pool, 10);
    
    set_basic_http_header(r, headers);
    h2_from_h1_set_basic_http_header(headers, r, r->pool);
    if (r->status == HTTP_NOT_MODIFIED) {
        apr_table_do((int (*)(void *, const char *, const char *)) copy_header,
                     (void *) headers, r->headers_out,
+3 −0
Original line number Diff line number Diff line
@@ -69,4 +69,7 @@ apr_status_t h2_response_output_filter(ap_filter_t *f, apr_bucket_brigade *bb);

apr_status_t h2_response_trailers_filter(ap_filter_t *f, apr_bucket_brigade *bb);

void h2_from_h1_set_basic_http_header(apr_table_t *headers, request_rec *r,
                                      apr_pool_t *pool);

#endif /* defined(__mod_h2__h2_from_h1__) */
+22 −40
Original line number Diff line number Diff line
@@ -282,11 +282,11 @@ h2_mplx *h2_mplx_create(conn_rec *c, apr_pool_t *parent,
        m->stream_max_mem = h2_config_geti(conf, H2_CONF_STREAM_MAX_MEM);

        m->streams = h2_ihash_create(m->pool, offsetof(h2_stream,id));
        m->sready = h2_ihash_create(m->pool, offsetof(h2_stream,id));
        m->shold = h2_ihash_create(m->pool, offsetof(h2_stream,id));
        m->spurge = h2_ihash_create(m->pool, offsetof(h2_stream,id));
        m->q = h2_iq_create(m->pool, m->max_streams);
        m->tasks = h2_ihash_create(m->pool, offsetof(h2_task,stream_id));
        m->ready_tasks = h2_ihash_create(m->pool, offsetof(h2_task,stream_id));

        m->stream_timeout = stream_timeout;
        m->workers = workers;
@@ -373,7 +373,6 @@ static void task_destroy(h2_mplx *m, h2_task *task, int called_from_master)
                   && !task->rst_error);
    
    h2_ihash_remove(m->tasks, task->stream_id);
    h2_ihash_remove(m->ready_tasks, task->stream_id);
    if (m->redo_tasks) {
        h2_ihash_remove(m->redo_tasks, task->stream_id);
    }
@@ -428,7 +427,7 @@ static void stream_done(h2_mplx *m, h2_stream *stream, int rst_error)
     * stream destruction until the task is done. 
     */
    h2_iq_remove(m->q, stream->id);
    h2_ihash_remove(m->ready_tasks, stream->id);
    h2_ihash_remove(m->sready, stream->id);
    h2_ihash_remove(m->streams, stream->id);
    if (stream->input) {
        m->tx_handles_reserved += h2_beam_get_files_beamed(stream->input);
@@ -657,11 +656,10 @@ apr_status_t h2_mplx_in_update_windows(h2_mplx *m)
    return status;
}

static int task_iter_first(void *ctx, void *val)
static int stream_iter_first(void *ctx, void *val)
{
    task_iter_ctx *tctx = ctx;
    h2_task *task = val;
    tctx->task = task;
    h2_stream **pstream = ctx;
    *pstream = val;
    return 0;
}

@@ -673,17 +671,11 @@ h2_stream *h2_mplx_next_submit(h2_mplx *m)

    AP_DEBUG_ASSERT(m);
    if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) {
        task_iter_ctx ctx;
        ctx.m = m;
        ctx.task = NULL;
        h2_ihash_iter(m->ready_tasks, task_iter_first, &ctx);
        
        if (ctx.task && !m->aborted) {
            h2_task *task = ctx.task;
            
            h2_ihash_remove(m->ready_tasks, task->stream_id);
            stream = h2_ihash_get(m->streams, task->stream_id);
            if (stream && task) {
        h2_ihash_iter(m->sready, stream_iter_first, &stream);
        if (stream) {
            h2_task *task = h2_ihash_get(m->tasks, stream->id);
            h2_ihash_remove(m->sready, stream->id);
            if (task) {
                task->submitted = 1;
                if (task->rst_error) {
                    h2_stream_rst(stream, task->rst_error);
@@ -694,24 +686,11 @@ h2_stream *h2_mplx_next_submit(h2_mplx *m)
                                           task->output.beam);
                }
            }
            else if (task) {
                /* We have the io ready, but the stream has gone away, maybe
                 * reset by the client. Should no longer happen since such
                 * streams should clear io's from the ready queue.
                 */
                ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, APLOGNO(03347)
                              "h2_mplx(%s): stream for response closed, "
                              "resetting io to close request processing",
                              task->id);
                h2_task_rst(task, H2_ERR_STREAM_CLOSED);
                if (!task->worker_started || task->worker_done) {
                    task_destroy(m, task, 1);
                }
            else {
                    /* hang around until the h2_task is done, but
                     * shutdown output */
                    h2_task_shutdown(task, 0);
                }
                /* We have the stream ready without a task. This happens
                 * when we fail streams early. A response should already
                 * be present.  */
                AP_DEBUG_ASSERT(stream->response || stream->rst_error);
            }
        }
        leave_mutex(m, acquired);
@@ -744,7 +723,7 @@ static apr_status_t out_open(h2_mplx *m, int stream_id, h2_response *response)
        h2_beam_mutex_set(task->output.beam, beam_enter, task->cond, m);
    }
    
    h2_ihash_add(m->ready_tasks, task);
    h2_ihash_add(m->sready, stream);
    if (response && response->http_status < 300) {
        /* we might see some file buckets in the output, see
         * if we have enough handles reserved. */
@@ -788,10 +767,9 @@ static apr_status_t out_close(h2_mplx *m, h2_task *task)

    if (!task->response && !task->rst_error) {
        /* In case a close comes before a response was created,
         * insert an error one so that our streams can properly
         * reset.
         * insert an error one so that our streams can properly reset.
         */
        h2_response *r = h2_response_die(task->stream_id, APR_EGENERAL, 
        h2_response *r = h2_response_die(task->stream_id, 500, 
                                         task->request, m->pool);
        status = out_open(m, task->stream_id, r);
        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, m->c,
@@ -876,6 +854,10 @@ apr_status_t h2_mplx_process(h2_mplx *m, struct h2_stream *stream,
        if (m->aborted) {
            status = APR_ECONNABORTED;
        }
        else if (stream->response) {
            /* already have a respone, schedule for submit */
            h2_ihash_add(m->sready, stream);
        }
        else {
            h2_beam_create(&stream->input, stream->pool, stream->id, 
                           "input", 0);
Loading