Commit 1d66e4df authored by Stefan Eissing's avatar Stefan Eissing
Browse files

v1.0.10 of mod_http2 backport, see CHANGES

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

Changes with Apache 2.4.18

  *) mod_http2: connection level window for flow control is set to protocol
     maximum of 2GB-1, preventing window exhaustion when sending data on many
     streams with higher cumulative window size. 
     Reducing write frequency unless push promises need to be flushed.
     [Stefan Eissing]
  
  *) mod_http2: required minimum version of libnghttp2 is 1.2.1
     [Stefan Eissing]
  
  *) mod_ssl: For the "SSLStaplingReturnResponderErrors off" case, make sure
     to only staple responses with certificate status "good". [Kaspar Brand]

+6 −2
Original line number Diff line number Diff line
@@ -127,12 +127,12 @@ AC_DEFUN([APACHE_CHECK_NGHTTP2],[
      fi
    fi

    AC_MSG_CHECKING([for nghttp2 version >= 1.0.0])
    AC_MSG_CHECKING([for nghttp2 version >= 1.2.1])
    AC_TRY_COMPILE([#include <nghttp2/nghttp2ver.h>],[
#if !defined(NGHTTP2_VERSION_NUM)
#error "Missing nghttp2 version"
#endif
#if NGHTTP2_VERSION_NUM < 0x010000
#if NGHTTP2_VERSION_NUM < 0x010201
#error "Unsupported nghttp2 version " NGHTTP2_VERSION_TEXT
#endif],
      [AC_MSG_RESULT(OK)
@@ -154,6 +154,10 @@ AC_DEFUN([APACHE_CHECK_NGHTTP2],[
      if test "x$liberrors" != "x"; then
        AC_MSG_WARN([nghttp2 library is unusable])
      fi
dnl # nghttp2 >= 1.3.0: access to stream weights
      AC_CHECK_FUNCS([nghttp2_stream_get_weight], 
        [APR_ADDTO(MOD_CPPFLAGS, ["-DH2_NG2_STREAM_API"])], [])
dnl # nghttp2 >= 1.5.0: changing stream priorities
      AC_CHECK_FUNCS([nghttp2_session_change_stream_priority], 
        [APR_ADDTO(MOD_CPPFLAGS, ["-DH2_NG2_CHANGE_PRIO"])], [])
    else
+14 −39
Original line number Diff line number Diff line
@@ -195,22 +195,23 @@ apr_status_t h2_conn_process(conn_rec *c, request_rec *r, server_rec *s)

static void fix_event_conn(conn_rec *c, conn_rec *master);

static int SLAVE_CONN_25DEV_STYLE = 1;

conn_rec *h2_conn_create(conn_rec *master, apr_pool_t *pool)
{
    apr_socket_t *socket;
    conn_rec *c;
    
    AP_DEBUG_ASSERT(master);

    if (SLAVE_CONN_25DEV_STYLE) {
    /* This is like the slave connection creation from 2.5-DEV. A
     * very efficient way - not sure how compatible this is, since
     * the core hooks are no longer run.
     * But maybe it's is better this way, not sure yet.
     */
    c = (conn_rec *) apr_palloc(pool, sizeof(conn_rec));
    if (c == NULL) {
        ap_log_perror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, pool, 
                      APLOGNO(02913) "h2_task: creating conn");
        return NULL;
    }
    
    memcpy(c, master, sizeof(conn_rec));
    c->id = (master->id & (long)pool);
@@ -218,32 +219,6 @@ conn_rec *h2_conn_create(conn_rec *master, apr_pool_t *pool)
    c->input_filters = NULL;
    c->output_filters = NULL;
    c->pool = pool;        
    }
    else {
        /* CAVEAT: it seems necessary to setup the conn_rec in the master
         * connection thread. Other attempts crashed. 
         * HOWEVER: we setup the connection using the pools and other items
         * from the master connection, since we do not want to allocate 
         * lots of resources here. 
         * Lets allocated pools and everything else when we actually start
         * working on this new connection.
         */
        /* Not sure about the scoreboard handle. Reusing the one from the main
         * connection could make sense, is not really correct, but we cannot
         * easily create new handles for our worker threads either.
         * TODO
         */
        socket = ap_get_module_config(master->conn_config, &core_module);
        c = ap_run_create_connection(pool, master->base_server,
                                     socket,
                                     master->id^((long)pool), 
                                     master->sbh,
                                     master->bucket_alloc);
    }
    if (c == NULL) {
        ap_log_perror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, pool, 
                      APLOGNO(02913) "h2_task: creating conn");
    }
    return c;
}

+57 −10
Original line number Diff line number Diff line
@@ -94,6 +94,8 @@ h2_stream *h2_session_open_stream(h2_session *session, int stream_id)
    return stream;
}

#ifdef H2_NG2_STREAM_API

/**
 * Determine the importance of streams when scheduling tasks.
 * - if both stream depend on the same one, compare weights
@@ -147,6 +149,20 @@ static int stream_pri_cmp(int sid1, int sid2, void *ctx)
    return spri_cmp(sid1, s1, sid2, s2, session);
}

#else /* ifdef H2_NG2_STREAM_API */

/* In absence of nghttp2_stream API, which gives information about
 * priorities since nghttp2 1.3.x, we just sort the streams by
 * their identifier, aka. order of arrival.
 */
static int stream_pri_cmp(int sid1, int sid2, void *ctx)
{
    (void)ctx;
    return sid1 - sid2;
}

#endif /* (ifdef else) H2_NG2_STREAM_API */

static apr_status_t stream_schedule(h2_session *session,
                                    h2_stream *stream, int eos)
{
@@ -884,7 +900,7 @@ apr_status_t h2_session_start(h2_session *session, int *rv)
    apr_status_t status = APR_SUCCESS;
    nghttp2_settings_entry settings[3];
    size_t slen;
    int i;
    int win_size;
    
    AP_DEBUG_ASSERT(session);
    /* Start the conversation by submitting our SETTINGS frame */
@@ -947,10 +963,10 @@ apr_status_t h2_session_start(h2_session *session, int *rv)
    settings[slen].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
    settings[slen].value = (uint32_t)session->max_stream_count;
    ++slen;
    i = h2_config_geti(session->config, H2_CONF_WIN_SIZE);
    if (i != H2_INITIAL_WINDOW_SIZE) {
    win_size = h2_config_geti(session->config, H2_CONF_WIN_SIZE);
    if (win_size != H2_INITIAL_WINDOW_SIZE) {
        settings[slen].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
        settings[slen].value = i;
        settings[slen].value = win_size;
        ++slen;
    }
    
@@ -962,7 +978,25 @@ apr_status_t h2_session_start(h2_session *session, int *rv)
                      APLOGNO(02935) "nghttp2_submit_settings: %s", 
                      nghttp2_strerror(*rv));
    }
    
    else {
        /* use maximum possible value for connection window size. We are only
         * interested in per stream flow control. which have the initial window
         * size configured above.
         * Therefore, for our use, the connection window can only get in the
         * way. Example: if we allow 100 streams with a 32KB window each, we
         * buffer up to 3.2 MB of data. Unless we do separate connection window
         * interim updates, any smaller connection window will lead to blocking
         * in DATA flow.
         */
        *rv = nghttp2_submit_window_update(session->ngh2, NGHTTP2_FLAG_NONE,
                                           0, NGHTTP2_MAX_WINDOW_SIZE - win_size);
        if (*rv != 0) {
            status = APR_EGENERAL;
            ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c,
                          APLOGNO(02970) "nghttp2_submit_window_update: %s", 
                          nghttp2_strerror(*rv));        
        }
    }
    return status;
}

@@ -1289,6 +1323,7 @@ struct h2_stream *h2_session_push(h2_session *session, h2_stream *is,
            h2_stream_cleanup(stream);
            stream = NULL;
        }
        ++session->unsent_promises;
    }
    else {
        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
@@ -1539,14 +1574,23 @@ apr_status_t h2_session_process(h2_session *session)
            h2_session_resume_streams_with_data(session);
            
            if (h2_stream_set_has_unsubmitted(session->streams)) {
                int unsent_submits = 0;
                
                /* If we have responses ready, submit them now. */
                while ((stream = h2_mplx_next_submit(session->mplx, session->streams))) {
                    status = submit_response(session, stream);
                    ++unsent_submits;
                    
                    /* Unsent push promises are written immediately, as nghttp2
                     * 1.5.0 realizes internal stream data structures only on 
                     * send and we might need them for other submits. 
                     * Also, to conserve memory, we send at least every 10 submits
                     * so that nghttp2 does not buffer all outbound items too 
                     * long.
                     */
                    if (status == APR_SUCCESS 
                        && nghttp2_session_want_write(session->ngh2)) {
                        int rv;
                        
                        rv = nghttp2_session_send(session->ngh2);
                        && (session->unsent_promises || unsent_submits > 10)) {
                        int rv = nghttp2_session_send(session->ngh2);
                        if (rv != 0) {
                            ap_log_cerror( APLOG_MARK, APLOG_DEBUG, 0, session->c,
                                          "h2_session: send: %s", nghttp2_strerror(rv));
@@ -1558,6 +1602,8 @@ apr_status_t h2_session_process(h2_session *session)
                        else {
                            have_written = 1;
                            wait_micros = 0;
                            session->unsent_promises = 0;
                            unsent_submits = 0;
                        }
                    }
                }
@@ -1582,6 +1628,7 @@ apr_status_t h2_session_process(h2_session *session)
            else {
                have_written = 1;
                wait_micros = 0;
                session->unsent_promises = 0;
            }
        }
        
+2 −0
Original line number Diff line number Diff line
@@ -63,6 +63,8 @@ struct h2_session {
    int aborted;                    /* this session is being aborted */
    int reprioritize;               /* scheduled streams priority needs to 
                                     * be re-evaluated */
    int unsent_promises;            /* number of submitted, but not yet sent
                                     * push promised */
    apr_size_t frames_received;     /* number of http/2 frames received */
    apr_size_t max_stream_count;    /* max number of open streams */
    apr_size_t max_stream_mem;      /* max buffer memory for a single stream */
Loading