mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
mod_http2: new vars, keepalive increase, no slave reuse when con->keepalive not set properly
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1737125 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
6
CHANGES
6
CHANGES
@@ -1,6 +1,12 @@
|
|||||||
-*- coding: utf-8 -*-
|
-*- coding: utf-8 -*-
|
||||||
Changes with Apache 2.5.0
|
Changes with Apache 2.5.0
|
||||||
|
|
||||||
|
*) mod_http2: incrementing keepalives on each request started so that logging
|
||||||
|
%k gives increasing numbers per master http2 connection.
|
||||||
|
New documented variables in env, usable in custom log formats: H2_PUSH,
|
||||||
|
H2_PUSHED, H2_PUSHED_ON, H2_STREAM_ID and H2_STREAM_TAG.
|
||||||
|
[Stefan Eissing]
|
||||||
|
|
||||||
*) core: Do not read .htaccess if AllowOverride and AllowOverrideList
|
*) core: Do not read .htaccess if AllowOverride and AllowOverrideList
|
||||||
are "None". PR 58528.
|
are "None". PR 58528.
|
||||||
[Michael Schlenker <msc contact.de, Rudiger Plum, Daniel Ruggeri]
|
[Michael Schlenker <msc contact.de, Rudiger Plum, Daniel Ruggeri]
|
||||||
|
@@ -166,7 +166,8 @@ Protocols h2 h2c http/1.1
|
|||||||
<section id="envvars"><title>Environment Variables</title>
|
<section id="envvars"><title>Environment Variables</title>
|
||||||
<p>
|
<p>
|
||||||
This module can be configured to provide HTTP/2 related information
|
This module can be configured to provide HTTP/2 related information
|
||||||
as additional environment variables to the SSI and CGI namespace.
|
as additional environment variables to the SSI and CGI namespace, as well
|
||||||
|
as in custom log configurations (see <code>%{VAR_NAME}e</code>).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<table border="1">
|
<table border="1">
|
||||||
@@ -178,7 +179,12 @@ Protocols h2 h2c http/1.1
|
|||||||
<th>Description:</th>
|
<th>Description:</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td><code>HTTP2</code></td><td>flag</td><td>HTTP/2 is being used.</td></tr>
|
<tr><td><code>HTTP2</code></td><td>flag</td><td>HTTP/2 is being used.</td></tr>
|
||||||
<tr><td><code>H2PUSH</code></td><td>flag</td><td>HTTP/2 Server Push is enabled for this request and also supported by the client.</td></tr>
|
<tr><td><code>H2PUSH</code></td><td>flag</td><td>HTTP/2 Server Push is enabled for this connection and also supported by the client.</td></tr>
|
||||||
|
<tr><td><code>H2_PUSH</code></td><td>flag</td><td>alternate name for <code>H2PUSH</code></td></tr>
|
||||||
|
<tr><td><code>H2_PUSHED</code></td><td>string</td><td>empty or <code>PUSHED</code> for a request being pushed by the server.</td></tr>
|
||||||
|
<tr><td><code>H2_PUSHED_ON</code></td><td>number</td><td>HTTP/2 stream number that triggered the push of this request.</td></tr>
|
||||||
|
<tr><td><code>H2_STREAM_ID</code></td><td>number</td><td>HTTP/2 stream number of this request.</td></tr>
|
||||||
|
<tr><td><code>H2_STREAM_TAG</code></td><td>string</td><td>HTTP/2 process unique stream identifier, consisting of connection id and stream id separated by <code>-</code>.</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@@ -117,7 +117,8 @@ typedef struct h2_request h2_request;
|
|||||||
|
|
||||||
struct h2_request {
|
struct h2_request {
|
||||||
int id; /* stream id */
|
int id; /* stream id */
|
||||||
|
int initiated_on; /* initiating stream id (PUSH) or 0 */
|
||||||
|
|
||||||
const char *method; /* pseudo header values, see ch. 8.1.2.3 */
|
const char *method; /* pseudo header values, see ch. 8.1.2.3 */
|
||||||
const char *scheme;
|
const char *scheme;
|
||||||
const char *authority;
|
const char *authority;
|
||||||
|
@@ -65,7 +65,11 @@ h2_ctx *h2_ctx_rget(const request_rec *r)
|
|||||||
|
|
||||||
const char *h2_ctx_protocol_get(const conn_rec *c)
|
const char *h2_ctx_protocol_get(const conn_rec *c)
|
||||||
{
|
{
|
||||||
h2_ctx *ctx = (h2_ctx*)ap_get_module_config(c->conn_config, &http2_module);
|
h2_ctx *ctx;
|
||||||
|
if (c->master) {
|
||||||
|
c = c->master;
|
||||||
|
}
|
||||||
|
ctx = (h2_ctx*)ap_get_module_config(c->conn_config, &http2_module);
|
||||||
return ctx? ctx->protocol : NULL;
|
return ctx? ctx->protocol : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -108,10 +108,16 @@ void h2_io_set_response(h2_io *io, h2_response *response)
|
|||||||
AP_DEBUG_ASSERT(io->pool);
|
AP_DEBUG_ASSERT(io->pool);
|
||||||
AP_DEBUG_ASSERT(response);
|
AP_DEBUG_ASSERT(response);
|
||||||
AP_DEBUG_ASSERT(!io->response);
|
AP_DEBUG_ASSERT(!io->response);
|
||||||
io->response = h2_response_clone(io->pool, response);
|
/* we used to clone the response into the io->pool. But
|
||||||
|
* we have much tighter control over the EOR bucket nowadays,
|
||||||
|
* so just use the instance given */
|
||||||
|
io->response = response;
|
||||||
if (response->rst_error) {
|
if (response->rst_error) {
|
||||||
h2_io_rst(io, response->rst_error);
|
h2_io_rst(io, response->rst_error);
|
||||||
}
|
}
|
||||||
|
else if (response->content_length == 0) {
|
||||||
|
io->eos_out = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void h2_io_rst(h2_io *io, int error)
|
void h2_io_rst(h2_io *io, int error)
|
||||||
@@ -378,16 +384,8 @@ apr_status_t h2_io_out_get_brigade(h2_io *io, apr_bucket_brigade *bb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_trailers(h2_io *io, apr_table_t *trailers)
|
|
||||||
{
|
|
||||||
if (trailers && io->response) {
|
|
||||||
h2_response_set_trailers(io->response,
|
|
||||||
apr_table_clone(io->pool, trailers));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb,
|
apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb,
|
||||||
apr_size_t maxlen, apr_table_t *trailers,
|
apr_size_t maxlen,
|
||||||
apr_size_t *pfile_buckets_allowed)
|
apr_size_t *pfile_buckets_allowed)
|
||||||
{
|
{
|
||||||
apr_status_t status;
|
apr_status_t status;
|
||||||
@@ -415,8 +413,6 @@ apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
process_trailers(io, trailers);
|
|
||||||
|
|
||||||
/* Let's move the buckets from the request processing in here, so
|
/* Let's move the buckets from the request processing in here, so
|
||||||
* that the main thread can read them when it has time/capacity.
|
* that the main thread can read them when it has time/capacity.
|
||||||
*
|
*
|
||||||
@@ -439,13 +435,12 @@ apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
apr_status_t h2_io_out_close(h2_io *io, apr_table_t *trailers)
|
apr_status_t h2_io_out_close(h2_io *io)
|
||||||
{
|
{
|
||||||
if (io->rst_error) {
|
if (io->rst_error) {
|
||||||
return APR_ECONNABORTED;
|
return APR_ECONNABORTED;
|
||||||
}
|
}
|
||||||
if (!io->eos_out_read) { /* EOS has not been read yet */
|
if (!io->eos_out_read) { /* EOS has not been read yet */
|
||||||
process_trailers(io, trailers);
|
|
||||||
if (!io->eos_out) {
|
if (!io->eos_out) {
|
||||||
check_bbout(io);
|
check_bbout(io);
|
||||||
io->eos_out = 1;
|
io->eos_out = 1;
|
||||||
|
@@ -37,7 +37,7 @@ typedef struct h2_io h2_io;
|
|||||||
|
|
||||||
struct h2_io {
|
struct h2_io {
|
||||||
int id; /* stream identifier */
|
int id; /* stream identifier */
|
||||||
apr_pool_t *pool; /* stream pool */
|
apr_pool_t *pool; /* stream pool */
|
||||||
apr_bucket_alloc_t *bucket_alloc;
|
apr_bucket_alloc_t *bucket_alloc;
|
||||||
|
|
||||||
const struct h2_request *request;/* request on this io */
|
const struct h2_request *request;/* request on this io */
|
||||||
@@ -156,14 +156,14 @@ apr_status_t h2_io_out_get_brigade(h2_io *io,
|
|||||||
apr_off_t len);
|
apr_off_t len);
|
||||||
|
|
||||||
apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb,
|
apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb,
|
||||||
apr_size_t maxlen, apr_table_t *trailers,
|
apr_size_t maxlen,
|
||||||
apr_size_t *pfile_buckets_allowed);
|
apr_size_t *pfile_buckets_allowed);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the input. After existing data has been read, APR_EOF will
|
* Closes the input. After existing data has been read, APR_EOF will
|
||||||
* be returned.
|
* be returned.
|
||||||
*/
|
*/
|
||||||
apr_status_t h2_io_out_close(h2_io *io, apr_table_t *trailers);
|
apr_status_t h2_io_out_close(h2_io *io);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gives the overall length of the data that is currently queued for
|
* Gives the overall length of the data that is currently queued for
|
||||||
|
@@ -306,12 +306,13 @@ static void io_destroy(h2_mplx *m, h2_io *io, int events)
|
|||||||
h2_task_destroy(io->task);
|
h2_task_destroy(io->task);
|
||||||
io->task = NULL;
|
io->task = NULL;
|
||||||
|
|
||||||
if (reuse_slave) {
|
if (reuse_slave && slave->keepalive == AP_CONN_KEEPALIVE) {
|
||||||
apr_bucket_delete(io->eor);
|
apr_bucket_delete(io->eor);
|
||||||
io->eor = NULL;
|
io->eor = NULL;
|
||||||
APR_ARRAY_PUSH(m->spare_slaves, conn_rec*) = slave;
|
APR_ARRAY_PUSH(m->spare_slaves, conn_rec*) = slave;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
slave->sbh = NULL;
|
||||||
h2_slave_destroy(slave, NULL);
|
h2_slave_destroy(slave, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -697,7 +698,6 @@ h2_stream *h2_mplx_next_submit(h2_mplx *m, h2_ihash_t *streams)
|
|||||||
static apr_status_t out_write(h2_mplx *m, h2_io *io,
|
static apr_status_t out_write(h2_mplx *m, h2_io *io,
|
||||||
ap_filter_t* f, int blocking,
|
ap_filter_t* f, int blocking,
|
||||||
apr_bucket_brigade *bb,
|
apr_bucket_brigade *bb,
|
||||||
apr_table_t *trailers,
|
|
||||||
struct apr_thread_cond_t *iowait)
|
struct apr_thread_cond_t *iowait)
|
||||||
{
|
{
|
||||||
apr_status_t status = APR_SUCCESS;
|
apr_status_t status = APR_SUCCESS;
|
||||||
@@ -711,7 +711,7 @@ static apr_status_t out_write(h2_mplx *m, h2_io *io,
|
|||||||
&& !is_aborted(m, &status)) {
|
&& !is_aborted(m, &status)) {
|
||||||
|
|
||||||
status = h2_io_out_write(io, bb, blocking? m->stream_max_mem : INT_MAX,
|
status = h2_io_out_write(io, bb, blocking? m->stream_max_mem : INT_MAX,
|
||||||
trailers, &m->tx_handles_reserved);
|
&m->tx_handles_reserved);
|
||||||
io_out_consumed_signal(m, io);
|
io_out_consumed_signal(m, io);
|
||||||
|
|
||||||
/* Wait for data to drain until there is room again or
|
/* Wait for data to drain until there is room again or
|
||||||
@@ -728,7 +728,6 @@ static apr_status_t out_write(h2_mplx *m, h2_io *io,
|
|||||||
m->id, io->id);
|
m->id, io->id);
|
||||||
return APR_INCOMPLETE;
|
return APR_INCOMPLETE;
|
||||||
}
|
}
|
||||||
trailers = NULL;
|
|
||||||
if (f) {
|
if (f) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
|
||||||
"h2_mplx(%ld-%d): waiting for out drain",
|
"h2_mplx(%ld-%d): waiting for out drain",
|
||||||
@@ -766,7 +765,7 @@ static apr_status_t out_open(h2_mplx *m, int stream_id, h2_response *response,
|
|||||||
check_tx_reservation(m);
|
check_tx_reservation(m);
|
||||||
}
|
}
|
||||||
if (bb) {
|
if (bb) {
|
||||||
status = out_write(m, io, f, 0, bb, response->trailers, iowait);
|
status = out_write(m, io, f, 0, bb, iowait);
|
||||||
if (status == APR_INCOMPLETE) {
|
if (status == APR_INCOMPLETE) {
|
||||||
/* write will have transferred as much data as possible.
|
/* write will have transferred as much data as possible.
|
||||||
caller has to deal with non-empty brigade */
|
caller has to deal with non-empty brigade */
|
||||||
@@ -807,7 +806,6 @@ apr_status_t h2_mplx_out_open(h2_mplx *m, int stream_id, h2_response *response,
|
|||||||
apr_status_t h2_mplx_out_write(h2_mplx *m, int stream_id,
|
apr_status_t h2_mplx_out_write(h2_mplx *m, int stream_id,
|
||||||
ap_filter_t* f, int blocking,
|
ap_filter_t* f, int blocking,
|
||||||
apr_bucket_brigade *bb,
|
apr_bucket_brigade *bb,
|
||||||
apr_table_t *trailers,
|
|
||||||
struct apr_thread_cond_t *iowait)
|
struct apr_thread_cond_t *iowait)
|
||||||
{
|
{
|
||||||
apr_status_t status;
|
apr_status_t status;
|
||||||
@@ -817,10 +815,9 @@ apr_status_t h2_mplx_out_write(h2_mplx *m, int stream_id,
|
|||||||
if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) {
|
if ((status = enter_mutex(m, &acquired)) == APR_SUCCESS) {
|
||||||
h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
|
h2_io *io = h2_io_set_get(m->stream_ios, stream_id);
|
||||||
if (io && !io->orphaned) {
|
if (io && !io->orphaned) {
|
||||||
status = out_write(m, io, f, blocking, bb, trailers, iowait);
|
status = out_write(m, io, f, blocking, bb, iowait);
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, m->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, m->c,
|
||||||
"h2_mplx(%ld-%d): write with trailers=%s",
|
"h2_mplx(%ld-%d): write", m->id, io->id);
|
||||||
m->id, io->id, trailers? "yes" : "no");
|
|
||||||
H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_write");
|
H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_write");
|
||||||
|
|
||||||
have_out_data_for(m, stream_id);
|
have_out_data_for(m, stream_id);
|
||||||
@@ -833,7 +830,7 @@ apr_status_t h2_mplx_out_write(h2_mplx *m, int stream_id,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id, apr_table_t *trailers)
|
apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id)
|
||||||
{
|
{
|
||||||
apr_status_t status;
|
apr_status_t status;
|
||||||
int acquired;
|
int acquired;
|
||||||
@@ -855,10 +852,9 @@ apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id, apr_table_t *trailers)
|
|||||||
m->id, io->id);
|
m->id, io->id);
|
||||||
}
|
}
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, m->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, m->c,
|
||||||
"h2_mplx(%ld-%d): close with eor=%s, trailers=%s",
|
"h2_mplx(%ld-%d): close with eor=%s",
|
||||||
m->id, io->id, io->eor? "yes" : "no",
|
m->id, io->id, io->eor? "yes" : "no");
|
||||||
trailers? "yes" : "no");
|
status = h2_io_out_close(io);
|
||||||
status = h2_io_out_close(io, trailers);
|
|
||||||
H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_close");
|
H2_MPLX_IO_OUT(APLOG_TRACE2, m, io, "h2_mplx_out_close");
|
||||||
io_out_consumed_signal(m, io);
|
io_out_consumed_signal(m, io);
|
||||||
|
|
||||||
@@ -987,7 +983,8 @@ static h2_io *open_io(h2_mplx *m, int stream_id, const h2_request *request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
apr_status_t h2_mplx_process(h2_mplx *m, int stream_id, const h2_request *req,
|
apr_status_t h2_mplx_process(h2_mplx *m, int stream_id,
|
||||||
|
const h2_request *req,
|
||||||
h2_stream_pri_cmp *cmp, void *ctx)
|
h2_stream_pri_cmp *cmp, void *ctx)
|
||||||
{
|
{
|
||||||
apr_status_t status;
|
apr_status_t status;
|
||||||
@@ -1048,8 +1045,9 @@ static h2_task *pop_task(h2_mplx *m)
|
|||||||
h2_slave_run_pre_connection(slave, ap_get_conn_socket(slave));
|
h2_slave_run_pre_connection(slave, ap_get_conn_socket(slave));
|
||||||
}
|
}
|
||||||
|
|
||||||
++m->c->keepalives;
|
slave->sbh = m->c->sbh;
|
||||||
io->task = task = h2_task_create(m->id, io->request, slave, m);
|
io->task = task = h2_task_create(m->id, io->request, slave, m);
|
||||||
|
m->c->keepalives++;
|
||||||
apr_table_setn(slave->notes, H2_TASK_ID_NOTE, task->id);
|
apr_table_setn(slave->notes, H2_TASK_ID_NOTE, task->id);
|
||||||
|
|
||||||
io->worker_started = 1;
|
io->worker_started = 1;
|
||||||
@@ -1111,7 +1109,7 @@ static void task_done(h2_mplx *m, h2_task *task, h2_req_engine *ngn)
|
|||||||
/* TODO: this will keep a worker attached to this h2_mplx as
|
/* TODO: this will keep a worker attached to this h2_mplx as
|
||||||
* long as it has requests to handle. Might no be fair to
|
* long as it has requests to handle. Might no be fair to
|
||||||
* other mplx's. Perhaps leave after n requests? */
|
* other mplx's. Perhaps leave after n requests? */
|
||||||
h2_mplx_out_close(m, task->stream_id, NULL);
|
h2_mplx_out_close(m, task->stream_id);
|
||||||
|
|
||||||
if (ngn && io) {
|
if (ngn && io) {
|
||||||
apr_off_t bytes = io->output_consumed + h2_io_out_length(io);
|
apr_off_t bytes = io->output_consumed + h2_io_out_length(io);
|
||||||
|
@@ -190,7 +190,8 @@ apr_status_t h2_mplx_out_trywait(h2_mplx *m, apr_interval_time_t timeout,
|
|||||||
* @param cmp the stream priority compare function
|
* @param cmp the stream priority compare function
|
||||||
* @param ctx context data for the compare function
|
* @param ctx context data for the compare function
|
||||||
*/
|
*/
|
||||||
apr_status_t h2_mplx_process(h2_mplx *m, int stream_id, const struct h2_request *r,
|
apr_status_t h2_mplx_process(h2_mplx *m, int stream_id,
|
||||||
|
const struct h2_request *r,
|
||||||
h2_stream_pri_cmp *cmp, void *ctx);
|
h2_stream_pri_cmp *cmp, void *ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -289,21 +290,18 @@ apr_status_t h2_mplx_out_open(h2_mplx *mplx, int stream_id,
|
|||||||
* @param blocking == 0 iff call should return with APR_INCOMPLETE if
|
* @param blocking == 0 iff call should return with APR_INCOMPLETE if
|
||||||
* the full brigade cannot be written at once
|
* the full brigade cannot be written at once
|
||||||
* @param bb the bucket brigade to append
|
* @param bb the bucket brigade to append
|
||||||
* @param trailers optional trailers for response, maybe NULL
|
|
||||||
* @param iowait a conditional used for block/signalling in h2_mplx
|
* @param iowait a conditional used for block/signalling in h2_mplx
|
||||||
*/
|
*/
|
||||||
apr_status_t h2_mplx_out_write(h2_mplx *mplx, int stream_id,
|
apr_status_t h2_mplx_out_write(h2_mplx *mplx, int stream_id,
|
||||||
ap_filter_t* filter,
|
ap_filter_t* filter,
|
||||||
int blocking,
|
int blocking,
|
||||||
apr_bucket_brigade *bb,
|
apr_bucket_brigade *bb,
|
||||||
apr_table_t *trailers,
|
|
||||||
struct apr_thread_cond_t *iowait);
|
struct apr_thread_cond_t *iowait);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the output for stream stream_id. Optionally forwards trailers
|
* Closes the output for stream stream_id.
|
||||||
* fromt the processed stream.
|
|
||||||
*/
|
*/
|
||||||
apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id, apr_table_t *trailers);
|
apr_status_t h2_mplx_out_close(h2_mplx *m, int stream_id);
|
||||||
|
|
||||||
apr_status_t h2_mplx_out_rst(h2_mplx *m, int stream_id, int error);
|
apr_status_t h2_mplx_out_rst(h2_mplx *m, int stream_id, int error);
|
||||||
|
|
||||||
|
@@ -342,6 +342,7 @@ apr_status_t h2_request_add_trailer(h2_request *req, apr_pool_t *pool,
|
|||||||
void h2_request_copy(apr_pool_t *p, h2_request *dst, const h2_request *src)
|
void h2_request_copy(apr_pool_t *p, h2_request *dst, const h2_request *src)
|
||||||
{
|
{
|
||||||
/* keep the dst id */
|
/* keep the dst id */
|
||||||
|
dst->initiated_on = src->initiated_on;
|
||||||
dst->method = OPT_COPY(p, src->method);
|
dst->method = OPT_COPY(p, src->method);
|
||||||
dst->scheme = OPT_COPY(p, src->scheme);
|
dst->scheme = OPT_COPY(p, src->scheme);
|
||||||
dst->authority = OPT_COPY(p, src->authority);
|
dst->authority = OPT_COPY(p, src->authority);
|
||||||
@@ -350,9 +351,15 @@ void h2_request_copy(apr_pool_t *p, h2_request *dst, const h2_request *src)
|
|||||||
if (src->trailers) {
|
if (src->trailers) {
|
||||||
dst->trailers = apr_table_clone(p, src->trailers);
|
dst->trailers = apr_table_clone(p, src->trailers);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
dst->trailers = NULL;
|
||||||
|
}
|
||||||
dst->content_length = src->content_length;
|
dst->content_length = src->content_length;
|
||||||
dst->chunked = src->chunked;
|
dst->chunked = src->chunked;
|
||||||
dst->eoh = src->eoh;
|
dst->eoh = src->eoh;
|
||||||
|
dst->body = src->body;
|
||||||
|
dst->serialize = src->serialize;
|
||||||
|
dst->push_policy = src->push_policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2_request *h2_request_clone(apr_pool_t *p, const h2_request *src)
|
h2_request *h2_request_clone(apr_pool_t *p, const h2_request *src)
|
||||||
|
@@ -70,6 +70,28 @@ static const char *get_sos_filter(apr_table_t *notes)
|
|||||||
return notes? apr_table_get(notes, H2_RESP_SOS_NOTE) : NULL;
|
return notes? apr_table_get(notes, H2_RESP_SOS_NOTE) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void check_clen(h2_response *response, request_rec *r, apr_pool_t *pool)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (r && r->header_only) {
|
||||||
|
response->content_length = 0;
|
||||||
|
}
|
||||||
|
else if (response->headers) {
|
||||||
|
const char *s = apr_table_get(response->headers, "Content-Length");
|
||||||
|
if (s) {
|
||||||
|
char *end;
|
||||||
|
response->content_length = apr_strtoi64(s, &end, 10);
|
||||||
|
if (s == end) {
|
||||||
|
ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL,
|
||||||
|
pool, APLOGNO(02956)
|
||||||
|
"h2_response: content-length"
|
||||||
|
" value not parsed: %s", s);
|
||||||
|
response->content_length = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static h2_response *h2_response_create_int(int stream_id,
|
static h2_response *h2_response_create_int(int stream_id,
|
||||||
int rst_error,
|
int rst_error,
|
||||||
int http_status,
|
int http_status,
|
||||||
@@ -78,7 +100,6 @@ static h2_response *h2_response_create_int(int stream_id,
|
|||||||
apr_pool_t *pool)
|
apr_pool_t *pool)
|
||||||
{
|
{
|
||||||
h2_response *response;
|
h2_response *response;
|
||||||
const char *s;
|
|
||||||
|
|
||||||
if (!headers) {
|
if (!headers) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -96,19 +117,7 @@ static h2_response *h2_response_create_int(int stream_id,
|
|||||||
response->headers = headers;
|
response->headers = headers;
|
||||||
response->sos_filter = get_sos_filter(notes);
|
response->sos_filter = get_sos_filter(notes);
|
||||||
|
|
||||||
s = apr_table_get(headers, "Content-Length");
|
check_clen(response, NULL, pool);
|
||||||
if (s) {
|
|
||||||
char *end;
|
|
||||||
|
|
||||||
response->content_length = apr_strtoi64(s, &end, 10);
|
|
||||||
if (s == end) {
|
|
||||||
ap_log_perror(APLOG_MARK, APLOG_WARNING, APR_EINVAL,
|
|
||||||
pool, APLOGNO(02956)
|
|
||||||
"h2_response: content-length"
|
|
||||||
" value not parsed: %s", s);
|
|
||||||
response->content_length = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,6 +147,8 @@ h2_response *h2_response_rcreate(int stream_id, request_rec *r,
|
|||||||
response->headers = header;
|
response->headers = header;
|
||||||
response->sos_filter = get_sos_filter(r->notes);
|
response->sos_filter = get_sos_filter(r->notes);
|
||||||
|
|
||||||
|
check_clen(response, r, pool);
|
||||||
|
|
||||||
if (response->http_status == HTTP_FORBIDDEN) {
|
if (response->http_status == HTTP_FORBIDDEN) {
|
||||||
const char *cause = apr_table_get(r->notes, "ssl-renegotiate-forbidden");
|
const char *cause = apr_table_get(r->notes, "ssl-renegotiate-forbidden");
|
||||||
if (cause) {
|
if (cause) {
|
||||||
|
@@ -491,7 +491,7 @@ static int on_frame_recv_cb(nghttp2_session *ng2s,
|
|||||||
session->id, (int)frame->hd.stream_id,
|
session->id, (int)frame->hd.stream_id,
|
||||||
(int)frame->rst_stream.error_code);
|
(int)frame->rst_stream.error_code);
|
||||||
stream = h2_session_get_stream(session, frame->hd.stream_id);
|
stream = h2_session_get_stream(session, frame->hd.stream_id);
|
||||||
if (stream && stream->initiated_on) {
|
if (stream && stream->request && stream->request->initiated_on) {
|
||||||
++session->pushes_reset;
|
++session->pushes_reset;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1270,18 +1270,21 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream)
|
|||||||
rv = NGHTTP2_PROTOCOL_ERROR;
|
rv = NGHTTP2_PROTOCOL_ERROR;
|
||||||
}
|
}
|
||||||
else if (response && response->headers) {
|
else if (response && response->headers) {
|
||||||
nghttp2_data_provider provider;
|
nghttp2_data_provider provider, *pprovider = NULL;
|
||||||
h2_ngheader *ngh;
|
h2_ngheader *ngh;
|
||||||
const h2_priority *prio;
|
const h2_priority *prio;
|
||||||
|
|
||||||
memset(&provider, 0, sizeof(provider));
|
|
||||||
provider.source.fd = stream->id;
|
|
||||||
provider.read_callback = stream_data_cb;
|
|
||||||
|
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03073)
|
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03073)
|
||||||
"h2_stream(%ld-%d): submit response %d",
|
"h2_stream(%ld-%d): submit response %d",
|
||||||
session->id, stream->id, response->http_status);
|
session->id, stream->id, response->http_status);
|
||||||
|
|
||||||
|
if (response->content_length != 0) {
|
||||||
|
memset(&provider, 0, sizeof(provider));
|
||||||
|
provider.source.fd = stream->id;
|
||||||
|
provider.read_callback = stream_data_cb;
|
||||||
|
pprovider = &provider;
|
||||||
|
}
|
||||||
|
|
||||||
/* If this stream is not a pushed one itself,
|
/* If this stream is not a pushed one itself,
|
||||||
* and HTTP/2 server push is enabled here,
|
* and HTTP/2 server push is enabled here,
|
||||||
* and the response is in the range 200-299 *),
|
* and the response is in the range 200-299 *),
|
||||||
@@ -1297,7 +1300,7 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream)
|
|||||||
* as the client, having this resource in its cache, might
|
* as the client, having this resource in its cache, might
|
||||||
* also have the pushed ones as well.
|
* also have the pushed ones as well.
|
||||||
*/
|
*/
|
||||||
if (!stream->initiated_on
|
if (stream->request && !stream->request->initiated_on
|
||||||
&& H2_HTTP_2XX(response->http_status)
|
&& H2_HTTP_2XX(response->http_status)
|
||||||
&& h2_session_push_enabled(session)) {
|
&& h2_session_push_enabled(session)) {
|
||||||
|
|
||||||
@@ -1313,7 +1316,7 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream)
|
|||||||
ngh = h2_util_ngheader_make_res(stream->pool, response->http_status,
|
ngh = h2_util_ngheader_make_res(stream->pool, response->http_status,
|
||||||
response->headers);
|
response->headers);
|
||||||
rv = nghttp2_submit_response(session->ngh2, response->stream_id,
|
rv = nghttp2_submit_response(session->ngh2, response->stream_id,
|
||||||
ngh->nv, ngh->nvlen, &provider);
|
ngh->nv, ngh->nvlen, pprovider);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int err = H2_STREAM_RST(stream, H2_ERR_PROTOCOL_ERROR);
|
int err = H2_STREAM_RST(stream, H2_ERR_PROTOCOL_ERROR);
|
||||||
@@ -1327,7 +1330,7 @@ static apr_status_t submit_response(h2_session *session, h2_stream *stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
stream->submitted = 1;
|
stream->submitted = 1;
|
||||||
if (stream->initiated_on) {
|
if (stream->request && stream->request->initiated_on) {
|
||||||
++session->pushes_submitted;
|
++session->pushes_submitted;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@@ -235,7 +235,7 @@ void h2_stream_set_h2_request(h2_stream *stream, int initiated_on,
|
|||||||
const h2_request *req)
|
const h2_request *req)
|
||||||
{
|
{
|
||||||
h2_request_copy(stream->pool, stream->request, req);
|
h2_request_copy(stream->pool, stream->request, req);
|
||||||
stream->initiated_on = initiated_on;
|
stream->request->initiated_on = initiated_on;
|
||||||
stream->request->eoh = 0;
|
stream->request->eoh = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,7 +476,7 @@ const h2_priority *h2_stream_get_priority(h2_stream *stream)
|
|||||||
{
|
{
|
||||||
h2_response *response = h2_stream_get_response(stream);
|
h2_response *response = h2_stream_get_response(stream);
|
||||||
|
|
||||||
if (stream->initiated_on && response) {
|
if (response && stream->request && stream->request->initiated_on) {
|
||||||
const char *ctype = apr_table_get(response->headers, "content-type");
|
const char *ctype = apr_table_get(response->headers, "content-type");
|
||||||
if (ctype) {
|
if (ctype) {
|
||||||
/* FIXME: Not good enough, config needs to come from request->server */
|
/* FIXME: Not good enough, config needs to come from request->server */
|
||||||
|
@@ -43,7 +43,6 @@ typedef struct h2_stream h2_stream;
|
|||||||
|
|
||||||
struct h2_stream {
|
struct h2_stream {
|
||||||
int id; /* http2 stream id */
|
int id; /* http2 stream id */
|
||||||
int initiated_on; /* http2 stream id this was initiated on or 0 */
|
|
||||||
h2_stream_state_t state; /* http/2 state of this stream */
|
h2_stream_state_t state; /* http/2 state of this stream */
|
||||||
struct h2_session *session; /* the session this stream belongs to */
|
struct h2_session *session; /* the session this stream belongs to */
|
||||||
|
|
||||||
|
@@ -135,7 +135,7 @@ h2_task *h2_task_create(long session_id, const h2_request *req,
|
|||||||
ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, c,
|
ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOMEM, c,
|
||||||
APLOGNO(02941) "h2_task(%ld-%d): create stream task",
|
APLOGNO(02941) "h2_task(%ld-%d): create stream task",
|
||||||
session_id, req->id);
|
session_id, req->id);
|
||||||
h2_mplx_out_close(mplx, req->id, NULL);
|
h2_mplx_out_close(mplx, req->id);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -45,23 +45,6 @@ h2_task_output *h2_task_output_create(h2_task *task, conn_rec *c)
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
static apr_table_t *get_trailers(h2_task_output *output)
|
|
||||||
{
|
|
||||||
if (!output->trailers_passed) {
|
|
||||||
h2_response *response = h2_from_h1_get_response(output->from_h1);
|
|
||||||
if (response && response->trailers) {
|
|
||||||
output->trailers_passed = 1;
|
|
||||||
if (h2_task_logio_add_bytes_out) {
|
|
||||||
/* counter trailers as if we'd do a HTTP/1.1 serialization */
|
|
||||||
h2_task_logio_add_bytes_out(output->task->c,
|
|
||||||
h2_util_table_bytes(response->trailers, 3)+1);
|
|
||||||
}
|
|
||||||
return response->trailers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static apr_status_t open_response(h2_task_output *output, ap_filter_t *f,
|
static apr_status_t open_response(h2_task_output *output, ap_filter_t *f,
|
||||||
apr_bucket_brigade *bb, const char *caller)
|
apr_bucket_brigade *bb, const char *caller)
|
||||||
{
|
{
|
||||||
@@ -71,7 +54,7 @@ static apr_status_t open_response(h2_task_output *output, ap_filter_t *f,
|
|||||||
if (f) {
|
if (f) {
|
||||||
/* This happens currently when ap_die(status, r) is invoked
|
/* This happens currently when ap_die(status, r) is invoked
|
||||||
* by a read request filter. */
|
* by a read request filter. */
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, output->task->c, APLOGNO(03204)
|
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, output->task->c, APLOGNO(03204)
|
||||||
"h2_task_output(%s): write without response by %s "
|
"h2_task_output(%s): write without response by %s "
|
||||||
"for %s %s %s",
|
"for %s %s %s",
|
||||||
output->task->id, caller,
|
output->task->id, caller,
|
||||||
@@ -91,7 +74,6 @@ static apr_status_t open_response(h2_task_output *output, ap_filter_t *f,
|
|||||||
output->written = h2_util_table_bytes(response->headers, 3)+1;
|
output->written = h2_util_table_bytes(response->headers, 3)+1;
|
||||||
h2_task_logio_add_bytes_out(output->task->c, output->written);
|
h2_task_logio_add_bytes_out(output->task->c, output->written);
|
||||||
}
|
}
|
||||||
get_trailers(output);
|
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, output->task->c, APLOGNO(03348)
|
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, output->task->c, APLOGNO(03348)
|
||||||
"h2_task(%s): open response to %s %s %s",
|
"h2_task(%s): open response to %s %s %s",
|
||||||
output->task->id, output->task->request->method,
|
output->task->id, output->task->request->method,
|
||||||
@@ -113,8 +95,7 @@ static apr_status_t write_brigade_raw(h2_task_output *output,
|
|||||||
output->task->id, (long)written);
|
output->task->id, (long)written);
|
||||||
|
|
||||||
status = h2_mplx_out_write(output->task->mplx, output->task->stream_id,
|
status = h2_mplx_out_write(output->task->mplx, output->task->stream_id,
|
||||||
f, output->task->blocking, bb,
|
f, output->task->blocking, bb, output->task->io);
|
||||||
get_trailers(output), output->task->io);
|
|
||||||
if (status == APR_INCOMPLETE) {
|
if (status == APR_INCOMPLETE) {
|
||||||
apr_brigade_length(bb, 0, &left);
|
apr_brigade_length(bb, 0, &left);
|
||||||
written -= left;
|
written -= left;
|
||||||
|
@@ -33,7 +33,6 @@ struct h2_task_output {
|
|||||||
struct h2_from_h1 *from_h1;
|
struct h2_from_h1 *from_h1;
|
||||||
|
|
||||||
unsigned int response_open : 1;
|
unsigned int response_open : 1;
|
||||||
unsigned int trailers_passed : 1;
|
|
||||||
|
|
||||||
apr_off_t written;
|
apr_off_t written;
|
||||||
apr_bucket_brigade *bb;
|
apr_bucket_brigade *bb;
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include <apr_optional.h>
|
#include <apr_optional.h>
|
||||||
#include <apr_optional_hooks.h>
|
#include <apr_optional_hooks.h>
|
||||||
|
#include <apr_strings.h>
|
||||||
#include <apr_time.h>
|
#include <apr_time.h>
|
||||||
#include <apr_want.h>
|
#include <apr_want.h>
|
||||||
|
|
||||||
@@ -198,36 +199,83 @@ static void h2_hooks(apr_pool_t *pool)
|
|||||||
ap_hook_handler(h2_filter_h2_status_handler, NULL, NULL, APR_HOOK_MIDDLE);
|
ap_hook_handler(h2_filter_h2_status_handler, NULL, NULL, APR_HOOK_MIDDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *value_of_HTTP2(apr_pool_t *p, server_rec *s,
|
static const char *val_HTTP2(apr_pool_t *p, server_rec *s,
|
||||||
conn_rec *c, request_rec *r)
|
conn_rec *c, request_rec *r, h2_ctx *ctx)
|
||||||
{
|
{
|
||||||
return c && http2_is_h2(c)? "on" : "off";
|
return ctx? "on" : "off";
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *value_of_H2PUSH(apr_pool_t *p, server_rec *s,
|
static const char *val_H2_PUSH(apr_pool_t *p, server_rec *s,
|
||||||
conn_rec *c, request_rec *r)
|
conn_rec *c, request_rec *r, h2_ctx *ctx)
|
||||||
{
|
{
|
||||||
h2_ctx *ctx;
|
if (ctx) {
|
||||||
if (r) {
|
if (r) {
|
||||||
ctx = h2_ctx_rget(r);
|
|
||||||
if (ctx) {
|
|
||||||
h2_task *task = h2_ctx_get_task(ctx);
|
h2_task *task = h2_ctx_get_task(ctx);
|
||||||
return (task && task->request->push_policy != H2_PUSH_NONE)? "on" : "off";
|
if (task && task->request->push_policy != H2_PUSH_NONE) {
|
||||||
|
return "on";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c && h2_session_push_enabled(ctx->session)) {
|
||||||
|
return "on";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (c) {
|
|
||||||
ctx = h2_ctx_get(c, 0);
|
|
||||||
return ctx && h2_session_push_enabled(ctx->session)? "on" : "off";
|
|
||||||
}
|
}
|
||||||
else if (s) {
|
else if (s) {
|
||||||
const h2_config *cfg = h2_config_sget(s);
|
const h2_config *cfg = h2_config_sget(s);
|
||||||
return cfg && h2_config_geti(cfg, H2_CONF_PUSH)? "on" : "off";
|
if (cfg && h2_config_geti(cfg, H2_CONF_PUSH)) {
|
||||||
|
return "on";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return "off";
|
return "off";
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef char *h2_var_lookup(apr_pool_t *p, server_rec *s,
|
static const char *val_H2_PUSHED(apr_pool_t *p, server_rec *s,
|
||||||
conn_rec *c, request_rec *r);
|
conn_rec *c, request_rec *r, h2_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (ctx) {
|
||||||
|
h2_task *task = h2_ctx_get_task(ctx);
|
||||||
|
if (task && !H2_STREAM_CLIENT_INITIATED(task->stream_id)) {
|
||||||
|
return "PUSHED";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *val_H2_PUSHED_ON(apr_pool_t *p, server_rec *s,
|
||||||
|
conn_rec *c, request_rec *r, h2_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (ctx) {
|
||||||
|
h2_task *task = h2_ctx_get_task(ctx);
|
||||||
|
if (task && !H2_STREAM_CLIENT_INITIATED(task->stream_id)) {
|
||||||
|
return apr_itoa(p, task->request->initiated_on);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *val_H2_STREAM_TAG(apr_pool_t *p, server_rec *s,
|
||||||
|
conn_rec *c, request_rec *r, h2_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (ctx) {
|
||||||
|
h2_task *task = h2_ctx_get_task(ctx);
|
||||||
|
if (task) {
|
||||||
|
return task->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *val_H2_STREAM_ID(apr_pool_t *p, server_rec *s,
|
||||||
|
conn_rec *c, request_rec *r, h2_ctx *ctx)
|
||||||
|
{
|
||||||
|
const char *cp = val_H2_STREAM_TAG(p, s, c, r, ctx);
|
||||||
|
if (cp && (cp = ap_strchr_c(cp, '-'))) {
|
||||||
|
return ++cp;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef const char *h2_var_lookup(apr_pool_t *p, server_rec *s,
|
||||||
|
conn_rec *c, request_rec *r, h2_ctx *ctx);
|
||||||
typedef struct h2_var_def {
|
typedef struct h2_var_def {
|
||||||
const char *name;
|
const char *name;
|
||||||
h2_var_lookup *lookup;
|
h2_var_lookup *lookup;
|
||||||
@@ -235,8 +283,13 @@ typedef struct h2_var_def {
|
|||||||
} h2_var_def;
|
} h2_var_def;
|
||||||
|
|
||||||
static h2_var_def H2_VARS[] = {
|
static h2_var_def H2_VARS[] = {
|
||||||
{ "HTTP2", value_of_HTTP2, 1 },
|
{ "HTTP2", val_HTTP2, 1 },
|
||||||
{ "H2PUSH", value_of_H2PUSH, 1 },
|
{ "H2PUSH", val_H2_PUSH, 1 },
|
||||||
|
{ "H2_PUSH", val_H2_PUSH, 1 },
|
||||||
|
{ "H2_PUSHED", val_H2_PUSHED, 1 },
|
||||||
|
{ "H2_PUSHED_ON", val_H2_PUSHED_ON, 1 },
|
||||||
|
{ "H2_STREAM_ID", val_H2_STREAM_ID, 1 },
|
||||||
|
{ "H2_STREAM_TAG", val_H2_STREAM_TAG, 1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef H2_ALEN
|
#ifndef H2_ALEN
|
||||||
@@ -257,7 +310,9 @@ static char *http2_var_lookup(apr_pool_t *p, server_rec *s,
|
|||||||
for (i = 0; i < H2_ALEN(H2_VARS); ++i) {
|
for (i = 0; i < H2_ALEN(H2_VARS); ++i) {
|
||||||
h2_var_def *vdef = &H2_VARS[i];
|
h2_var_def *vdef = &H2_VARS[i];
|
||||||
if (!strcmp(vdef->name, name)) {
|
if (!strcmp(vdef->name, name)) {
|
||||||
return vdef->lookup(p, s, c, r);
|
h2_ctx *ctx = (r? h2_ctx_rget(r) :
|
||||||
|
h2_ctx_get(c->master? c->master : c, 0));
|
||||||
|
return (char *)vdef->lookup(p, s, c, r, ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
@@ -273,7 +328,8 @@ static int h2_h2_fixups(request_rec *r)
|
|||||||
h2_var_def *vdef = &H2_VARS[i];
|
h2_var_def *vdef = &H2_VARS[i];
|
||||||
if (vdef->subprocess) {
|
if (vdef->subprocess) {
|
||||||
apr_table_setn(r->subprocess_env, vdef->name,
|
apr_table_setn(r->subprocess_env, vdef->name,
|
||||||
vdef->lookup(r->pool, r->server, r->connection, r));
|
vdef->lookup(r->pool, r->server, r->connection,
|
||||||
|
r, ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user