u_char *pos, u_char *end);
static u_char *ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c,
u_char *pos, u_char *end, ngx_http_v2_handler_pt handler);
+static u_char *ngx_http_v2_state_headers_save(ngx_http_v2_connection_t *h2c,
+ u_char *pos, u_char *end, ngx_http_v2_handler_pt handler);
static u_char *ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c,
ngx_uint_t err);
static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r);
static void ngx_http_v2_run_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_v2_init_request_body(ngx_http_request_t *r);
+static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c,
ngx_http_v2_stream_t *stream, ngx_uint_t status);
"run http2 stream %ui", stream->node->id);
wev = stream->request->connection->write;
+
+ wev->active = 0;
+ wev->ready = 1;
+
wev->handler(wev);
}
ngx_buf_t *buf;
ngx_int_t rc;
ngx_temp_file_t *tf;
+ ngx_connection_t *fc;
ngx_http_request_t *r;
ngx_http_v2_stream_t *stream;
ngx_http_request_body_t *rb;
return ngx_http_v2_state_skip_padded(h2c, pos, end);
}
+ fc = r->connection;
rb = r->request_body;
tf = rb->temp_file;
buf = rb->buf;
if (r->headers_in.content_length_n != -1
&& r->headers_in.content_length_n < rb->rest)
{
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client intended to send body data "
"larger than declared");
if (clcf->client_max_body_size
&& clcf->client_max_body_size < rb->rest)
{
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ ngx_log_error(NGX_LOG_ERR, fc->log, 0,
"client intended to send "
"too large chunked body: %O bytes", rb->rest);
}
if (h2c->state.length) {
+ if (rb->post_handler) {
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+ ngx_add_timer(fc->read, clcf->client_body_timeout);
+ }
+
return ngx_http_v2_state_save(h2c, pos, end,
ngx_http_v2_state_read_data);
}
r->headers_in.content_length_n = rb->rest;
} else if (r->headers_in.content_length_n != rb->rest) {
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client prematurely closed stream: "
"only %O out of %O bytes of request body received",
rb->rest, r->headers_in.content_length_n);
}
if (rb->post_handler) {
+ if (fc->read->timer_set) {
+ ngx_del_timer(fc->read);
+ }
+
r->read_event_handler = ngx_http_block_reading;
rb->post_handler(r);
}
+
+ } else if (rb->post_handler) {
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+ ngx_add_timer(fc->read, clcf->client_body_timeout);
}
if (h2c->state.padding) {
error:
if (rb->post_handler) {
+ if (fc->read->timer_set) {
+ ngx_del_timer(fc->read);
+ }
if (stream->skip_data == NGX_HTTP_V2_DATA_ERROR) {
rc = (r->headers_in.content_length_n == -1)
ngx_uint_t indexed, size_update, prefix;
if (end - pos < 1) {
- return ngx_http_v2_state_save(h2c, pos, end,
- ngx_http_v2_state_header_block);
+ return ngx_http_v2_state_headers_save(h2c, pos, end,
+ ngx_http_v2_state_header_block);
}
if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)
if (value < 0) {
if (value == NGX_AGAIN) {
- return ngx_http_v2_state_save(h2c, pos, end,
- ngx_http_v2_state_header_block);
+ return ngx_http_v2_state_headers_save(h2c, pos, end,
+ ngx_http_v2_state_header_block);
}
if (value == NGX_DECLINED) {
}
if (end - pos < 1) {
- return ngx_http_v2_state_save(h2c, pos, end,
- ngx_http_v2_state_field_len);
+ return ngx_http_v2_state_headers_save(h2c, pos, end,
+ ngx_http_v2_state_field_len);
}
huff = *pos >> 7;
if (len < 0) {
if (len == NGX_AGAIN) {
- return ngx_http_v2_state_save(h2c, pos, end,
- ngx_http_v2_state_field_len);
+ return ngx_http_v2_state_headers_save(h2c, pos, end,
+ ngx_http_v2_state_field_len);
}
if (len == NGX_DECLINED) {
}
if (h2c->state.length) {
- return ngx_http_v2_state_save(h2c, pos, end,
- ngx_http_v2_state_field_huff);
+ return ngx_http_v2_state_headers_save(h2c, pos, end,
+ ngx_http_v2_state_field_huff);
}
if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
}
if (h2c->state.length) {
- return ngx_http_v2_state_save(h2c, pos, end,
- ngx_http_v2_state_field_raw);
+ return ngx_http_v2_state_headers_save(h2c, pos, end,
+ ngx_http_v2_state_field_raw);
}
if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
}
if ((size_t) (end - pos) < len + NGX_HTTP_V2_FRAME_HEADER_SIZE) {
- return ngx_http_v2_state_save(h2c, pos, end, handler);
+ return ngx_http_v2_state_headers_save(h2c, pos, end, handler);
}
p = pos + len;
wev = stream->request->connection->write;
- if (!wev->timer_set) {
- wev->delayed = 0;
+ wev->active = 0;
+ wev->ready = 1;
+
+ if (!wev->delayed) {
wev->handler(wev);
}
}
wev = stream->request->connection->write;
- if (!wev->timer_set) {
- wev->delayed = 0;
+ wev->active = 0;
+ wev->ready = 1;
+
+ if (!wev->delayed) {
wev->handler(wev);
if (h2c->send_window == 0) {
}
+static u_char *
+ngx_http_v2_state_headers_save(ngx_http_v2_connection_t *h2c, u_char *pos,
+ u_char *end, ngx_http_v2_handler_pt handler)
+{
+ ngx_event_t *rev;
+ ngx_http_request_t *r;
+ ngx_http_core_srv_conf_t *cscf;
+
+ if (h2c->state.stream) {
+ r = h2c->state.stream->request;
+ rev = r->connection->read;
+
+ if (!rev->timer_set) {
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+ ngx_add_timer(rev, cscf->client_header_timeout);
+ }
+ }
+
+ return ngx_http_v2_state_save(h2c, pos, end, handler);
+}
+
+
static u_char *
ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c,
ngx_uint_t err)
ngx_memcpy(log, h2c->connection->log, sizeof(ngx_log_t));
log->data = ctx;
+ log->action = "reading client request headers";
ngx_memzero(rev, sizeof(ngx_event_t));
ngx_http_v2_read_request_body(ngx_http_request_t *r,
ngx_http_client_body_handler_pt post_handler)
{
- ngx_http_v2_stream_t *stream;
+ ngx_http_v2_stream_t *stream;
+ ngx_http_core_loc_conf_t *clcf;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http2 read request body");
r->request_body->post_handler = post_handler;
- r->read_event_handler = ngx_http_test_reading;
+ r->read_event_handler = ngx_http_v2_read_client_request_body_handler;
r->write_event_handler = ngx_http_request_empty_handler;
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+ ngx_add_timer(r->connection->read, clcf->client_body_timeout);
+
return NGX_AGAIN;
}
+static void
+ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r)
+{
+ ngx_connection_t *fc;
+
+ fc = r->connection;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
+ "http2 read client request body handler");
+
+ if (fc->read->timedout) {
+ ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out");
+
+ fc->timedout = 1;
+ r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD;
+
+ ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
+ return;
+ }
+
+ if (fc->error) {
+ ngx_log_error(NGX_LOG_INFO, fc->log, 0,
+ "client prematurely closed stream");
+
+ r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD;
+
+ ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST);
+ return;
+ }
+}
+
+
static ngx_int_t
ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c,
ngx_http_v2_stream_t *stream, ngx_uint_t status)
if (!stream->out_closed) {
if (ngx_http_v2_send_rst_stream(h2c, node->id,
- NGX_HTTP_V2_INTERNAL_ERROR)
+ fc->timedout ? NGX_HTTP_V2_PROTOCOL_ERROR
+ : NGX_HTTP_V2_INTERNAL_ERROR)
!= NGX_OK)
{
h2c->connection->error = 1;
ev = fc->read;
- if (ev->active || ev->disabled) {
- ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
- "fake read event was activated");
- }
-
if (ev->timer_set) {
ngx_del_timer(ev);
}
ev = fc->write;
- if (ev->active || ev->disabled) {
- ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
- "fake write event was activated");
- }
-
if (ev->timer_set) {
ngx_del_timer(ev);
}
fc = ev->data;
r = fc->data;
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
"http2 close stream handler");
+ if (ev->timedout) {
+ ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out");
+
+ fc->timedout = 1;
+
+ ngx_http_v2_close_stream(r->stream, NGX_HTTP_REQUEST_TIME_OUT);
+ return;
+ }
+
ngx_http_v2_close_stream(r->stream, 0);
}
static void
ngx_http_v2_handle_connection_handler(ngx_event_t *rev)
{
- ngx_connection_t *c;
+ ngx_connection_t *c;
+ ngx_http_v2_connection_t *h2c;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
+ "http2 handle connection handler");
rev->handler = ngx_http_v2_read_handler;
}
c = rev->data;
+ h2c = c->data;
+
+ if (h2c->last_out && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
+ ngx_http_v2_finalize_connection(h2c, 0);
+ return;
+ }
ngx_http_v2_handle_connection(c->data);
}
if (stream->queued) {
stream->queued = 0;
-
ev = fc->write;
- ev->delayed = 0;
} else {
ev = fc->read;
wev = stream->request->connection->write;
- if (!wev->timer_set) {
- wev->delayed = 0;
+ wev->active = 0;
+ wev->ready = 1;
+
+ if (!wev->delayed) {
wev->handler(wev);
}
}