mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
mod_http2: support for intermediate responses
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1755323 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
3
CHANGES
3
CHANGES
@@ -1,6 +1,9 @@
|
|||||||
-*- coding: utf-8 -*-
|
-*- coding: utf-8 -*-
|
||||||
Changes with Apache 2.5.0
|
Changes with Apache 2.5.0
|
||||||
|
|
||||||
|
*) mod_http2: adding support for intermediate responses.
|
||||||
|
[Stefan Eissing]
|
||||||
|
|
||||||
*) mod_reqtimeout: Fix body timeout disabling for CONNECT requests to avoid
|
*) mod_reqtimeout: Fix body timeout disabling for CONNECT requests to avoid
|
||||||
triggering mod_proxy_connect's AH01018 once the tunnel is established.
|
triggering mod_proxy_connect's AH01018 once the tunnel is established.
|
||||||
[Yann Ylavic]
|
[Yann Ylavic]
|
||||||
|
@@ -146,6 +146,8 @@ struct h2_response {
|
|||||||
apr_off_t content_length;
|
apr_off_t content_length;
|
||||||
apr_table_t *headers;
|
apr_table_t *headers;
|
||||||
apr_table_t *trailers;
|
apr_table_t *trailers;
|
||||||
|
struct h2_response *next;
|
||||||
|
|
||||||
const char *sos_filter;
|
const char *sos_filter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -471,7 +471,8 @@ static h2_response *create_response(h2_from_h1 *from_h1, request_rec *r)
|
|||||||
(void *) headers, r->headers_out, NULL);
|
(void *) headers, r->headers_out, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return h2_response_rcreate(from_h1->stream_id, r, headers, r->pool);
|
return h2_response_rcreate(from_h1->stream_id, r, r->status,
|
||||||
|
headers, r->pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t h2_response_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
|
apr_status_t h2_response_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
|
||||||
|
@@ -196,12 +196,17 @@ static int purge_stream(void *ctx, void *val)
|
|||||||
{
|
{
|
||||||
h2_mplx *m = ctx;
|
h2_mplx *m = ctx;
|
||||||
h2_stream *stream = val;
|
h2_stream *stream = val;
|
||||||
h2_task *task = h2_ihash_get(m->tasks, stream->id);
|
int stream_id = stream->id;
|
||||||
h2_ihash_remove(m->spurge, stream->id);
|
h2_task *task = h2_ihash_get(m->tasks, stream_id);
|
||||||
|
|
||||||
|
h2_ihash_remove(m->spurge, stream_id);
|
||||||
h2_stream_destroy(stream);
|
h2_stream_destroy(stream);
|
||||||
if (task) {
|
if (task) {
|
||||||
task_destroy(m, task, 1);
|
task_destroy(m, task, 1);
|
||||||
}
|
}
|
||||||
|
/* FIXME: task_destroy() might in some twisted way place the
|
||||||
|
* stream in the spurge hash again. Remove it last. */
|
||||||
|
h2_ihash_remove(m->spurge, stream_id);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +217,7 @@ static void purge_streams(h2_mplx *m)
|
|||||||
/* repeat until empty */
|
/* repeat until empty */
|
||||||
}
|
}
|
||||||
h2_ihash_clear(m->spurge);
|
h2_ihash_clear(m->spurge);
|
||||||
|
AP_DEBUG_ASSERT(h2_ihash_empty(m->spurge));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,13 +510,13 @@ static int task_print(void *ctx, void *val)
|
|||||||
|
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, /* NO APLOGNO */
|
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, /* NO APLOGNO */
|
||||||
"->03198: h2_stream(%s): %s %s %s -> %s %d"
|
"->03198: h2_stream(%s): %s %s %s -> %s %d"
|
||||||
"[orph=%d/started=%d/done=%d]",
|
"[orph=%d/started=%d/done=%d/frozen=%d]",
|
||||||
task->id, task->request->method,
|
task->id, task->request->method,
|
||||||
task->request->authority, task->request->path,
|
task->request->authority, task->request->path,
|
||||||
task->response? "http" : (task->rst_error? "reset" : "?"),
|
task->response? "http" : (task->rst_error? "reset" : "?"),
|
||||||
task->response? task->response->http_status : task->rst_error,
|
task->response? task->response->http_status : task->rst_error,
|
||||||
(stream? 0 : 1), task->worker_started,
|
(stream? 0 : 1), task->worker_started,
|
||||||
task->worker_done);
|
task->worker_done, task->frozen);
|
||||||
}
|
}
|
||||||
else if (task) {
|
else if (task) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, /* NO APLOGNO */
|
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, m->c, /* NO APLOGNO */
|
||||||
@@ -593,8 +599,11 @@ apr_status_t h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait)
|
|||||||
|
|
||||||
if (!h2_ihash_empty(m->shold)) {
|
if (!h2_ihash_empty(m->shold)) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
||||||
"h2_mplx(%ld): 2. release_join with %d streams in hold",
|
"h2_mplx(%ld): 2. release_join with %d streams in "
|
||||||
m->id, (int)h2_ihash_count(m->shold));
|
"hold, %d workers busy, %d tasks",
|
||||||
|
m->id, (int)h2_ihash_count(m->shold),
|
||||||
|
m->workers_busy,
|
||||||
|
(int)h2_ihash_count(m->tasks));
|
||||||
}
|
}
|
||||||
if (!h2_ihash_empty(m->spurge)) {
|
if (!h2_ihash_empty(m->spurge)) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
||||||
@@ -635,6 +644,12 @@ apr_status_t h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!h2_ihash_empty(m->tasks) && APLOGctrace1(m->c)) {
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
|
||||||
|
"h2_mplx(%ld): 3. release_join with %d tasks",
|
||||||
|
m->id, (int)h2_ihash_count(m->tasks));
|
||||||
|
h2_ihash_iter(m->tasks, task_print, m);
|
||||||
|
}
|
||||||
AP_DEBUG_ASSERT(h2_ihash_empty(m->shold));
|
AP_DEBUG_ASSERT(h2_ihash_empty(m->shold));
|
||||||
if (!h2_ihash_empty(m->spurge)) {
|
if (!h2_ihash_empty(m->spurge)) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c,
|
||||||
@@ -642,7 +657,6 @@ apr_status_t h2_mplx_release_and_join(h2_mplx *m, apr_thread_cond_t *wait)
|
|||||||
m->id, (int)h2_ihash_count(m->spurge));
|
m->id, (int)h2_ihash_count(m->spurge));
|
||||||
purge_streams(m);
|
purge_streams(m);
|
||||||
}
|
}
|
||||||
AP_DEBUG_ASSERT(h2_ihash_empty(m->spurge));
|
|
||||||
|
|
||||||
if (!h2_ihash_empty(m->tasks)) {
|
if (!h2_ihash_empty(m->tasks)) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c, APLOGNO(03056)
|
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, m->c, APLOGNO(03056)
|
||||||
@@ -702,13 +716,15 @@ static apr_status_t out_open(h2_mplx *m, int stream_id, h2_response *response)
|
|||||||
return APR_ECONNABORTED;
|
return APR_ECONNABORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, m->c,
|
status = h2_task_add_response(task, response);
|
||||||
"h2_mplx(%s): open response: %d, rst=%d",
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, m->c,
|
||||||
|
"h2_mplx(%s): add response: %d, rst=%d",
|
||||||
task->id, response->http_status, response->rst_error);
|
task->id, response->http_status, response->rst_error);
|
||||||
|
if (status != APR_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
h2_task_set_response(task, response);
|
if (task->output.beam && !task->output.opened) {
|
||||||
|
|
||||||
if (task->output.beam) {
|
|
||||||
h2_beam_buffer_size_set(task->output.beam, m->stream_max_mem);
|
h2_beam_buffer_size_set(task->output.beam, m->stream_max_mem);
|
||||||
h2_beam_timeout_set(task->output.beam, m->stream_timeout);
|
h2_beam_timeout_set(task->output.beam, m->stream_timeout);
|
||||||
h2_beam_on_consumed(task->output.beam, stream_output_consumed, task);
|
h2_beam_on_consumed(task->output.beam, stream_output_consumed, task);
|
||||||
@@ -717,6 +733,7 @@ static apr_status_t out_open(h2_mplx *m, int stream_id, h2_response *response)
|
|||||||
h2_beam_on_file_beam(task->output.beam, can_beam_file, m);
|
h2_beam_on_file_beam(task->output.beam, can_beam_file, m);
|
||||||
}
|
}
|
||||||
h2_beam_mutex_set(task->output.beam, beam_enter, task->cond, m);
|
h2_beam_mutex_set(task->output.beam, beam_enter, task->cond, m);
|
||||||
|
task->output.opened = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2_ihash_add(m->sready, stream);
|
h2_ihash_add(m->sready, stream);
|
||||||
@@ -1402,13 +1419,21 @@ apr_status_t h2_mplx_dispatch_master_events(h2_mplx *m,
|
|||||||
m->id, stream->id);
|
m->id, stream->id);
|
||||||
task = h2_ihash_get(m->tasks, stream->id);
|
task = h2_ihash_get(m->tasks, stream->id);
|
||||||
if (task) {
|
if (task) {
|
||||||
task->submitted = 1;
|
task->response_sent = 1;
|
||||||
if (task->rst_error) {
|
if (task->rst_error) {
|
||||||
h2_stream_rst(stream, task->rst_error);
|
h2_stream_rst(stream, task->rst_error);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
AP_DEBUG_ASSERT(task->response);
|
AP_DEBUG_ASSERT(task->response);
|
||||||
h2_stream_set_response(stream, task->response, task->output.beam);
|
status = h2_stream_add_response(stream, task->response,
|
||||||
|
task->output.beam);
|
||||||
|
if (status != APR_SUCCESS) {
|
||||||
|
h2_stream_rst(stream, H2_ERR_INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
if (!h2_response_get_final(task->response)) {
|
||||||
|
/* the final response needs still to arrive */
|
||||||
|
task->response = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1476,7 +1501,7 @@ apr_status_t h2_mplx_suspend_stream(h2_mplx *m, int stream_id)
|
|||||||
if (stream->started && (!task || task->worker_done)) {
|
if (stream->started && (!task || task->worker_done)) {
|
||||||
h2_ihash_add(m->sresume, stream);
|
h2_ihash_add(m->sresume, stream);
|
||||||
}
|
}
|
||||||
else {
|
else if (task->output.beam) {
|
||||||
/* register callback so that we can resume on new output */
|
/* register callback so that we can resume on new output */
|
||||||
h2_beam_on_produced(task->output.beam, output_produced, m);
|
h2_beam_on_produced(task->output.beam, output_produced, m);
|
||||||
}
|
}
|
||||||
|
@@ -168,6 +168,12 @@ apr_status_t h2_ngn_shed_push_task(h2_ngn_shed *shed, const char *ngn_type,
|
|||||||
return APR_EOF;
|
return APR_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (task->assigned) {
|
||||||
|
--task->assigned->no_assigned;
|
||||||
|
--task->assigned->no_live;
|
||||||
|
task->assigned = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
ngn = apr_hash_get(shed->ngns, ngn_type, APR_HASH_KEY_STRING);
|
ngn = apr_hash_get(shed->ngns, ngn_type, APR_HASH_KEY_STRING);
|
||||||
if (ngn && !ngn->shutdown) {
|
if (ngn && !ngn->shutdown) {
|
||||||
/* this task will be processed in another thread,
|
/* this task will be processed in another thread,
|
||||||
@@ -178,7 +184,6 @@ apr_status_t h2_ngn_shed_push_task(h2_ngn_shed *shed, const char *ngn_type,
|
|||||||
if (!h2_task_is_detached(task)) {
|
if (!h2_task_is_detached(task)) {
|
||||||
h2_task_freeze(task);
|
h2_task_freeze(task);
|
||||||
}
|
}
|
||||||
/* FIXME: sometimes ngn is garbage, probly alread freed */
|
|
||||||
ngn_add_task(ngn, task);
|
ngn_add_task(ngn, task);
|
||||||
ngn->no_assigned++;
|
ngn->no_assigned++;
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
|
@@ -247,7 +247,8 @@ h2_request *h2_request_clone(apr_pool_t *p, const h2_request *src)
|
|||||||
request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
|
request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
|
||||||
{
|
{
|
||||||
int access_status = HTTP_OK;
|
int access_status = HTTP_OK;
|
||||||
|
const char *expect;
|
||||||
|
|
||||||
request_rec *r = ap_create_request(c);
|
request_rec *r = ap_create_request(c);
|
||||||
|
|
||||||
r->headers_in = apr_table_clone(r->pool, req->headers);
|
r->headers_in = apr_table_clone(r->pool, req->headers);
|
||||||
@@ -281,6 +282,18 @@ request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
|
|||||||
/* we may have switched to another server */
|
/* we may have switched to another server */
|
||||||
r->per_dir_config = r->server->lookup_defaults;
|
r->per_dir_config = r->server->lookup_defaults;
|
||||||
|
|
||||||
|
if (r && ((expect = apr_table_get(r->headers_in, "Expect")) != NULL)
|
||||||
|
&& (expect[0] != '\0')) {
|
||||||
|
if (ap_cstr_casecmp(expect, "100-continue") == 0) {
|
||||||
|
r->expecting_100 = 1;
|
||||||
|
ap_add_input_filter("H2_CONTINUE", NULL, r, c);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r->status = HTTP_EXPECTATION_FAILED;
|
||||||
|
ap_send_error_response(r, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add the HTTP_IN filter here to ensure that ap_discard_request_body
|
* Add the HTTP_IN filter here to ensure that ap_discard_request_body
|
||||||
* called by ap_die and by ap_send_error_response works correctly on
|
* called by ap_die and by ap_send_error_response works correctly on
|
||||||
@@ -304,7 +317,7 @@ request_rec *h2_request_create_rec(const h2_request *req, conn_rec *c)
|
|||||||
r = NULL;
|
r = NULL;
|
||||||
goto traceout;
|
goto traceout;
|
||||||
}
|
}
|
||||||
|
|
||||||
AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method,
|
AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method,
|
||||||
(char *)r->uri, (char *)r->server->defn_name,
|
(char *)r->uri, (char *)r->server->defn_name,
|
||||||
r->status);
|
r->status);
|
||||||
|
@@ -133,7 +133,7 @@ h2_response *h2_response_create(int stream_id,
|
|||||||
parse_headers(hlines, pool), notes, pool);
|
parse_headers(hlines, pool), notes, pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
h2_response *h2_response_rcreate(int stream_id, request_rec *r,
|
h2_response *h2_response_rcreate(int stream_id, request_rec *r, int status,
|
||||||
apr_table_t *header, apr_pool_t *pool)
|
apr_table_t *header, apr_pool_t *pool)
|
||||||
{
|
{
|
||||||
h2_response *response = apr_pcalloc(pool, sizeof(h2_response));
|
h2_response *response = apr_pcalloc(pool, sizeof(h2_response));
|
||||||
@@ -142,7 +142,7 @@ h2_response *h2_response_rcreate(int stream_id, request_rec *r,
|
|||||||
}
|
}
|
||||||
|
|
||||||
response->stream_id = stream_id;
|
response->stream_id = stream_id;
|
||||||
response->http_status = r->status;
|
response->http_status = status;
|
||||||
response->content_length = -1;
|
response->content_length = -1;
|
||||||
response->headers = header;
|
response->headers = header;
|
||||||
response->sos_filter = get_sos_filter(r->notes);
|
response->sos_filter = get_sos_filter(r->notes);
|
||||||
@@ -203,3 +203,17 @@ void h2_response_set_trailers(h2_response *response, apr_table_t *trailers)
|
|||||||
response->trailers = trailers;
|
response->trailers = trailers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int h2_response_is_final(h2_response *response)
|
||||||
|
{
|
||||||
|
return response->http_status >= 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2_response *h2_response_get_final(h2_response *response)
|
||||||
|
{
|
||||||
|
for (/**/; response; response = response->next) {
|
||||||
|
if (h2_response_is_final(response)) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -40,7 +40,7 @@ h2_response *h2_response_create(int stream_id,
|
|||||||
* @param header the headers of the response
|
* @param header the headers of the response
|
||||||
* @param pool the memory pool to use
|
* @param pool the memory pool to use
|
||||||
*/
|
*/
|
||||||
h2_response *h2_response_rcreate(int stream_id, request_rec *r,
|
h2_response *h2_response_rcreate(int stream_id, request_rec *r, int status,
|
||||||
apr_table_t *header, apr_pool_t *pool);
|
apr_table_t *header, apr_pool_t *pool);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,4 +70,7 @@ h2_response *h2_response_clone(apr_pool_t *pool, h2_response *from);
|
|||||||
*/
|
*/
|
||||||
void h2_response_set_trailers(h2_response *response, apr_table_t *trailers);
|
void h2_response_set_trailers(h2_response *response, apr_table_t *trailers);
|
||||||
|
|
||||||
|
int h2_response_is_final(h2_response *response);
|
||||||
|
h2_response *h2_response_get_final(h2_response *response);
|
||||||
|
|
||||||
#endif /* defined(__mod_h2__h2_response__) */
|
#endif /* defined(__mod_h2__h2_response__) */
|
||||||
|
@@ -1419,18 +1419,28 @@ static apr_status_t on_stream_response(void *ctx, int stream_id)
|
|||||||
if (!stream) {
|
if (!stream) {
|
||||||
return APR_NOTFOUND;
|
return APR_NOTFOUND;
|
||||||
}
|
}
|
||||||
|
else if (!stream->response) {
|
||||||
response = h2_stream_get_response(stream);
|
int err = H2_STREAM_RST(stream, H2_ERR_PROTOCOL_ERROR);
|
||||||
AP_DEBUG_ASSERT(response || stream->rst_error);
|
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03074)
|
||||||
if (stream->submitted) {
|
"h2_stream(%ld-%d): RST_STREAM, err=%d",
|
||||||
rv = NGHTTP2_PROTOCOL_ERROR;
|
session->id, stream->id, err);
|
||||||
|
|
||||||
|
rv = nghttp2_submit_rst_stream(session->ngh2, NGHTTP2_FLAG_NONE,
|
||||||
|
stream->id, err);
|
||||||
|
goto leave;
|
||||||
}
|
}
|
||||||
else if (response && response->headers) {
|
|
||||||
|
while ((response = h2_stream_get_unsent_response(stream)) != NULL) {
|
||||||
nghttp2_data_provider provider, *pprovider = NULL;
|
nghttp2_data_provider provider, *pprovider = NULL;
|
||||||
h2_ngheader *ngh;
|
h2_ngheader *ngh;
|
||||||
const h2_priority *prio;
|
const h2_priority *prio;
|
||||||
|
|
||||||
|
if (stream->submitted) {
|
||||||
|
rv = NGHTTP2_PROTOCOL_ERROR;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
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, REMOTE_WINDOW_SIZE=%u",
|
"h2_stream(%ld-%d): submit response %d, REMOTE_WINDOW_SIZE=%u",
|
||||||
session->id, stream->id, response->http_status,
|
session->id, stream->id, response->http_status,
|
||||||
@@ -1458,7 +1468,9 @@ static apr_status_t on_stream_response(void *ctx, int stream_id)
|
|||||||
* 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->request && !stream->request->initiated_on
|
if (stream->request
|
||||||
|
&& !stream->request->initiated_on
|
||||||
|
&& h2_response_is_final(response)
|
||||||
&& H2_HTTP_2XX(response->http_status)
|
&& H2_HTTP_2XX(response->http_status)
|
||||||
&& h2_session_push_enabled(session)) {
|
&& h2_session_push_enabled(session)) {
|
||||||
|
|
||||||
@@ -1468,35 +1480,24 @@ static apr_status_t on_stream_response(void *ctx, int stream_id)
|
|||||||
prio = h2_stream_get_priority(stream);
|
prio = h2_stream_get_priority(stream);
|
||||||
if (prio) {
|
if (prio) {
|
||||||
h2_session_set_prio(session, stream, prio);
|
h2_session_set_prio(session, stream, prio);
|
||||||
/* no showstopper if that fails for some reason */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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, pprovider);
|
ngh->nv, ngh->nvlen, pprovider);
|
||||||
}
|
stream->submitted = h2_response_is_final(response);
|
||||||
else {
|
session->have_written = 1;
|
||||||
int err = H2_STREAM_RST(stream, H2_ERR_PROTOCOL_ERROR);
|
|
||||||
|
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03074)
|
if (stream->request && stream->request->initiated_on) {
|
||||||
"h2_stream(%ld-%d): RST_STREAM, err=%d",
|
++session->pushes_submitted;
|
||||||
session->id, stream->id, err);
|
}
|
||||||
|
else {
|
||||||
rv = nghttp2_submit_rst_stream(session->ngh2, NGHTTP2_FLAG_NONE,
|
++session->responses_submitted;
|
||||||
stream->id, err);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
stream->submitted = 1;
|
|
||||||
session->have_written = 1;
|
|
||||||
|
|
||||||
if (stream->request && stream->request->initiated_on) {
|
|
||||||
++session->pushes_submitted;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
++session->responses_submitted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
if (nghttp2_is_fatal(rv)) {
|
if (nghttp2_is_fatal(rv)) {
|
||||||
status = APR_EGENERAL;
|
status = APR_EGENERAL;
|
||||||
dispatch_event(session, H2_SESSION_EV_PROTO_ERROR, rv, nghttp2_strerror(rv));
|
dispatch_event(session, H2_SESSION_EV_PROTO_ERROR, rv, nghttp2_strerror(rv));
|
||||||
@@ -1699,7 +1700,12 @@ static void update_child_status(h2_session *session, int status, const char *msg
|
|||||||
static void transit(h2_session *session, const char *action, h2_session_state nstate)
|
static void transit(h2_session *session, const char *action, h2_session_state nstate)
|
||||||
{
|
{
|
||||||
if (session->state != nstate) {
|
if (session->state != nstate) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03078)
|
int loglvl = APLOG_DEBUG;
|
||||||
|
if ((session->state == H2_SESSION_ST_BUSY && nstate == H2_SESSION_ST_WAIT)
|
||||||
|
|| (session->state == H2_SESSION_ST_WAIT && nstate == H2_SESSION_ST_BUSY)){
|
||||||
|
loglvl = APLOG_TRACE1;
|
||||||
|
}
|
||||||
|
ap_log_cerror(APLOG_MARK, loglvl, 0, session->c, APLOGNO(03078)
|
||||||
"h2_session(%ld): transit [%s] -- %s --> [%s]", session->id,
|
"h2_session(%ld): transit [%s] -- %s --> [%s]", session->id,
|
||||||
state_name(session->state), action, state_name(nstate));
|
state_name(session->state), action, state_name(nstate));
|
||||||
session->state = nstate;
|
session->state = nstate;
|
||||||
|
@@ -265,6 +265,16 @@ struct h2_response *h2_stream_get_response(h2_stream *stream)
|
|||||||
return stream->response;
|
return stream->response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct h2_response *h2_stream_get_unsent_response(h2_stream *stream)
|
||||||
|
{
|
||||||
|
h2_response *unsent = (stream->last_sent?
|
||||||
|
stream->last_sent->next : stream->response);
|
||||||
|
if (unsent) {
|
||||||
|
stream->last_sent = unsent;
|
||||||
|
}
|
||||||
|
return unsent;
|
||||||
|
}
|
||||||
|
|
||||||
apr_status_t h2_stream_set_request(h2_stream *stream, request_rec *r)
|
apr_status_t h2_stream_set_request(h2_stream *stream, request_rec *r)
|
||||||
{
|
{
|
||||||
apr_status_t status;
|
apr_status_t status;
|
||||||
@@ -524,11 +534,12 @@ static apr_status_t fill_buffer(h2_stream *stream, apr_size_t amount)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t h2_stream_set_response(h2_stream *stream, h2_response *response,
|
apr_status_t h2_stream_add_response(h2_stream *stream, h2_response *response,
|
||||||
h2_bucket_beam *output)
|
h2_bucket_beam *output)
|
||||||
{
|
{
|
||||||
apr_status_t status = APR_SUCCESS;
|
apr_status_t status = APR_SUCCESS;
|
||||||
conn_rec *c = stream->session->c;
|
conn_rec *c = stream->session->c;
|
||||||
|
h2_response **pr = &stream->response;
|
||||||
|
|
||||||
if (!output_open(stream)) {
|
if (!output_open(stream)) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
||||||
@@ -536,15 +547,29 @@ apr_status_t h2_stream_set_response(h2_stream *stream, h2_response *response,
|
|||||||
stream->session->id, stream->id);
|
stream->session->id, stream->id);
|
||||||
return APR_ECONNRESET;
|
return APR_ECONNRESET;
|
||||||
}
|
}
|
||||||
|
if (stream->submitted) {
|
||||||
stream->response = response;
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
||||||
stream->output = output;
|
"h2_stream(%ld-%d): already submitted final response",
|
||||||
stream->buffer = apr_brigade_create(stream->pool, c->bucket_alloc);
|
stream->session->id, stream->id);
|
||||||
|
return APR_ECONNRESET;
|
||||||
h2_stream_filter(stream);
|
|
||||||
if (stream->output) {
|
|
||||||
status = fill_buffer(stream, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* append */
|
||||||
|
while (*pr) {
|
||||||
|
pr = &((*pr)->next);
|
||||||
|
}
|
||||||
|
*pr = response;
|
||||||
|
|
||||||
|
if (h2_response_is_final(response)) {
|
||||||
|
stream->output = output;
|
||||||
|
stream->buffer = apr_brigade_create(stream->pool, c->bucket_alloc);
|
||||||
|
|
||||||
|
h2_stream_filter(stream);
|
||||||
|
if (stream->output) {
|
||||||
|
status = fill_buffer(stream, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, c,
|
||||||
"h2_stream(%ld-%d): set_response(%d)",
|
"h2_stream(%ld-%d): set_response(%d)",
|
||||||
stream->session->id, stream->id,
|
stream->session->id, stream->id,
|
||||||
@@ -561,7 +586,7 @@ apr_status_t h2_stream_set_error(h2_stream *stream, int http_status)
|
|||||||
}
|
}
|
||||||
response = h2_response_die(stream->id, http_status, stream->request,
|
response = h2_response_die(stream->id, http_status, stream->request,
|
||||||
stream->pool);
|
stream->pool);
|
||||||
return h2_stream_set_response(stream, response, NULL);
|
return h2_stream_add_response(stream, response, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const apr_size_t DATA_CHUNK_SIZE = ((16*1024) - 100 - 9);
|
static const apr_size_t DATA_CHUNK_SIZE = ((16*1024) - 100 - 9);
|
||||||
@@ -579,6 +604,10 @@ apr_status_t h2_stream_out_prepare(h2_stream *stream,
|
|||||||
return APR_ECONNRESET;
|
return APR_ECONNRESET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!stream->buffer) {
|
||||||
|
return APR_EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
if (*plen > 0) {
|
if (*plen > 0) {
|
||||||
requested = H2MIN(*plen, DATA_CHUNK_SIZE);
|
requested = H2MIN(*plen, DATA_CHUNK_SIZE);
|
||||||
}
|
}
|
||||||
@@ -662,7 +691,7 @@ apr_status_t h2_stream_submit_pushes(h2_stream *stream)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
pushes = h2_push_collect_update(stream, stream->request,
|
pushes = h2_push_collect_update(stream, stream->request,
|
||||||
h2_stream_get_response(stream));
|
stream->response);
|
||||||
if (pushes && !apr_is_empty_array(pushes)) {
|
if (pushes && !apr_is_empty_array(pushes)) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, stream->session->c,
|
||||||
"h2_stream(%ld-%d): found %d push candidates",
|
"h2_stream(%ld-%d): found %d push candidates",
|
||||||
@@ -686,10 +715,8 @@ apr_table_t *h2_stream_get_trailers(h2_stream *stream)
|
|||||||
|
|
||||||
const h2_priority *h2_stream_get_priority(h2_stream *stream)
|
const h2_priority *h2_stream_get_priority(h2_stream *stream)
|
||||||
{
|
{
|
||||||
h2_response *response = h2_stream_get_response(stream);
|
if (stream->response && stream->request && stream->request->initiated_on) {
|
||||||
|
const char *ctype = apr_table_get(stream->response->headers, "content-type");
|
||||||
if (response && stream->request && stream->request->initiated_on) {
|
|
||||||
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 */
|
||||||
return h2_config_get_priority(stream->session->config, ctype);
|
return h2_config_get_priority(stream->session->config, ctype);
|
||||||
|
@@ -52,6 +52,7 @@ struct h2_stream {
|
|||||||
int request_headers_added; /* number of request headers added */
|
int request_headers_added; /* number of request headers added */
|
||||||
|
|
||||||
struct h2_response *response;
|
struct h2_response *response;
|
||||||
|
struct h2_response *last_sent;
|
||||||
struct h2_bucket_beam *output;
|
struct h2_bucket_beam *output;
|
||||||
apr_bucket_brigade *buffer;
|
apr_bucket_brigade *buffer;
|
||||||
apr_bucket_brigade *tmp;
|
apr_bucket_brigade *tmp;
|
||||||
@@ -179,6 +180,7 @@ apr_status_t h2_stream_schedule(h2_stream *stream, int eos, int push_enabled,
|
|||||||
int h2_stream_is_scheduled(const h2_stream *stream);
|
int h2_stream_is_scheduled(const h2_stream *stream);
|
||||||
|
|
||||||
struct h2_response *h2_stream_get_response(h2_stream *stream);
|
struct h2_response *h2_stream_get_response(h2_stream *stream);
|
||||||
|
struct h2_response *h2_stream_get_unsent_response(h2_stream *stream);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the response for this stream. Invoked when all meta data for
|
* Set the response for this stream. Invoked when all meta data for
|
||||||
@@ -189,7 +191,7 @@ struct h2_response *h2_stream_get_response(h2_stream *stream);
|
|||||||
* @param bb bucket brigade with output data for the stream. Optional,
|
* @param bb bucket brigade with output data for the stream. Optional,
|
||||||
* may be incomplete.
|
* may be incomplete.
|
||||||
*/
|
*/
|
||||||
apr_status_t h2_stream_set_response(h2_stream *stream,
|
apr_status_t h2_stream_add_response(h2_stream *stream,
|
||||||
struct h2_response *response,
|
struct h2_response *response,
|
||||||
struct h2_bucket_beam *output);
|
struct h2_bucket_beam *output);
|
||||||
|
|
||||||
|
@@ -42,6 +42,7 @@
|
|||||||
#include "h2_h2.h"
|
#include "h2_h2.h"
|
||||||
#include "h2_mplx.h"
|
#include "h2_mplx.h"
|
||||||
#include "h2_request.h"
|
#include "h2_request.h"
|
||||||
|
#include "h2_response.h"
|
||||||
#include "h2_session.h"
|
#include "h2_session.h"
|
||||||
#include "h2_stream.h"
|
#include "h2_stream.h"
|
||||||
#include "h2_task.h"
|
#include "h2_task.h"
|
||||||
@@ -163,6 +164,21 @@ static apr_status_t input_read(h2_task *task, ap_filter_t* f,
|
|||||||
return APR_EOF;
|
return APR_EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (f->r && f->r->expecting_100) {
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
|
||||||
|
"h2_task(%s): need to send 100 Continue here",
|
||||||
|
task->id);
|
||||||
|
f->r->expecting_100 = 0;
|
||||||
|
}
|
||||||
|
if (task->r && task->r->expecting_100) {
|
||||||
|
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
|
||||||
|
"h2_task2(%s): need to send 100 Continue here",
|
||||||
|
task->id);
|
||||||
|
task->r->expecting_100 = 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/* Cleanup brigades from those nasty 0 length non-meta buckets
|
/* Cleanup brigades from those nasty 0 length non-meta buckets
|
||||||
* that apr_brigade_split_line() sometimes produces. */
|
* that apr_brigade_split_line() sometimes produces. */
|
||||||
for (b = APR_BRIGADE_FIRST(task->input.bb);
|
for (b = APR_BRIGADE_FIRST(task->input.bb);
|
||||||
@@ -314,10 +330,8 @@ static apr_status_t input_read(h2_task *task, ap_filter_t* f,
|
|||||||
* task output handling
|
* task output handling
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
static apr_status_t open_response(h2_task *task)
|
static apr_status_t open_response(h2_task *task, h2_response *response)
|
||||||
{
|
{
|
||||||
h2_response *response;
|
|
||||||
response = h2_from_h1_get_response(task->output.from_h1);
|
|
||||||
if (!response) {
|
if (!response) {
|
||||||
/* 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. */
|
||||||
@@ -461,7 +475,8 @@ static apr_status_t output_write(h2_task *task, ap_filter_t* f,
|
|||||||
&& (flush || h2_beam_get_mem_used(task->output.beam) > (32*1024))) {
|
&& (flush || h2_beam_get_mem_used(task->output.beam) > (32*1024))) {
|
||||||
/* if we have enough buffered or we got a flush bucket, open
|
/* if we have enough buffered or we got a flush bucket, open
|
||||||
* the response now. */
|
* the response now. */
|
||||||
status = open_response(task);
|
status = open_response(task,
|
||||||
|
h2_from_h1_get_response(task->output.from_h1));
|
||||||
task->output.response_open = 1;
|
task->output.response_open = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,7 +488,8 @@ static apr_status_t output_finish(h2_task *task)
|
|||||||
apr_status_t status = APR_SUCCESS;
|
apr_status_t status = APR_SUCCESS;
|
||||||
|
|
||||||
if (!task->output.response_open) {
|
if (!task->output.response_open) {
|
||||||
status = open_response(task);
|
status = open_response(task,
|
||||||
|
h2_from_h1_get_response(task->output.from_h1));
|
||||||
task->output.response_open = 1;
|
task->output.response_open = 1;
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
@@ -494,6 +510,33 @@ static apr_status_t h2_filter_stream_input(ap_filter_t* filter,
|
|||||||
return input_read(task, filter, brigade, mode, block, readbytes);
|
return input_read(task, filter, brigade, mode, block, readbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static apr_status_t h2_filter_continue(ap_filter_t* f,
|
||||||
|
apr_bucket_brigade* brigade,
|
||||||
|
ap_input_mode_t mode,
|
||||||
|
apr_read_type_e block,
|
||||||
|
apr_off_t readbytes)
|
||||||
|
{
|
||||||
|
h2_task *task = h2_ctx_cget_task(f->c);
|
||||||
|
apr_status_t status;
|
||||||
|
|
||||||
|
AP_DEBUG_ASSERT(task);
|
||||||
|
if (f->r->expecting_100) {
|
||||||
|
h2_response *response;
|
||||||
|
|
||||||
|
response = h2_response_rcreate(task->stream_id, f->r, HTTP_CONTINUE,
|
||||||
|
f->r->headers_out, f->r->pool);
|
||||||
|
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, f->r,
|
||||||
|
"h2_task(%s): send 100 Continue", task->id);
|
||||||
|
status = open_response(task, response);
|
||||||
|
if (status != APR_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
f->r->expecting_100 = 0;
|
||||||
|
apr_table_clear(f->r->headers_out);
|
||||||
|
}
|
||||||
|
return ap_get_brigade(f->next, brigade, mode, block, readbytes);
|
||||||
|
}
|
||||||
|
|
||||||
static apr_status_t h2_filter_stream_output(ap_filter_t* filter,
|
static apr_status_t h2_filter_stream_output(ap_filter_t* filter,
|
||||||
apr_bucket_brigade* brigade)
|
apr_bucket_brigade* brigade)
|
||||||
{
|
{
|
||||||
@@ -517,22 +560,23 @@ static apr_status_t h2_filter_read_response(ap_filter_t* filter,
|
|||||||
* task things
|
* task things
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void h2_task_set_response(h2_task *task, h2_response *response)
|
apr_status_t h2_task_add_response(h2_task *task, h2_response *response)
|
||||||
{
|
{
|
||||||
AP_DEBUG_ASSERT(response);
|
AP_DEBUG_ASSERT(response);
|
||||||
AP_DEBUG_ASSERT(!task->response);
|
|
||||||
/* we used to clone the response into out own pool. But
|
/* we used to clone the response into out own pool. But
|
||||||
* we have much tighter control over the EOR bucket nowadays,
|
* we have much tighter control over the EOR bucket nowadays,
|
||||||
* so just use the instance given */
|
* so just use the instance given */
|
||||||
|
response->next = task->response;
|
||||||
task->response = response;
|
task->response = response;
|
||||||
if (response->rst_error) {
|
if (response->rst_error) {
|
||||||
h2_task_rst(task, response->rst_error);
|
h2_task_rst(task, response->rst_error);
|
||||||
}
|
}
|
||||||
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int h2_task_can_redo(h2_task *task) {
|
int h2_task_can_redo(h2_task *task) {
|
||||||
if (task->submitted
|
if (task->response_sent
|
||||||
|| (task->input.beam && h2_beam_was_received(task->input.beam))
|
|| (task->input.beam && h2_beam_was_received(task->input.beam))
|
||||||
|| !task->request) {
|
|| !task->request) {
|
||||||
/* cannot repeat that. */
|
/* cannot repeat that. */
|
||||||
@@ -591,6 +635,8 @@ void h2_task_register_hooks(void)
|
|||||||
NULL, AP_FTYPE_PROTOCOL);
|
NULL, AP_FTYPE_PROTOCOL);
|
||||||
ap_register_input_filter("H2_TO_H1", h2_filter_stream_input,
|
ap_register_input_filter("H2_TO_H1", h2_filter_stream_input,
|
||||||
NULL, AP_FTYPE_NETWORK);
|
NULL, AP_FTYPE_NETWORK);
|
||||||
|
ap_register_input_filter("H2_CONTINUE", h2_filter_continue,
|
||||||
|
NULL, AP_FTYPE_PROTOCOL);
|
||||||
ap_register_output_filter("H1_TO_H2", h2_filter_stream_output,
|
ap_register_output_filter("H1_TO_H2", h2_filter_stream_output,
|
||||||
NULL, AP_FTYPE_NETWORK);
|
NULL, AP_FTYPE_NETWORK);
|
||||||
ap_register_output_filter("H1_TO_H2_RESP", h2_filter_read_response,
|
ap_register_output_filter("H1_TO_H2_RESP", h2_filter_read_response,
|
||||||
@@ -749,11 +795,16 @@ static apr_status_t h2_task_process_request(h2_task *task, conn_rec *c)
|
|||||||
}
|
}
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
||||||
"h2_task(%s): start process_request", task->id);
|
"h2_task(%s): start process_request", task->id);
|
||||||
|
task->r = r;
|
||||||
|
|
||||||
ap_process_request(r);
|
ap_process_request(r);
|
||||||
if (task->frozen) {
|
if (task->frozen) {
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
||||||
"h2_task(%s): process_request frozen", task->id);
|
"h2_task(%s): process_request frozen", task->id);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
task->r = NULL;
|
||||||
|
}
|
||||||
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
||||||
"h2_task(%s): process_request done", task->id);
|
"h2_task(%s): process_request done", task->id);
|
||||||
|
|
||||||
|
@@ -70,6 +70,7 @@ struct h2_task {
|
|||||||
struct {
|
struct {
|
||||||
struct h2_bucket_beam *beam;
|
struct h2_bucket_beam *beam;
|
||||||
struct h2_from_h1 *from_h1;
|
struct h2_from_h1 *from_h1;
|
||||||
|
unsigned int opened : 1;
|
||||||
unsigned int response_open : 1;
|
unsigned int response_open : 1;
|
||||||
unsigned int copy_files : 1;
|
unsigned int copy_files : 1;
|
||||||
apr_off_t written;
|
apr_off_t written;
|
||||||
@@ -85,7 +86,7 @@ struct h2_task {
|
|||||||
unsigned int frozen : 1;
|
unsigned int frozen : 1;
|
||||||
unsigned int blocking : 1;
|
unsigned int blocking : 1;
|
||||||
unsigned int detached : 1;
|
unsigned int detached : 1;
|
||||||
unsigned int submitted : 1; /* response has been submitted to client */
|
unsigned int response_sent : 1; /* a response has been sent to client */
|
||||||
unsigned int worker_started : 1; /* h2_worker started processing for this io */
|
unsigned int worker_started : 1; /* h2_worker started processing for this io */
|
||||||
unsigned int worker_done : 1; /* h2_worker finished for this io */
|
unsigned int worker_done : 1; /* h2_worker finished for this io */
|
||||||
|
|
||||||
@@ -105,7 +106,7 @@ void h2_task_destroy(h2_task *task);
|
|||||||
|
|
||||||
apr_status_t h2_task_do(h2_task *task, apr_thread_t *thread);
|
apr_status_t h2_task_do(h2_task *task, apr_thread_t *thread);
|
||||||
|
|
||||||
void h2_task_set_response(h2_task *task, struct h2_response *response);
|
apr_status_t h2_task_add_response(h2_task *task, struct h2_response *response);
|
||||||
|
|
||||||
void h2_task_redo(h2_task *task);
|
void h2_task_redo(h2_task *task);
|
||||||
int h2_task_can_redo(h2_task *task);
|
int h2_task_can_redo(h2_task *task);
|
||||||
|
@@ -1160,7 +1160,7 @@ typedef struct {
|
|||||||
#define H2_LIT_ARGS(a) (a),H2_ALEN(a)
|
#define H2_LIT_ARGS(a) (a),H2_ALEN(a)
|
||||||
|
|
||||||
static literal IgnoredRequestHeaders[] = {
|
static literal IgnoredRequestHeaders[] = {
|
||||||
H2_DEF_LITERAL("expect"),
|
/*H2_DEF_LITERAL("expect"),*/
|
||||||
H2_DEF_LITERAL("upgrade"),
|
H2_DEF_LITERAL("upgrade"),
|
||||||
H2_DEF_LITERAL("connection"),
|
H2_DEF_LITERAL("connection"),
|
||||||
H2_DEF_LITERAL("keep-alive"),
|
H2_DEF_LITERAL("keep-alive"),
|
||||||
|
@@ -26,7 +26,7 @@
|
|||||||
* @macro
|
* @macro
|
||||||
* Version number of the http2 module as c string
|
* Version number of the http2 module as c string
|
||||||
*/
|
*/
|
||||||
#define MOD_HTTP2_VERSION "1.5.14-DEV"
|
#define MOD_HTTP2_VERSION "1.6.0-DEV"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @macro
|
* @macro
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
* release. This is a 24 bit number with 8 bits for major number, 8 bits
|
* 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.
|
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
|
||||||
*/
|
*/
|
||||||
#define MOD_HTTP2_VERSION_NUM 0x01050e
|
#define MOD_HTTP2_VERSION_NUM 0x010600
|
||||||
|
|
||||||
|
|
||||||
#endif /* mod_h2_h2_version_h */
|
#endif /* mod_h2_h2_version_h */
|
||||||
|
Reference in New Issue
Block a user