apr_status_t h2_session_start(h2_session *session, int *rv) { apr_status_t status = APR_SUCCESS; h2_config *config; nghttp2_settings_entry settings[3]; AP_DEBUG_ASSERT(session); /* Start the conversation by submitting our SETTINGS frame */ *rv = 0; config = h2_config_get(session->c); if (session->r) { const char *s, *cs; apr_size_t dlen; h2_stream * stream; /* better for vhost matching */ config = h2_config_rget(session->r); /* 'h2c' mode: we should have a 'HTTP2-Settings' header with * base64 encoded client settings. */ s = apr_table_get(session->r->headers_in, "HTTP2-Settings"); if (!s) { ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EINVAL, session->r, APLOGNO(02931) "HTTP2-Settings header missing in request"); return APR_EINVAL; } cs = NULL; dlen = h2_util_base64url_decode(&cs, s, session->pool); if (APLOGrdebug(session->r)) { char buffer[128]; h2_util_hex_dump(buffer, 128, (char*)cs, dlen); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, session->r, "upgrading h2c session with HTTP2-Settings: %s -> %s (%d)", s, buffer, (int)dlen); } *rv = nghttp2_session_upgrade(session->ngh2, (uint8_t*)cs, dlen, NULL); if (*rv != 0) { status = APR_EINVAL; ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r, APLOGNO(02932) "nghttp2_session_upgrade: %s", nghttp2_strerror(*rv)); return status; } /* Now we need to auto-open stream 1 for the request we got. */ *rv = stream_open(session, 1); if (*rv != 0) { status = APR_EGENERAL; ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r, APLOGNO(02933) "open stream 1: %s", nghttp2_strerror(*rv)); return status; } stream = h2_stream_set_get(session->streams, 1); if (stream == NULL) { status = APR_EGENERAL; ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r, APLOGNO(02934) "lookup of stream 1"); return status; } status = h2_stream_rwrite(stream, session->r); if (status != APR_SUCCESS) { return status; } status = stream_end_headers(session, stream, 1); if (status != APR_SUCCESS) { return status; } } settings[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; settings[0].value = (uint32_t)session->max_stream_count; settings[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; settings[1].value = h2_config_geti(config, H2_CONF_WIN_SIZE); settings[2].settings_id = NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE; settings[2].value = 64*1024; *rv = nghttp2_submit_settings(session->ngh2, NGHTTP2_FLAG_NONE, settings, sizeof(settings)/sizeof(settings[0])); if (*rv != 0) { status = APR_EGENERAL; ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c, APLOGNO(02935) "nghttp2_submit_settings: %s", nghttp2_strerror(*rv)); } return status; }
apr_status_t h2_session_start(h2_session *session) { assert(session); /* Start the conversation by submitting our SETTINGS frame */ apr_status_t status = APR_SUCCESS; h2_config *config = h2_config_get(session->c); int rv = 0; if (session->r) { /* 'h2c' mode: we should have a 'HTTP2-Settings' header with * base64 encoded client settings. */ const char *s = apr_table_get(session->r->headers_in, "HTTP2-Settings"); if (!s) { ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EINVAL, session->r, "HTTP2-Settings header missing in request"); return APR_EINVAL; } int cslen = apr_base64_decode_len(s); char *cs = apr_pcalloc(session->r->pool, cslen); --cslen; /* apr also counts the terminating 0 */ apr_base64_decode(cs, s); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, session->r, "upgrading h2c session with nghttp2 from %s (%d)", s, cslen); rv = nghttp2_session_upgrade(session->ngh2, (uint8_t*)cs, cslen, NULL); if (rv != 0) { status = APR_EGENERAL; ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r, "nghttp2_session_upgrade: %s", nghttp2_strerror(rv)); return status; } /* Now we need to auto-open stream 1 for the request we got. */ rv = stream_open(session, 1); if (rv != 0) { status = APR_EGENERAL; ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r, "open stream 1: %s", nghttp2_strerror(rv)); return status; } h2_stream * stream = h2_stream_set_get(session->streams, 1); if (stream == NULL) { status = APR_EGENERAL; ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r, "lookup of stream 1"); return status; } status = h2_stream_rwrite(stream, session->r); if (status != APR_SUCCESS) { return status; } status = stream_end_headers(session, stream, 1); if (status != APR_SUCCESS) { return status; } status = h2_stream_write_eos(stream); if (status != APR_SUCCESS) { return status; } } nghttp2_settings_entry settings[] = { { NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE, h2_config_geti(config, H2_CONF_MAX_HL_SIZE) }, { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, h2_config_geti(config, H2_CONF_WIN_SIZE) }, {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, h2_config_geti(config, H2_CONF_MAX_STREAMS) }, }; rv = nghttp2_submit_settings(session->ngh2, NGHTTP2_FLAG_NONE, settings, sizeof(settings)/sizeof(settings[0])); if (rv != 0) { status = APR_EGENERAL; ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c, "nghttp2_submit_settings: %s", nghttp2_strerror(rv)); } return status; }