mirror of
https://github.com/nginx/nginx.git
synced 2024-12-03 21:18:59 +08:00
SPDY: ngx_http_spdy_state_headers() error handling cleanup.
- Specification-friendly handling of invalid header block or special headers. Such errors are not fatal for session and shouldn't lead to connection close; - Avoid mix of NGX_HTTP_PARSE_INVALID_REQUEST/NGX_HTTP_PARSE_INVALID_HEADER.
This commit is contained in:
parent
cf770ddd82
commit
ef51079fe2
@ -105,6 +105,8 @@ static u_char *ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc,
|
|||||||
u_char *pos, u_char *end);
|
u_char *pos, u_char *end);
|
||||||
static u_char *ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc,
|
static u_char *ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc,
|
||||||
u_char *pos, u_char *end);
|
u_char *pos, u_char *end);
|
||||||
|
static u_char *ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc,
|
||||||
|
u_char *pos, u_char *end);
|
||||||
static u_char *ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc,
|
static u_char *ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc,
|
||||||
u_char *pos, u_char *end);
|
u_char *pos, u_char *end);
|
||||||
static u_char *ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc,
|
static u_char *ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc,
|
||||||
@ -1083,11 +1085,10 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
|
|||||||
if (buf->last - buf->pos < NGX_SPDY_NV_NUM_SIZE) {
|
if (buf->last - buf->pos < NGX_SPDY_NV_NUM_SIZE) {
|
||||||
|
|
||||||
if (complete) {
|
if (complete) {
|
||||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||||
"client sent SYN_STREAM frame "
|
"premature end of spdy header block");
|
||||||
"with invalid HEADERS block");
|
|
||||||
|
|
||||||
return ngx_http_spdy_state_protocol_error(sc);
|
return ngx_http_spdy_state_headers_error(sc, pos, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ngx_http_spdy_state_save(sc, pos, end,
|
return ngx_http_spdy_state_save(sc, pos, end,
|
||||||
@ -1181,13 +1182,13 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
|
|||||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||||
"spdy again while last chunk");
|
"spdy again while last chunk");
|
||||||
|
|
||||||
return ngx_http_spdy_state_protocol_error(sc);
|
return ngx_http_spdy_state_headers_error(sc, pos, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ngx_http_spdy_state_save(sc, pos, end,
|
return ngx_http_spdy_state_save(sc, pos, end,
|
||||||
ngx_http_spdy_state_headers);
|
ngx_http_spdy_state_headers);
|
||||||
|
|
||||||
case NGX_HTTP_PARSE_INVALID_REQUEST:
|
case NGX_HTTP_PARSE_INVALID_HEADER:
|
||||||
|
|
||||||
/* TODO: improve error message */
|
/* TODO: improve error message */
|
||||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||||
@ -1197,12 +1198,8 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
|
|||||||
|
|
||||||
return ngx_http_spdy_state_headers_skip(sc, pos, end);
|
return ngx_http_spdy_state_headers_skip(sc, pos, end);
|
||||||
|
|
||||||
default: /* NGX_HTTP_PARSE_INVALID_HEADER */
|
default: /* NGX_ERROR */
|
||||||
|
return ngx_http_spdy_state_headers_error(sc, pos, end);
|
||||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
|
||||||
"client sent invalid HEADERS spdy frame");
|
|
||||||
|
|
||||||
return ngx_http_spdy_state_protocol_error(sc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* a header line has been parsed successfully */
|
/* a header line has been parsed successfully */
|
||||||
@ -1211,14 +1208,13 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
|
|||||||
|
|
||||||
if (rc != NGX_OK) {
|
if (rc != NGX_OK) {
|
||||||
if (rc == NGX_HTTP_PARSE_INVALID_HEADER) {
|
if (rc == NGX_HTTP_PARSE_INVALID_HEADER) {
|
||||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||||
"client sent invalid HEADERS spdy frame");
|
return ngx_http_spdy_state_headers_skip(sc, pos, end);
|
||||||
|
|
||||||
return ngx_http_spdy_state_protocol_error(sc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc == NGX_HTTP_PARSE_INVALID_REQUEST) {
|
if (rc != NGX_ABORT) {
|
||||||
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
ngx_http_spdy_close_stream(sc->stream,
|
||||||
|
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ngx_http_spdy_state_headers_skip(sc, pos, end);
|
return ngx_http_spdy_state_headers_skip(sc, pos, end);
|
||||||
@ -1226,11 +1222,10 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (buf->pos != buf->last || sc->zstream_in.avail_in) {
|
if (buf->pos != buf->last || sc->zstream_in.avail_in) {
|
||||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||||
"client sent SYN_STREAM frame "
|
"incorrect number of spdy header block entries");
|
||||||
"with invalid HEADERS block");
|
|
||||||
|
|
||||||
return ngx_http_spdy_state_protocol_error(sc);
|
return ngx_http_spdy_state_headers_error(sc, pos, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!complete) {
|
if (!complete) {
|
||||||
@ -1292,6 +1287,33 @@ ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static u_char *
|
||||||
|
ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, u_char *pos,
|
||||||
|
u_char *end)
|
||||||
|
{
|
||||||
|
ngx_http_spdy_stream_t *stream;
|
||||||
|
|
||||||
|
stream = sc->stream;
|
||||||
|
|
||||||
|
ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
|
||||||
|
"client sent SYN_STREAM frame for stream %ui "
|
||||||
|
"with invalid header block", stream->id);
|
||||||
|
|
||||||
|
if (ngx_http_spdy_send_rst_stream(sc, stream->id, NGX_SPDY_PROTOCOL_ERROR,
|
||||||
|
stream->priority)
|
||||||
|
!= NGX_OK)
|
||||||
|
{
|
||||||
|
return ngx_http_spdy_state_internal_error(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->out_closed = 1;
|
||||||
|
|
||||||
|
ngx_http_spdy_close_stream(stream, NGX_HTTP_BAD_REQUEST);
|
||||||
|
|
||||||
|
return ngx_http_spdy_state_headers_skip(sc, pos, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static u_char *
|
static u_char *
|
||||||
ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos,
|
ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos,
|
||||||
u_char *end)
|
u_char *end)
|
||||||
@ -2425,7 +2447,7 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r)
|
|||||||
r->lowcase_index = ngx_spdy_frame_parse_uint32(p);
|
r->lowcase_index = ngx_spdy_frame_parse_uint32(p);
|
||||||
|
|
||||||
if (r->lowcase_index == 0) {
|
if (r->lowcase_index == 0) {
|
||||||
return NGX_HTTP_PARSE_INVALID_HEADER;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* null-terminate the previous header value */
|
/* null-terminate the previous header value */
|
||||||
@ -2475,11 +2497,11 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r)
|
|||||||
case LF:
|
case LF:
|
||||||
case CR:
|
case CR:
|
||||||
case ':':
|
case ':':
|
||||||
return NGX_HTTP_PARSE_INVALID_REQUEST;
|
return NGX_HTTP_PARSE_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch >= 'A' && ch <= 'Z') {
|
if (ch >= 'A' && ch <= 'Z') {
|
||||||
return NGX_HTTP_PARSE_INVALID_HEADER;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
r->invalid_header = 1;
|
r->invalid_header = 1;
|
||||||
@ -2642,13 +2664,11 @@ ngx_http_spdy_handle_request_header(ngx_http_request_t *r)
|
|||||||
return sh->handler(r);
|
return sh->handler(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NGX_HTTP_PARSE_INVALID_REQUEST;
|
return NGX_HTTP_PARSE_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
h = ngx_list_push(&r->headers_in.headers);
|
h = ngx_list_push(&r->headers_in.headers);
|
||||||
if (h == NULL) {
|
if (h == NULL) {
|
||||||
ngx_http_spdy_close_stream(r->spdy_stream,
|
|
||||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2752,7 +2772,7 @@ ngx_http_spdy_parse_method(ngx_http_request_t *r)
|
|||||||
if ((*p < 'A' || *p > 'Z') && *p != '_') {
|
if ((*p < 'A' || *p > 'Z') && *p != '_') {
|
||||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||||
"client sent invalid method");
|
"client sent invalid method");
|
||||||
return NGX_HTTP_PARSE_INVALID_REQUEST;
|
return NGX_HTTP_PARSE_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
p++;
|
p++;
|
||||||
@ -2788,8 +2808,6 @@ ngx_http_spdy_parse_host(ngx_http_request_t *r)
|
|||||||
|
|
||||||
h = ngx_list_push(&r->headers_in.headers);
|
h = ngx_list_push(&r->headers_in.headers);
|
||||||
if (h == NULL) {
|
if (h == NULL) {
|
||||||
ngx_http_spdy_close_stream(r->spdy_stream,
|
|
||||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2820,11 +2838,15 @@ ngx_http_spdy_parse_path(ngx_http_request_t *r)
|
|||||||
r->uri_end = r->header_end;
|
r->uri_end = r->header_end;
|
||||||
|
|
||||||
if (ngx_http_parse_uri(r) != NGX_OK) {
|
if (ngx_http_parse_uri(r) != NGX_OK) {
|
||||||
return NGX_HTTP_PARSE_INVALID_REQUEST;
|
return NGX_HTTP_PARSE_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ngx_http_process_request_uri(r) != NGX_OK) {
|
if (ngx_http_process_request_uri(r) != NGX_OK) {
|
||||||
return NGX_ERROR;
|
/*
|
||||||
|
* request has been finalized already
|
||||||
|
* in ngx_http_process_request_uri()
|
||||||
|
*/
|
||||||
|
return NGX_ABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
@ -2843,13 +2865,13 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r)
|
|||||||
p = r->header_start;
|
p = r->header_start;
|
||||||
|
|
||||||
if (r->header_end - p < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) {
|
if (r->header_end - p < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) {
|
||||||
return NGX_HTTP_PARSE_INVALID_REQUEST;
|
return NGX_HTTP_PARSE_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
ch = *(p + 5);
|
ch = *(p + 5);
|
||||||
|
|
||||||
if (ch < '1' || ch > '9') {
|
if (ch < '1' || ch > '9') {
|
||||||
return NGX_HTTP_PARSE_INVALID_REQUEST;
|
return NGX_HTTP_PARSE_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
r->http_major = ch - '0';
|
r->http_major = ch - '0';
|
||||||
@ -2863,20 +2885,20 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ch < '0' || ch > '9') {
|
if (ch < '0' || ch > '9') {
|
||||||
return NGX_HTTP_PARSE_INVALID_REQUEST;
|
return NGX_HTTP_PARSE_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
r->http_major = r->http_major * 10 + ch - '0';
|
r->http_major = r->http_major * 10 + ch - '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*p != '.') {
|
if (*p != '.') {
|
||||||
return NGX_HTTP_PARSE_INVALID_REQUEST;
|
return NGX_HTTP_PARSE_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
ch = *(p + 1);
|
ch = *(p + 1);
|
||||||
|
|
||||||
if (ch < '0' || ch > '9') {
|
if (ch < '0' || ch > '9') {
|
||||||
return NGX_HTTP_PARSE_INVALID_REQUEST;
|
return NGX_HTTP_PARSE_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
r->http_minor = ch - '0';
|
r->http_minor = ch - '0';
|
||||||
@ -2886,7 +2908,7 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r)
|
|||||||
ch = *p;
|
ch = *p;
|
||||||
|
|
||||||
if (ch < '0' || ch > '9') {
|
if (ch < '0' || ch > '9') {
|
||||||
return NGX_HTTP_PARSE_INVALID_REQUEST;
|
return NGX_HTTP_PARSE_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
r->http_minor = r->http_minor * 10 + ch - '0';
|
r->http_minor = r->http_minor * 10 + ch - '0';
|
||||||
|
Loading…
Reference in New Issue
Block a user