summaryrefslogtreecommitdiff
path: root/src/http/ngx_http_spdy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/http/ngx_http_spdy.c')
-rw-r--r--src/http/ngx_http_spdy.c83
1 files changed, 57 insertions, 26 deletions
diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c
index 6e45f4b46..33f0f03ac 100644
--- a/src/http/ngx_http_spdy.c
+++ b/src/http/ngx_http_spdy.c
@@ -47,11 +47,11 @@
#define ngx_spdy_ctl_frame_check(h) \
- (((h) & 0xffffff00) == ngx_spdy_ctl_frame_head(0))
+ (((h) & 0xffff0000) == ngx_spdy_ctl_frame_head(0))
#define ngx_spdy_data_frame_check(h) \
(!((h) & (uint32_t) NGX_SPDY_CTL_BIT << 31))
-#define ngx_spdy_ctl_frame_type(h) ((h) & 0x000000ff)
+#define ngx_spdy_ctl_frame_type(h) ((h) & 0x0000ffff)
#define ngx_spdy_frame_flags(p) ((p) >> 24)
#define ngx_spdy_frame_length(p) ((p) & 0x00ffffff)
#define ngx_spdy_frame_id(p) ((p) & 0x00ffffff)
@@ -836,7 +836,8 @@ static u_char *
ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
u_char *end)
{
- uint32_t head, flen;
+ uint32_t head, flen;
+ ngx_uint_t type;
if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) {
return ngx_http_spdy_state_save(sc, pos, end,
@@ -859,7 +860,9 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
head, sc->flags, sc->length);
if (ngx_spdy_ctl_frame_check(head)) {
- switch (ngx_spdy_ctl_frame_type(head)) {
+ type = ngx_spdy_ctl_frame_type(head);
+
+ switch (type) {
case NGX_SPDY_SYN_STREAM:
return ngx_http_spdy_state_syn_stream(sc, pos, end);
@@ -885,7 +888,9 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
case NGX_SPDY_WINDOW_UPDATE:
return ngx_http_spdy_state_window_update(sc, pos, end);
- default: /* TODO logging */
+ default:
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy control frame with unknown type %ui", type);
return ngx_http_spdy_state_skip(sc, pos, end);
}
}
@@ -1049,6 +1054,15 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
if (r->headers_in.headers.part.elts == NULL) {
if (buf->last - buf->pos < NGX_SPDY_NV_NUM_SIZE) {
+
+ if (complete) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent SYN_STREAM frame "
+ "with invalid HEADERS block");
+ ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
+ return ngx_http_spdy_state_protocol_error(sc);
+ }
+
return ngx_http_spdy_state_save(sc, pos, end,
ngx_http_spdy_state_headers);
}
@@ -1187,10 +1201,10 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
}
}
- if (buf->pos != buf->last) {
- /* TODO: improve error message */
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "end %ui %p %p", complete, buf->pos, buf->last);
+ if (buf->pos != buf->last || sc->zstream_in.avail_in) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent SYN_STREAM frame "
+ "with invalid HEADERS block");
ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
return ngx_http_spdy_state_protocol_error(sc);
}
@@ -1489,7 +1503,6 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
ssize_t n;
ngx_buf_t *buf;
ngx_int_t rc;
- ngx_uint_t complete;
ngx_temp_file_t *tf;
ngx_http_request_t *r;
ngx_http_spdy_stream_t *stream;
@@ -1514,13 +1527,8 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
size = end - pos;
- if (size >= sc->length) {
+ if (size > sc->length) {
size = sc->length;
- complete = 1;
-
- } else {
- sc->length -= size;
- complete = 0;
}
r = stream->request;
@@ -1562,6 +1570,8 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
}
}
+ sc->length -= size;
+
if (tf) {
buf->start = pos;
buf->pos = pos;
@@ -1590,7 +1600,7 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
r->request_length += size;
}
- if (!complete) {
+ if (sc->length) {
return ngx_http_spdy_state_save(sc, pos, end,
ngx_http_spdy_state_read_data);
}
@@ -1599,6 +1609,19 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
stream->in_closed = 1;
+ if (r->headers_in.content_length_n < 0) {
+ 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,
+ "client prematurely closed stream: "
+ "%O of %O bytes of request body received",
+ rb->rest, r->headers_in.content_length_n);
+
+ stream->skip_data = NGX_SPDY_DATA_ERROR;
+ goto error;
+ }
+
if (tf) {
ngx_memzero(buf, sizeof(ngx_buf_t));
@@ -1609,10 +1632,6 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
rb->buf = NULL;
}
- if (r->headers_in.content_length_n < 0) {
- r->headers_in.content_length_n = rb->rest;
- }
-
if (rb->post_handler) {
r->read_event_handler = ngx_http_block_reading;
rb->post_handler(r);
@@ -1872,18 +1891,20 @@ static u_char *
ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler)
{
-#if 1
- if (end - pos > NGX_SPDY_STATE_BUFFER_SIZE) {
+ size_t size;
+
+ size = end - pos;
+
+ if (size > NGX_SPDY_STATE_BUFFER_SIZE) {
ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
"spdy state buffer overflow: "
- "%z bytes required", end - pos);
+ "%uz bytes required", size);
return ngx_http_spdy_state_internal_error(sc);
}
-#endif
ngx_memcpy(sc->buffer, pos, NGX_SPDY_STATE_BUFFER_SIZE);
- sc->buffer_used = end - pos;
+ sc->buffer_used = size;
sc->handler = handler;
sc->incomplete = 1;
@@ -2941,6 +2962,16 @@ ngx_http_spdy_run_request(ngx_http_request_t *r)
return;
}
+ if (r->headers_in.content_length_n > 0 && r->spdy_stream->in_closed) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client prematurely closed stream");
+
+ r->spdy_stream->skip_data = NGX_SPDY_DATA_ERROR;
+
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+ return;
+ }
+
ngx_http_process_request(r);
}