Mercurial > hg > nginx
annotate src/http/v3/ngx_http_v3_request.c @ 8292:46e3542d51b3 quic
Chunked response body in HTTP/3.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Fri, 27 Mar 2020 19:46:54 +0300 |
parents | 4feae8bc0ca9 |
children | 5649079a41f4 |
rev | line source |
---|---|
8215 | 1 |
2 /* | |
3 * Copyright (C) Roman Arutyunyan | |
4 * Copyright (C) Nginx, Inc. | |
5 */ | |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, | |
14 ngx_str_t *name, ngx_str_t *value); | |
15 | |
16 | |
17 struct { | |
18 ngx_str_t name; | |
19 ngx_uint_t method; | |
20 } ngx_http_v3_methods[] = { | |
21 | |
22 { ngx_string("GET"), NGX_HTTP_GET }, | |
23 { ngx_string("POST"), NGX_HTTP_POST }, | |
24 { ngx_string("HEAD"), NGX_HTTP_HEAD }, | |
25 { ngx_string("OPTIONS"), NGX_HTTP_OPTIONS }, | |
26 { ngx_string("PROPFIND"), NGX_HTTP_PROPFIND }, | |
27 { ngx_string("PUT"), NGX_HTTP_PUT }, | |
28 { ngx_string("MKCOL"), NGX_HTTP_MKCOL }, | |
29 { ngx_string("DELETE"), NGX_HTTP_DELETE }, | |
30 { ngx_string("COPY"), NGX_HTTP_COPY }, | |
31 { ngx_string("MOVE"), NGX_HTTP_MOVE }, | |
32 { ngx_string("PROPPATCH"), NGX_HTTP_PROPPATCH }, | |
33 { ngx_string("LOCK"), NGX_HTTP_LOCK }, | |
34 { ngx_string("UNLOCK"), NGX_HTTP_UNLOCK }, | |
35 { ngx_string("PATCH"), NGX_HTTP_PATCH }, | |
36 { ngx_string("TRACE"), NGX_HTTP_TRACE } | |
37 }; | |
38 | |
39 | |
40 ngx_int_t | |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
41 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b) |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
42 { |
8233
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
43 size_t n; |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
44 u_char *p; |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
45 ngx_int_t rc; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
46 ngx_str_t *name, *value; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
47 ngx_connection_t *c; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
48 ngx_http_v3_parse_headers_t *st; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
49 enum { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
50 sw_start = 0, |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
51 sw_prev, |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
52 sw_headers, |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
53 sw_last, |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
54 sw_done |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
55 }; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
56 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
57 c = r->connection; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
58 st = r->h3_parse; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
59 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
60 if (st == NULL) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
61 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header"); |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
62 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
63 st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_headers_t)); |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
64 if (st == NULL) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
65 goto failed; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
66 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
67 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
68 r->h3_parse = st; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
69 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
70 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
71 switch (r->state) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
72 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
73 case sw_prev: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
74 r->state = sw_headers; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
75 return NGX_OK; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
76 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
77 case sw_done: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
78 goto done; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
79 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
80 case sw_last: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
81 r->state = sw_done; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
82 return NGX_OK; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
83 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
84 default: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
85 break; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
86 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
87 |
8230
31f7c697b6d9
Fixed pointer increment while parsing HTTP/3 header.
Roman Arutyunyan <arut@nginx.com>
parents:
8226
diff
changeset
|
88 while (b->pos < b->last) { |
31f7c697b6d9
Fixed pointer increment while parsing HTTP/3 header.
Roman Arutyunyan <arut@nginx.com>
parents:
8226
diff
changeset
|
89 rc = ngx_http_v3_parse_headers(c, st, *b->pos++); |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
90 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
91 if (rc == NGX_ERROR) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
92 goto failed; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
93 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
94 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
95 if (rc == NGX_AGAIN) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
96 continue; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
97 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
98 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
99 name = &st->header_rep.header.name; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
100 value = &st->header_rep.header.value; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
101 |
8233
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
102 if (r->state == sw_start) { |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
103 |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
104 if (ngx_http_v3_process_pseudo_header(r, name, value) == NGX_OK) { |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
105 if (rc == NGX_OK) { |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
106 continue; |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
107 } |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
108 |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
109 r->state = sw_done; |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
110 |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
111 } else if (rc == NGX_OK) { |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
112 r->state = sw_prev; |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
113 |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
114 } else { |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
115 r->state = sw_last; |
8233
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
116 } |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
117 |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
118 n = (r->method_end - r->method_start) + 1 |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
119 + (r->uri_end - r->uri_start) + 1 |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
120 + sizeof("HTTP/3") - 1; |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
121 |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
122 p = ngx_pnalloc(c->pool, n); |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
123 if (p == NULL) { |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
124 goto failed; |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
125 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
126 |
8233
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
127 r->request_start = p; |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
128 |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
129 p = ngx_cpymem(p, r->method_start, r->method_end - r->method_start); |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
130 *p++ = ' '; |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
131 p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start); |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
132 *p++ = ' '; |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
133 p = ngx_cpymem(p, "HTTP/3", sizeof("HTTP/3") - 1); |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
134 |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
135 r->request_end = p; |
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
136 |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
137 } else if (rc == NGX_DONE) { |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
138 r->state = sw_done; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
139 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
140 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
141 r->header_name_start = name->data; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
142 r->header_name_end = name->data + name->len; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
143 r->header_start = value->data; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
144 r->header_end = value->data + value->len; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
145 r->header_hash = ngx_hash_key(name->data, name->len); |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
146 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
147 /* XXX r->lowcase_index = i; */ |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
148 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
149 return NGX_OK; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
150 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
151 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
152 return NGX_AGAIN; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
153 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
154 failed: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
155 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
156 return r->state == sw_start ? NGX_HTTP_PARSE_INVALID_REQUEST |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
157 : NGX_HTTP_PARSE_INVALID_HEADER; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
158 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
159 done: |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
160 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
161 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header done"); |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
162 |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
163 return NGX_HTTP_PARSE_HEADER_DONE; |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
164 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
165 |
8215 | 166 |
167 static ngx_int_t | |
168 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name, | |
169 ngx_str_t *value) | |
170 { | |
171 ngx_uint_t i; | |
172 ngx_connection_t *c; | |
173 | |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
174 if (name->len == 0 || name->data[0] != ':') { |
8233
1e45c02f6376
HTTP/3 $request_line variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8230
diff
changeset
|
175 return NGX_DONE; |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
176 } |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
177 |
8215 | 178 c = r->connection; |
179 | |
180 if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) { | |
181 r->method_start = value->data; | |
182 r->method_end = value->data + value->len; | |
183 | |
184 for (i = 0; i < sizeof(ngx_http_v3_methods) | |
185 / sizeof(ngx_http_v3_methods[0]); i++) | |
186 { | |
187 if (value->len == ngx_http_v3_methods[i].name.len | |
188 && ngx_strncmp(value->data, ngx_http_v3_methods[i].name.data, | |
189 value->len) == 0) | |
190 { | |
191 r->method = ngx_http_v3_methods[i].method; | |
192 break; | |
193 } | |
194 } | |
195 | |
196 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
197 "http3 method \"%V\" %ui", value, r->method); | |
198 return NGX_OK; | |
199 } | |
200 | |
201 if (name->len == 5 && ngx_strncmp(name->data, ":path", 5) == 0) { | |
202 r->uri_start = value->data; | |
203 r->uri_end = value->data + value->len; | |
204 | |
205 if (ngx_http_parse_uri(r) != NGX_OK) { | |
206 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
207 "client sent invalid :path header: \"%V\"", value); | |
208 return NGX_ERROR; | |
209 } | |
210 | |
211 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
212 "http3 path \"%V\"", value); | |
213 | |
214 return NGX_OK; | |
215 } | |
216 | |
217 if (name->len == 7 && ngx_strncmp(name->data, ":scheme", 7) == 0) { | |
218 r->schema_start = value->data; | |
219 r->schema_end = value->data + value->len; | |
220 | |
221 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
222 "http3 schema \"%V\"", value); | |
223 | |
224 return NGX_OK; | |
225 } | |
226 | |
227 if (name->len == 10 && ngx_strncmp(name->data, ":authority", 10) == 0) { | |
228 r->host_start = value->data; | |
229 r->host_end = value->data + value->len; | |
230 | |
231 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
232 "http3 authority \"%V\"", value); | |
233 | |
234 return NGX_OK; | |
235 } | |
236 | |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
237 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, |
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
238 "http3 unknown pseudo header \"%V\" \"%V\"", name, value); |
8215 | 239 |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
240 return NGX_OK; |
8215 | 241 } |
242 | |
243 | |
244 ngx_chain_t * | |
245 ngx_http_v3_create_header(ngx_http_request_t *r) | |
246 { | |
247 u_char *p; | |
8253
69365c7bb07f
Removed unused variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8238
diff
changeset
|
248 size_t len, n; |
8215 | 249 ngx_buf_t *b; |
250 ngx_uint_t i, j; | |
251 ngx_chain_t *hl, *cl, *bl; | |
252 ngx_list_part_t *part; | |
253 ngx_table_elt_t *header; | |
254 ngx_connection_t *c; | |
255 ngx_http_core_loc_conf_t *clcf; | |
256 | |
257 c = r->connection; | |
258 | |
259 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 create header"); | |
260 | |
8291 | 261 len = 2; |
8215 | 262 |
263 if (r->headers_out.status == NGX_HTTP_OK) { | |
264 len += ngx_http_v3_encode_prefix_int(NULL, 25, 6); | |
265 | |
266 } else { | |
267 len += 3 + ngx_http_v3_encode_prefix_int(NULL, 25, 4) | |
268 + ngx_http_v3_encode_prefix_int(NULL, 3, 7); | |
269 } | |
270 | |
271 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
272 | |
273 if (r->headers_out.server == NULL) { | |
274 if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) { | |
275 n = sizeof(NGINX_VER) - 1; | |
276 | |
277 } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) { | |
278 n = sizeof(NGINX_VER_BUILD) - 1; | |
279 | |
280 } else { | |
281 n = sizeof("nginx") - 1; | |
282 } | |
283 | |
284 len += ngx_http_v3_encode_prefix_int(NULL, 92, 4) | |
285 + ngx_http_v3_encode_prefix_int(NULL, n, 7) + n; | |
286 } | |
287 | |
288 if (r->headers_out.date == NULL) { | |
289 len += ngx_http_v3_encode_prefix_int(NULL, 6, 4) | |
290 + ngx_http_v3_encode_prefix_int(NULL, ngx_cached_http_time.len, | |
291 7) | |
292 + ngx_cached_http_time.len; | |
293 } | |
294 | |
295 if (r->headers_out.content_type.len) { | |
296 n = r->headers_out.content_type.len; | |
297 | |
298 if (r->headers_out.content_type_len == r->headers_out.content_type.len | |
299 && r->headers_out.charset.len) | |
300 { | |
301 n += sizeof("; charset=") - 1 + r->headers_out.charset.len; | |
302 } | |
303 | |
304 len += ngx_http_v3_encode_prefix_int(NULL, 53, 4) | |
305 + ngx_http_v3_encode_prefix_int(NULL, n, 7) + n; | |
306 } | |
307 | |
8238
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
308 if (r->headers_out.content_length_n > 0) { |
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
309 len += ngx_http_v3_encode_prefix_int(NULL, 4, 4) + 1 + NGX_OFF_T_LEN; |
8215 | 310 |
8238
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
311 } else if (r->headers_out.content_length_n == 0) { |
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
312 len += ngx_http_v3_encode_prefix_int(NULL, 4, 6); |
8215 | 313 } |
314 | |
315 if (r->headers_out.last_modified == NULL | |
316 && r->headers_out.last_modified_time != -1) | |
317 { | |
318 len += ngx_http_v3_encode_prefix_int(NULL, 10, 4) + 1 | |
319 + sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT"); | |
320 } | |
321 | |
322 /* XXX location */ | |
323 | |
324 #if (NGX_HTTP_GZIP) | |
325 if (r->gzip_vary) { | |
326 if (clcf->gzip_vary) { | |
327 /* Vary: Accept-Encoding */ | |
328 len += ngx_http_v3_encode_prefix_int(NULL, 59, 6); | |
329 | |
330 } else { | |
331 r->gzip_vary = 0; | |
332 } | |
333 } | |
334 #endif | |
335 | |
336 part = &r->headers_out.headers.part; | |
337 header = part->elts; | |
338 | |
339 for (i = 0; /* void */; i++) { | |
340 | |
341 if (i >= part->nelts) { | |
342 if (part->next == NULL) { | |
343 break; | |
344 } | |
345 | |
346 part = part->next; | |
347 header = part->elts; | |
348 i = 0; | |
349 } | |
350 | |
351 if (header[i].hash == 0) { | |
352 continue; | |
353 } | |
354 | |
355 len += ngx_http_v3_encode_prefix_int(NULL, header[i].key.len, 3) | |
356 + header[i].key.len | |
357 + ngx_http_v3_encode_prefix_int(NULL, header[i].value.len, 7 ) | |
358 + header[i].value.len; | |
359 } | |
360 | |
361 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 header len:%uz", len); | |
362 | |
363 b = ngx_create_temp_buf(r->pool, len); | |
364 if (b == NULL) { | |
365 return NULL; | |
366 } | |
367 | |
368 *b->last++ = 0; | |
369 *b->last++ = 0; | |
370 | |
371 if (r->headers_out.status == NGX_HTTP_OK) { | |
372 /* :status: 200 */ | |
373 *b->last = 0xc0; | |
374 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 25, 6); | |
375 | |
376 } else { | |
377 /* :status: 200 */ | |
378 *b->last = 0x70; | |
379 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 25, 4); | |
380 *b->last = 0; | |
381 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 3, 7); | |
8226
268f4389130d
Refactored HTTP/3 parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8219
diff
changeset
|
382 b->last = ngx_sprintf(b->last, "%03ui", r->headers_out.status); |
8215 | 383 } |
384 | |
385 if (r->headers_out.server == NULL) { | |
386 if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) { | |
387 p = (u_char *) NGINX_VER; | |
388 n = sizeof(NGINX_VER) - 1; | |
389 | |
390 } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) { | |
391 p = (u_char *) NGINX_VER_BUILD; | |
392 n = sizeof(NGINX_VER_BUILD) - 1; | |
393 | |
394 } else { | |
395 p = (u_char *) "nginx"; | |
396 n = sizeof("nginx") - 1; | |
397 } | |
398 | |
399 /* server */ | |
400 *b->last = 0x70; | |
401 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 92, 4); | |
402 *b->last = 0; | |
403 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, n, 7); | |
404 b->last = ngx_cpymem(b->last, p, n); | |
405 } | |
406 | |
407 if (r->headers_out.date == NULL) { | |
408 /* date */ | |
409 *b->last = 0x70; | |
410 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 6, 4); | |
411 *b->last = 0; | |
412 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, | |
413 ngx_cached_http_time.len, 7); | |
414 b->last = ngx_cpymem(b->last, ngx_cached_http_time.data, | |
415 ngx_cached_http_time.len); | |
416 } | |
417 | |
418 if (r->headers_out.content_type.len) { | |
419 n = r->headers_out.content_type.len; | |
420 | |
421 if (r->headers_out.content_type_len == r->headers_out.content_type.len | |
422 && r->headers_out.charset.len) | |
423 { | |
424 n += sizeof("; charset=") - 1 + r->headers_out.charset.len; | |
425 } | |
426 | |
427 /* content-type: text/plain */ | |
428 *b->last = 0x70; | |
429 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 53, 4); | |
430 *b->last = 0; | |
431 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, n, 7); | |
432 | |
433 p = b->last; | |
434 b->last = ngx_copy(b->last, r->headers_out.content_type.data, | |
435 r->headers_out.content_type.len); | |
436 | |
437 if (r->headers_out.content_type_len == r->headers_out.content_type.len | |
438 && r->headers_out.charset.len) | |
439 { | |
440 b->last = ngx_cpymem(b->last, "; charset=", | |
441 sizeof("; charset=") - 1); | |
442 b->last = ngx_copy(b->last, r->headers_out.charset.data, | |
443 r->headers_out.charset.len); | |
444 | |
445 /* update r->headers_out.content_type for possible logging */ | |
446 | |
447 r->headers_out.content_type.len = b->last - p; | |
448 r->headers_out.content_type.data = p; | |
449 } | |
450 } | |
451 | |
8238
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
452 if (r->headers_out.content_length_n > 0) { |
8215 | 453 /* content-length: 0 */ |
454 *b->last = 0x70; | |
455 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 4, 4); | |
456 p = b->last++; | |
457 b->last = ngx_sprintf(b->last, "%O", r->headers_out.content_length_n); | |
458 *p = b->last - p - 1; | |
8238
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
459 |
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
460 } else if (r->headers_out.content_length_n == 0) { |
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
461 /* content-length: 0 */ |
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
462 *b->last = 0xc0; |
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
463 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 4, 6); |
8215 | 464 } |
465 | |
466 if (r->headers_out.last_modified == NULL | |
467 && r->headers_out.last_modified_time != -1) | |
468 { | |
469 /* last-modified */ | |
470 *b->last = 0x70; | |
471 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 10, 4); | |
472 p = b->last++; | |
473 b->last = ngx_http_time(b->last, r->headers_out.last_modified_time); | |
474 *p = b->last - p - 1; | |
475 } | |
476 | |
477 #if (NGX_HTTP_GZIP) | |
478 if (r->gzip_vary) { | |
479 /* vary: accept-encoding */ | |
480 *b->last = 0xc0; | |
481 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, 59, 6); | |
482 } | |
483 #endif | |
484 | |
485 part = &r->headers_out.headers.part; | |
486 header = part->elts; | |
487 | |
488 for (i = 0; /* void */; i++) { | |
489 | |
490 if (i >= part->nelts) { | |
491 if (part->next == NULL) { | |
492 break; | |
493 } | |
494 | |
495 part = part->next; | |
496 header = part->elts; | |
497 i = 0; | |
498 } | |
499 | |
500 if (header[i].hash == 0) { | |
501 continue; | |
502 } | |
503 | |
504 *b->last = 0x30; | |
505 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, | |
506 header[i].key.len, | |
507 3); | |
508 for (j = 0; j < header[i].key.len; j++) { | |
509 *b->last++ = ngx_tolower(header[i].key.data[j]); | |
510 } | |
511 | |
512 *b->last = 0; | |
513 b->last = (u_char *) ngx_http_v3_encode_prefix_int(b->last, | |
514 header[i].value.len, | |
515 7); | |
516 b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); | |
517 } | |
518 | |
8238
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
519 if (r->header_only) { |
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
520 b->last_buf = 1; |
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
521 } |
a3257a725b3d
Fixed header creation for header_only responses in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8233
diff
changeset
|
522 |
8215 | 523 cl = ngx_alloc_chain_link(c->pool); |
524 if (cl == NULL) { | |
525 return NULL; | |
526 } | |
527 | |
528 cl->buf = b; | |
529 cl->next = NULL; | |
530 | |
531 n = b->last - b->pos; | |
532 | |
533 len = 1 + ngx_http_v3_encode_varlen_int(NULL, n); | |
534 | |
535 b = ngx_create_temp_buf(c->pool, len); | |
536 if (b == NULL) { | |
537 return NULL; | |
538 } | |
539 | |
540 *b->last++ = NGX_HTTP_V3_FRAME_HEADERS; | |
541 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, n); | |
542 | |
543 hl = ngx_alloc_chain_link(c->pool); | |
544 if (hl == NULL) { | |
545 return NULL; | |
546 } | |
547 | |
548 hl->buf = b; | |
549 hl->next = cl; | |
550 | |
551 if (r->headers_out.content_length_n >= 0) { | |
552 len = 1 + ngx_http_v3_encode_varlen_int(NULL, | |
553 r->headers_out.content_length_n); | |
554 | |
555 b = ngx_create_temp_buf(c->pool, len); | |
556 if (b == NULL) { | |
557 NULL; | |
558 } | |
559 | |
560 *b->last++ = NGX_HTTP_V3_FRAME_DATA; | |
561 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, | |
562 r->headers_out.content_length_n); | |
563 | |
564 bl = ngx_alloc_chain_link(c->pool); | |
565 if (bl == NULL) { | |
566 return NULL; | |
567 } | |
568 | |
569 bl->buf = b; | |
570 bl->next = NULL; | |
571 cl->next = bl; | |
572 } | |
573 | |
574 return hl; | |
575 } | |
8292
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
576 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
577 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
578 ngx_chain_t * |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
579 ngx_http_v3_create_trailers(ngx_http_request_t *r) |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
580 { |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
581 ngx_buf_t *b; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
582 ngx_chain_t *cl; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
583 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
584 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
585 "http3 create trailers"); |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
586 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
587 /* XXX */ |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
588 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
589 b = ngx_calloc_buf(r->pool); |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
590 if (b == NULL) { |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
591 return NULL; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
592 } |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
593 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
594 b->last_buf = 1; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
595 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
596 cl = ngx_alloc_chain_link(r->pool); |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
597 if (cl == NULL) { |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
598 return NULL; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
599 } |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
600 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
601 cl->buf = b; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
602 cl->next = NULL; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
603 |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
604 return cl; |
46e3542d51b3
Chunked response body in HTTP/3.
Roman Arutyunyan <arut@nginx.com>
parents:
8291
diff
changeset
|
605 } |