[PATCH 2 of 3] HTTP/2: added support for trailers in HTTP responses
Valentin V. Bartenev
vbart at nginx.com
Wed Jun 7 19:16:17 UTC 2017
On Friday 02 June 2017 20:33:46 Piotr Sikora via nginx-devel wrote:
> # HG changeset patch
> # User Piotr Sikora <piotrsikora at google.com>
> # Date 1493191954 25200
> # Wed Apr 26 00:32:34 2017 -0700
> # Node ID 8d74ff6c2015180f5c1f399f492214d7d0a52b3f
> # Parent 41c09a2fd90410e25ad8515793bd48028001c954
> HTTP/2: added support for trailers in HTTP responses.
>
> Signed-off-by: Piotr Sikora <piotrsikora at google.com>
>
> diff -r 41c09a2fd904 -r 8d74ff6c2015 src/http/v2/ngx_http_v2_filter_module.c
> --- a/src/http/v2/ngx_http_v2_filter_module.c
> +++ b/src/http/v2/ngx_http_v2_filter_module.c
> @@ -50,13 +50,17 @@
> #define NGX_HTTP_V2_SERVER_INDEX 54
> #define NGX_HTTP_V2_VARY_INDEX 59
>
> +#define NGX_HTTP_V2_FRAME_ERROR (ngx_http_v2_out_frame_t *) -1
> +
>
> static u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
> u_char *tmp, ngx_uint_t lower);
> static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix,
> ngx_uint_t value);
> static ngx_http_v2_out_frame_t *ngx_http_v2_create_headers_frame(
> - ngx_http_request_t *r, u_char *pos, u_char *end);
> + ngx_http_request_t *r, u_char *pos, u_char *end, ngx_uint_t fin);
> +static ngx_http_v2_out_frame_t *ngx_http_v2_create_trailers_frame(
> + ngx_http_request_t *r);
>
> static ngx_chain_t *ngx_http_v2_send_chain(ngx_connection_t *fc,
> ngx_chain_t *in, off_t limit);
> @@ -612,7 +616,7 @@ ngx_http_v2_header_filter(ngx_http_reque
> header[i].value.len, tmp);
> }
>
> - frame = ngx_http_v2_create_headers_frame(r, start, pos);
> + frame = ngx_http_v2_create_headers_frame(r, start, pos, r->header_only);
> if (frame == NULL) {
> return NGX_ERROR;
> }
> @@ -636,6 +640,126 @@ ngx_http_v2_header_filter(ngx_http_reque
> }
>
>
> +static ngx_http_v2_out_frame_t *
> +ngx_http_v2_create_trailers_frame(ngx_http_request_t *r)
> +{
[..]
> +
> + frame = ngx_http_v2_create_headers_frame(r, start, pos, 1);
> + if (frame == NULL) {
> + return NGX_HTTP_V2_FRAME_ERROR;
> + }
> +
> + return frame;
> +}
It's better to keep return values consistent with
ngx_http_v2_create_headers_frame() and introduce
NGX_HTTP_V2_NO_TRAILERS instead of NGX_HTTP_V2_FRAME_ERROR.
[..]
> @@ -934,17 +1060,36 @@ ngx_http_v2_send_chain(ngx_connection_t
> size -= rest;
> }
>
> - frame = ngx_http_v2_filter_get_data_frame(stream, frame_size, out, cl);
> - if (frame == NULL) {
> - return NGX_CHAIN_ERROR;
> + if (cl->buf->last_buf) {
> + trailers = ngx_http_v2_create_trailers_frame(r);
> + if (trailers == NGX_HTTP_V2_FRAME_ERROR) {
> + return NGX_CHAIN_ERROR;
> + }
> +
> + if (trailers) {
> + cl->buf->last_buf = 0;
> + }
> }
>
> - ngx_http_v2_queue_frame(h2c, frame);
> + if (frame_size || cl->buf->last_buf) {
> + frame = ngx_http_v2_filter_get_data_frame(stream, frame_size, out,
> + cl);
> + if (frame == NULL) {
> + return NGX_CHAIN_ERROR;
> + }
>
> - h2c->send_window -= frame_size;
> + ngx_http_v2_queue_frame(h2c, frame);
>
> - stream->send_window -= frame_size;
> - stream->queued++;
> + h2c->send_window -= frame_size;
> +
> + stream->send_window -= frame_size;
> + stream->queued++;
> + }
> +
> + if (trailers) {
> + ngx_http_v2_queue_frame(h2c, trailers);
> + stream->queued++;
> + }
>
> if (in == NULL) {
> break;
There's no reason to check "trailers" on each iteration.
I think you can put it inside the "if (in == NULL)" condition.
Please consider the changes below.
wbr, Valentin V. Bartenev
diff -r 0e2f2f8b5c9b src/http/v2/ngx_http_v2_filter_module.c
--- a/src/http/v2/ngx_http_v2_filter_module.c Wed Apr 26 00:32:34 2017 -0700
+++ b/src/http/v2/ngx_http_v2_filter_module.c Wed Jun 07 22:10:04 2017 +0300
@@ -50,7 +50,7 @@
#define NGX_HTTP_V2_SERVER_INDEX 54
#define NGX_HTTP_V2_VARY_INDEX 59
-#define NGX_HTTP_V2_FRAME_ERROR (ngx_http_v2_out_frame_t *) -1
+#define NGX_HTTP_V2_NO_TRAILERS (ngx_http_v2_out_frame_t *) -1
static u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
@@ -643,12 +643,11 @@ ngx_http_v2_header_filter(ngx_http_reque
static ngx_http_v2_out_frame_t *
ngx_http_v2_create_trailers_frame(ngx_http_request_t *r)
{
- u_char *pos, *start, *tmp;
- size_t len, tmp_len;
- ngx_uint_t i;
- ngx_list_part_t *part;
- ngx_table_elt_t *header;
- ngx_http_v2_out_frame_t *frame;
+ u_char *pos, *start, *tmp;
+ size_t len, tmp_len;
+ ngx_uint_t i;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *header;
len = 0;
tmp_len = 0;
@@ -677,7 +676,7 @@ ngx_http_v2_create_trailers_frame(ngx_ht
"too long response trailer name: \"%V\"",
&header[i].key);
- return NGX_HTTP_V2_FRAME_ERROR;
+ return NULL;
}
if (header[i].value.len > NGX_HTTP_V2_MAX_FIELD) {
@@ -685,7 +684,7 @@ ngx_http_v2_create_trailers_frame(ngx_ht
"too long response trailer value: \"%V: %V\"",
&header[i].key, &header[i].value);
- return NGX_HTTP_V2_FRAME_ERROR;
+ return NULL;
}
len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len
@@ -701,14 +700,14 @@ ngx_http_v2_create_trailers_frame(ngx_ht
}
if (len == 0) {
- return NULL;
+ return NGX_HTTP_V2_NO_TRAILERS;
}
tmp = ngx_palloc(r->pool, tmp_len);
pos = ngx_pnalloc(r->pool, len);
if (pos == NULL || tmp == NULL) {
- return NGX_HTTP_V2_FRAME_ERROR;
+ return NULL;
}
start = pos;
@@ -751,12 +750,7 @@ ngx_http_v2_create_trailers_frame(ngx_ht
header[i].value.len, tmp);
}
- frame = ngx_http_v2_create_headers_frame(r, start, pos, 1);
- if (frame == NULL) {
- return NGX_HTTP_V2_FRAME_ERROR;
- }
-
- return frame;
+ return ngx_http_v2_create_headers_frame(r, start, pos, 1);
}
@@ -996,7 +990,7 @@ ngx_http_v2_send_chain(ngx_connection_t
frame_size = (h2lcf->chunk_size < h2c->frame_size)
? h2lcf->chunk_size : h2c->frame_size;
- trailers = NULL;
+ trailers = NGX_HTTP_V2_NO_TRAILERS;
#if (NGX_SUPPRESS_WARN)
cl = NULL;
@@ -1062,18 +1056,18 @@ ngx_http_v2_send_chain(ngx_connection_t
if (cl->buf->last_buf) {
trailers = ngx_http_v2_create_trailers_frame(r);
- if (trailers == NGX_HTTP_V2_FRAME_ERROR) {
+ if (trailers == NULL) {
return NGX_CHAIN_ERROR;
}
- if (trailers) {
+ if (trailers != NGX_HTTP_V2_NO_TRAILERS) {
cl->buf->last_buf = 0;
}
}
if (frame_size || cl->buf->last_buf) {
- frame = ngx_http_v2_filter_get_data_frame(stream, frame_size, out,
- cl);
+ frame = ngx_http_v2_filter_get_data_frame(stream, frame_size,
+ out, cl);
if (frame == NULL) {
return NGX_CHAIN_ERROR;
}
@@ -1086,12 +1080,13 @@ ngx_http_v2_send_chain(ngx_connection_t
stream->queued++;
}
- if (trailers) {
- ngx_http_v2_queue_frame(h2c, trailers);
- stream->queued++;
- }
+ if (in == NULL) {
- if (in == NULL) {
+ if (trailers != NGX_HTTP_V2_NO_TRAILERS) {
+ ngx_http_v2_queue_frame(h2c, trailers);
+ stream->queued++;
+ }
+
break;
}
More information about the nginx-devel
mailing list