Mercurial > hg > nginx
annotate src/http/v3/ngx_http_v3_parse.c @ 8549:d70a38acaea0 quic
HTTP/3: skip unknown frames on request stream.
As per HTTP/3 draft 29, section 4.1:
Frames of unknown types (Section 9), including reserved frames
(Section 7.2.8) MAY be sent on a request or push stream before,
after, or interleaved with other frames described in this section.
Also, trailers frame is now used as an indication of the request body end.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Mon, 24 Aug 2020 09:56:36 +0300 |
parents | 0596fe1aee16 |
children | 234e9d89ff7f |
rev | line source |
---|---|
8226 | 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 | |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
13 static ngx_int_t ngx_http_v3_parse_lookup(ngx_connection_t *c, |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
14 ngx_uint_t dynamic, ngx_uint_t index, ngx_str_t *name, ngx_str_t *value); |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
15 |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
16 |
8226 | 17 ngx_int_t |
18 ngx_http_v3_parse_varlen_int(ngx_connection_t *c, | |
19 ngx_http_v3_parse_varlen_int_t *st, u_char ch) | |
20 { | |
21 enum { | |
22 sw_start = 0, | |
23 sw_length_2, | |
24 sw_length_3, | |
25 sw_length_4, | |
26 sw_length_5, | |
27 sw_length_6, | |
28 sw_length_7, | |
29 sw_length_8 | |
30 }; | |
31 | |
32 switch (st->state) { | |
33 | |
34 case sw_start: | |
35 | |
36 st->value = ch; | |
37 if (st->value & 0xc0) { | |
38 st->state = sw_length_2; | |
39 break; | |
40 } | |
41 | |
42 goto done; | |
43 | |
44 case sw_length_2: | |
45 | |
46 st->value = (st->value << 8) + ch; | |
47 if ((st->value & 0xc000) == 0x4000) { | |
48 st->value &= 0x3fff; | |
49 goto done; | |
50 } | |
51 | |
52 st->state = sw_length_3; | |
53 break; | |
54 | |
55 case sw_length_4: | |
56 | |
57 st->value = (st->value << 8) + ch; | |
58 if ((st->value & 0xc0000000) == 0x80000000) { | |
59 st->value &= 0x3fffffff; | |
60 goto done; | |
61 } | |
62 | |
63 st->state = sw_length_5; | |
64 break; | |
65 | |
66 case sw_length_3: | |
67 case sw_length_5: | |
68 case sw_length_6: | |
69 case sw_length_7: | |
70 | |
71 st->value = (st->value << 8) + ch; | |
72 st->state++; | |
73 break; | |
74 | |
75 case sw_length_8: | |
76 | |
77 st->value = (st->value << 8) + ch; | |
78 st->value &= 0x3fffffffffffffff; | |
79 goto done; | |
80 } | |
81 | |
82 return NGX_AGAIN; | |
83 | |
84 done: | |
85 | |
86 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
87 "http3 parse varlen int %uL", st->value); | |
88 | |
89 st->state = sw_start; | |
90 return NGX_DONE; | |
91 } | |
92 | |
93 | |
94 ngx_int_t | |
95 ngx_http_v3_parse_prefix_int(ngx_connection_t *c, | |
96 ngx_http_v3_parse_prefix_int_t *st, ngx_uint_t prefix, u_char ch) | |
97 { | |
8455
b0e81f49d7c0
HTTP/3: fixed prefixed integer encoding and decoding.
Roman Arutyunyan <arut@nginx.com>
parents:
8454
diff
changeset
|
98 ngx_uint_t mask; |
8226 | 99 enum { |
100 sw_start = 0, | |
101 sw_value | |
102 }; | |
103 | |
104 switch (st->state) { | |
105 | |
106 case sw_start: | |
107 | |
8455
b0e81f49d7c0
HTTP/3: fixed prefixed integer encoding and decoding.
Roman Arutyunyan <arut@nginx.com>
parents:
8454
diff
changeset
|
108 mask = (1 << prefix) - 1; |
b0e81f49d7c0
HTTP/3: fixed prefixed integer encoding and decoding.
Roman Arutyunyan <arut@nginx.com>
parents:
8454
diff
changeset
|
109 st->value = ch & mask; |
8226 | 110 |
8455
b0e81f49d7c0
HTTP/3: fixed prefixed integer encoding and decoding.
Roman Arutyunyan <arut@nginx.com>
parents:
8454
diff
changeset
|
111 if (st->value != mask) { |
8226 | 112 goto done; |
113 } | |
114 | |
8455
b0e81f49d7c0
HTTP/3: fixed prefixed integer encoding and decoding.
Roman Arutyunyan <arut@nginx.com>
parents:
8454
diff
changeset
|
115 st->shift = 0; |
8226 | 116 st->state = sw_value; |
117 break; | |
118 | |
119 case sw_value: | |
120 | |
8463
2576485b93d4
HTTP/3: fixed overflow in prefixed integer parser.
Roman Arutyunyan <arut@nginx.com>
parents:
8462
diff
changeset
|
121 st->value += (uint64_t) (ch & 0x7f) << st->shift; |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
122 |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
123 if (st->shift == 56 |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
124 && ((ch & 0x80) || (st->value & 0xc000000000000000))) |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
125 { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
126 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
127 "client exceeded integer size limit"); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
128 return NGX_HTTP_V3_ERR_EXCESSIVE_LOAD; |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
129 } |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
130 |
8226 | 131 if (ch & 0x80) { |
8455
b0e81f49d7c0
HTTP/3: fixed prefixed integer encoding and decoding.
Roman Arutyunyan <arut@nginx.com>
parents:
8454
diff
changeset
|
132 st->shift += 7; |
8226 | 133 break; |
134 } | |
135 | |
136 goto done; | |
137 } | |
138 | |
139 return NGX_AGAIN; | |
140 | |
141 done: | |
142 | |
143 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
144 "http3 parse prefix int %uL", st->value); | |
145 | |
146 st->state = sw_start; | |
147 return NGX_DONE; | |
148 } | |
149 | |
150 | |
151 ngx_int_t | |
152 ngx_http_v3_parse_headers(ngx_connection_t *c, ngx_http_v3_parse_headers_t *st, | |
153 u_char ch) | |
154 { | |
155 ngx_int_t rc; | |
156 enum { | |
157 sw_start = 0, | |
8549
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
158 sw_type, |
8226 | 159 sw_length, |
8549
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
160 sw_skip, |
8226 | 161 sw_prefix, |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
162 sw_verify, |
8226 | 163 sw_header_rep, |
164 sw_done | |
165 }; | |
166 | |
167 switch (st->state) { | |
168 | |
169 case sw_start: | |
170 | |
171 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse headers"); | |
172 | |
8549
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
173 st->state = sw_type; |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
174 |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
175 /* fall through */ |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
176 |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
177 case sw_type: |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
178 |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
179 rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, ch); |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
180 if (rc != NGX_DONE) { |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
181 return rc; |
8226 | 182 } |
183 | |
8549
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
184 st->type = st->vlint.value; |
8226 | 185 st->state = sw_length; |
186 break; | |
187 | |
188 case sw_length: | |
189 | |
8466
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
190 rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, ch); |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
191 if (rc != NGX_DONE) { |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
192 return rc; |
8226 | 193 } |
194 | |
195 st->length = st->vlint.value; | |
196 | |
8549
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
197 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
198 "http3 parse headers type:%ui, len:%ui", |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
199 st->type, st->length); |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
200 |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
201 if (st->type != NGX_HTTP_V3_FRAME_HEADERS) { |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
202 st->state = st->length > 0 ? sw_skip : sw_type; |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
203 break; |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
204 } |
8226 | 205 |
206 st->state = sw_prefix; | |
207 break; | |
208 | |
8549
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
209 case sw_skip: |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
210 |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
211 if (--st->length == 0) { |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
212 st->state = sw_type; |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
213 } |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
214 |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
215 break; |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
216 |
8226 | 217 case sw_prefix: |
218 | |
219 if (st->length-- == 0) { | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
220 return NGX_HTTP_V3_ERR_FRAME_ERROR; |
8226 | 221 } |
222 | |
223 rc = ngx_http_v3_parse_header_block_prefix(c, &st->prefix, ch); | |
224 if (rc != NGX_DONE) { | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
225 return rc; |
8226 | 226 } |
227 | |
228 if (st->length == 0) { | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
229 return NGX_HTTP_V3_ERR_FRAME_ERROR; |
8226 | 230 } |
231 | |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
232 st->state = sw_verify; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
233 break; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
234 |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
235 case sw_verify: |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
236 |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
237 rc = ngx_http_v3_check_insert_count(c, st->prefix.insert_count); |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
238 if (rc != NGX_OK) { |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
239 return rc; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
240 } |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
241 |
8226 | 242 st->state = sw_header_rep; |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
243 |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
244 /* fall through */ |
8226 | 245 |
246 case sw_header_rep: | |
247 | |
248 rc = ngx_http_v3_parse_header_rep(c, &st->header_rep, st->prefix.base, | |
249 ch); | |
250 | |
8467
e02250b55b17
HTTP/3: simplified handling return codes from parse functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8466
diff
changeset
|
251 if (--st->length == 0 && rc == NGX_AGAIN) { |
e02250b55b17
HTTP/3: simplified handling return codes from parse functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8466
diff
changeset
|
252 return NGX_HTTP_V3_ERR_FRAME_ERROR; |
8226 | 253 } |
254 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
255 if (rc != NGX_DONE) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
256 return rc; |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
257 } |
8226 | 258 |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
259 if (st->length == 0) { |
8226 | 260 goto done; |
261 } | |
262 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
263 return NGX_OK; |
8226 | 264 } |
265 | |
266 return NGX_AGAIN; | |
267 | |
268 done: | |
269 | |
270 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse headers done"); | |
271 | |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
272 if (st->prefix.insert_count > 0) { |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
273 if (ngx_http_v3_client_ack_header(c, c->qs->id) != NGX_OK) { |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
274 return NGX_ERROR; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
275 } |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
276 } |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
277 |
8226 | 278 st->state = sw_start; |
279 return NGX_DONE; | |
280 } | |
281 | |
282 | |
283 ngx_int_t | |
284 ngx_http_v3_parse_header_block_prefix(ngx_connection_t *c, | |
285 ngx_http_v3_parse_header_block_prefix_t *st, u_char ch) | |
286 { | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
287 ngx_int_t rc; |
8226 | 288 enum { |
289 sw_start = 0, | |
290 sw_req_insert_count, | |
291 sw_delta_base, | |
292 sw_read_delta_base | |
293 }; | |
294 | |
295 switch (st->state) { | |
296 | |
297 case sw_start: | |
298 | |
299 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
300 "http3 parse header block prefix"); | |
301 | |
302 st->state = sw_req_insert_count; | |
303 | |
304 /* fall through */ | |
305 | |
306 case sw_req_insert_count: | |
307 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
308 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 8, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
309 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
310 return rc; |
8226 | 311 } |
312 | |
313 st->insert_count = st->pint.value; | |
314 st->state = sw_delta_base; | |
315 break; | |
316 | |
317 case sw_delta_base: | |
318 | |
319 st->sign = (ch & 0x80) ? 1 : 0; | |
320 st->state = sw_read_delta_base; | |
321 | |
322 /* fall through */ | |
323 | |
324 case sw_read_delta_base: | |
325 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
326 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
327 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
328 return rc; |
8226 | 329 } |
330 | |
331 st->delta_base = st->pint.value; | |
332 goto done; | |
333 } | |
334 | |
335 return NGX_AGAIN; | |
336 | |
337 done: | |
338 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
339 rc = ngx_http_v3_decode_insert_count(c, &st->insert_count); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
340 if (rc != NGX_OK) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
341 return rc; |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
342 } |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
343 |
8226 | 344 if (st->sign) { |
345 st->base = st->insert_count - st->delta_base - 1; | |
346 } else { | |
347 st->base = st->insert_count + st->delta_base; | |
348 } | |
349 | |
350 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
351 "http3 parse header block prefix done " | |
8478
d2f716e668e8
Fixed format specifiers.
Sergey Kandaurov <pluknet@nginx.com>
parents:
8467
diff
changeset
|
352 "insert_count:%ui, sign:%ui, delta_base:%ui, base:%ui", |
8226 | 353 st->insert_count, st->sign, st->delta_base, st->base); |
354 | |
355 st->state = sw_start; | |
356 return NGX_DONE; | |
357 } | |
358 | |
359 | |
360 ngx_int_t | |
361 ngx_http_v3_parse_header_rep(ngx_connection_t *c, | |
362 ngx_http_v3_parse_header_rep_t *st, ngx_uint_t base, u_char ch) | |
363 { | |
364 ngx_int_t rc; | |
365 enum { | |
366 sw_start = 0, | |
367 sw_header_ri, | |
368 sw_header_lri, | |
369 sw_header_l, | |
370 sw_header_pbi, | |
371 sw_header_lpbi | |
372 }; | |
373 | |
374 if (st->state == sw_start) { | |
375 | |
376 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
377 "http3 parse header representation"); | |
378 | |
379 ngx_memzero(&st->header, sizeof(ngx_http_v3_parse_header_t)); | |
380 | |
381 st->header.base = base; | |
382 | |
383 if (ch & 0x80) { | |
384 /* Indexed Header Field */ | |
385 | |
386 st->state = sw_header_ri; | |
387 | |
388 } else if (ch & 0x40) { | |
389 /* Literal Header Field With Name Reference */ | |
390 | |
391 st->state = sw_header_lri; | |
392 | |
393 } else if (ch & 0x20) { | |
394 /* Literal Header Field Without Name Reference */ | |
395 | |
396 st->state = sw_header_l; | |
397 | |
398 } else if (ch & 0x10) { | |
399 /* Indexed Header Field With Post-Base Index */ | |
400 | |
401 st->state = sw_header_pbi; | |
402 | |
403 } else { | |
404 /* Literal Header Field With Post-Base Name Reference */ | |
405 | |
406 st->state = sw_header_lpbi; | |
407 } | |
408 } | |
409 | |
410 switch (st->state) { | |
411 | |
412 case sw_header_ri: | |
413 rc = ngx_http_v3_parse_header_ri(c, &st->header, ch); | |
414 break; | |
415 | |
416 case sw_header_lri: | |
417 rc = ngx_http_v3_parse_header_lri(c, &st->header, ch); | |
418 break; | |
419 | |
420 case sw_header_l: | |
421 rc = ngx_http_v3_parse_header_l(c, &st->header, ch); | |
422 break; | |
423 | |
424 case sw_header_pbi: | |
425 rc = ngx_http_v3_parse_header_pbi(c, &st->header, ch); | |
426 break; | |
427 | |
428 case sw_header_lpbi: | |
429 rc = ngx_http_v3_parse_header_lpbi(c, &st->header, ch); | |
430 break; | |
431 | |
432 default: | |
433 rc = NGX_OK; | |
434 } | |
435 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
436 if (rc != NGX_DONE) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
437 return rc; |
8226 | 438 } |
439 | |
440 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
441 "http3 parse header representation done"); | |
442 | |
443 st->state = sw_start; | |
444 return NGX_DONE; | |
445 } | |
446 | |
447 | |
448 ngx_int_t | |
449 ngx_http_v3_parse_literal(ngx_connection_t *c, ngx_http_v3_parse_literal_t *st, | |
450 u_char ch) | |
451 { | |
8454
032cb35ce758
HTTP/3: http3_max_field_size directive to limit string size.
Roman Arutyunyan <arut@nginx.com>
parents:
8295
diff
changeset
|
452 ngx_uint_t n; |
8492
65c1fc5fae15
HTTP/3: renamed server configuration variables from v3cf to h3scf.
Roman Arutyunyan <arut@nginx.com>
parents:
8478
diff
changeset
|
453 ngx_http_v3_srv_conf_t *h3scf; |
8226 | 454 enum { |
455 sw_start = 0, | |
456 sw_value | |
457 }; | |
458 | |
459 switch (st->state) { | |
460 | |
461 case sw_start: | |
462 | |
463 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
464 "http3 parse literal huff:%ui, len:%ui", | |
465 st->huffman, st->length); | |
466 | |
467 n = st->length; | |
468 | |
8492
65c1fc5fae15
HTTP/3: renamed server configuration variables from v3cf to h3scf.
Roman Arutyunyan <arut@nginx.com>
parents:
8478
diff
changeset
|
469 h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module); |
8454
032cb35ce758
HTTP/3: http3_max_field_size directive to limit string size.
Roman Arutyunyan <arut@nginx.com>
parents:
8295
diff
changeset
|
470 |
8492
65c1fc5fae15
HTTP/3: renamed server configuration variables from v3cf to h3scf.
Roman Arutyunyan <arut@nginx.com>
parents:
8478
diff
changeset
|
471 if (n > h3scf->max_field_size) { |
8457
a7f64438aa3c
HTTP/3: downgraded literal size error level to NGX_LOG_INFO.
Roman Arutyunyan <arut@nginx.com>
parents:
8456
diff
changeset
|
472 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
8454
032cb35ce758
HTTP/3: http3_max_field_size directive to limit string size.
Roman Arutyunyan <arut@nginx.com>
parents:
8295
diff
changeset
|
473 "client exceeded http3_max_field_size limit"); |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
474 return NGX_HTTP_V3_ERR_EXCESSIVE_LOAD; |
8454
032cb35ce758
HTTP/3: http3_max_field_size directive to limit string size.
Roman Arutyunyan <arut@nginx.com>
parents:
8295
diff
changeset
|
475 } |
032cb35ce758
HTTP/3: http3_max_field_size directive to limit string size.
Roman Arutyunyan <arut@nginx.com>
parents:
8295
diff
changeset
|
476 |
8226 | 477 if (st->huffman) { |
478 n = n * 8 / 5; | |
479 st->huffstate = 0; | |
480 } | |
481 | |
482 st->last = ngx_pnalloc(c->pool, n + 1); | |
483 if (st->last == NULL) { | |
484 return NGX_ERROR; | |
485 } | |
486 | |
487 st->value.data = st->last; | |
488 st->state = sw_value; | |
489 | |
490 /* fall through */ | |
491 | |
492 case sw_value: | |
493 | |
494 if (st->huffman) { | |
495 if (ngx_http_v2_huff_decode(&st->huffstate, &ch, 1, &st->last, | |
496 st->length == 1, c->log) | |
497 != NGX_OK) | |
498 { | |
499 return NGX_ERROR; | |
500 } | |
501 | |
502 } else { | |
503 *st->last++ = ch; | |
504 } | |
505 | |
506 if (--st->length) { | |
507 break; | |
508 } | |
509 | |
510 st->value.len = st->last - st->value.data; | |
511 *st->last = '\0'; | |
512 goto done; | |
513 } | |
514 | |
515 return NGX_AGAIN; | |
516 | |
517 done: | |
518 | |
519 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
520 "http3 parse literal done \"%V\"", &st->value); | |
521 | |
522 st->state = sw_start; | |
523 return NGX_DONE; | |
524 } | |
525 | |
526 | |
527 ngx_int_t | |
528 ngx_http_v3_parse_header_ri(ngx_connection_t *c, ngx_http_v3_parse_header_t *st, | |
529 u_char ch) | |
530 { | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
531 ngx_int_t rc; |
8226 | 532 enum { |
533 sw_start = 0, | |
534 sw_index | |
535 }; | |
536 | |
537 switch (st->state) { | |
538 | |
539 case sw_start: | |
540 | |
541 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header ri"); | |
542 | |
543 st->dynamic = (ch & 0x40) ? 0 : 1; | |
544 st->state = sw_index; | |
545 | |
546 /* fall through */ | |
547 | |
548 case sw_index: | |
549 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
550 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 6, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
551 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
552 return rc; |
8226 | 553 } |
554 | |
555 st->index = st->pint.value; | |
556 goto done; | |
557 } | |
558 | |
559 return NGX_AGAIN; | |
560 | |
561 done: | |
562 | |
563 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
564 "http3 parse header ri done %s%ui]", | |
565 st->dynamic ? "dynamic[-" : "static[", st->index); | |
566 | |
567 if (st->dynamic) { | |
568 st->index = st->base - st->index - 1; | |
569 } | |
570 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
571 rc = ngx_http_v3_parse_lookup(c, st->dynamic, st->index, &st->name, |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
572 &st->value); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
573 if (rc != NGX_OK) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
574 return rc; |
8226 | 575 } |
576 | |
577 st->state = sw_start; | |
578 return NGX_DONE; | |
579 } | |
580 | |
581 | |
582 ngx_int_t | |
583 ngx_http_v3_parse_header_lri(ngx_connection_t *c, | |
584 ngx_http_v3_parse_header_t *st, u_char ch) | |
585 { | |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
586 ngx_int_t rc; |
8226 | 587 enum { |
588 sw_start = 0, | |
589 sw_index, | |
590 sw_value_len, | |
591 sw_read_value_len, | |
592 sw_value | |
593 }; | |
594 | |
595 switch (st->state) { | |
596 | |
597 case sw_start: | |
598 | |
599 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header lri"); | |
600 | |
601 st->dynamic = (ch & 0x10) ? 0 : 1; | |
602 st->state = sw_index; | |
603 | |
604 /* fall through */ | |
605 | |
606 case sw_index: | |
607 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
608 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 4, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
609 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
610 return rc; |
8226 | 611 } |
612 | |
613 st->index = st->pint.value; | |
614 st->state = sw_value_len; | |
615 break; | |
616 | |
617 case sw_value_len: | |
618 | |
619 st->literal.huffman = (ch & 0x80) ? 1 : 0; | |
620 st->state = sw_read_value_len; | |
621 | |
622 /* fall through */ | |
623 | |
624 case sw_read_value_len: | |
625 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
626 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
627 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
628 return rc; |
8226 | 629 } |
630 | |
631 st->literal.length = st->pint.value; | |
632 if (st->literal.length == 0) { | |
633 goto done; | |
634 } | |
635 | |
636 st->state = sw_value; | |
637 break; | |
638 | |
639 case sw_value: | |
640 | |
641 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
642 if (rc != NGX_DONE) { |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
643 return rc; |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
644 } |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
645 |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
646 st->value = st->literal.value; |
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
647 goto done; |
8226 | 648 } |
649 | |
650 return NGX_AGAIN; | |
651 | |
652 done: | |
653 | |
654 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
655 "http3 parse header lri done %s%ui] \"%V\"", | |
656 st->dynamic ? "dynamic[-" : "static[", | |
657 st->index, &st->value); | |
658 | |
659 if (st->dynamic) { | |
660 st->index = st->base - st->index - 1; | |
661 } | |
662 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
663 rc = ngx_http_v3_parse_lookup(c, st->dynamic, st->index, &st->name, NULL); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
664 if (rc != NGX_OK) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
665 return rc; |
8226 | 666 } |
667 | |
668 st->state = sw_start; | |
669 return NGX_DONE; | |
670 } | |
671 | |
672 | |
673 ngx_int_t | |
674 ngx_http_v3_parse_header_l(ngx_connection_t *c, | |
675 ngx_http_v3_parse_header_t *st, u_char ch) | |
676 { | |
677 ngx_int_t rc; | |
678 enum { | |
679 sw_start = 0, | |
680 sw_name_len, | |
681 sw_name, | |
682 sw_value_len, | |
683 sw_read_value_len, | |
684 sw_value | |
685 }; | |
686 | |
687 switch (st->state) { | |
688 | |
689 case sw_start: | |
690 | |
691 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header l"); | |
692 | |
693 st->literal.huffman = (ch & 0x08) ? 1 : 0; | |
694 st->state = sw_name_len; | |
695 | |
696 /* fall through */ | |
697 | |
698 case sw_name_len: | |
699 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
700 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 3, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
701 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
702 return rc; |
8226 | 703 } |
704 | |
705 st->literal.length = st->pint.value; | |
706 if (st->literal.length == 0) { | |
707 return NGX_ERROR; | |
708 } | |
709 | |
710 st->state = sw_name; | |
711 break; | |
712 | |
713 case sw_name: | |
714 | |
715 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
716 if (rc != NGX_DONE) { |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
717 return rc; |
8226 | 718 } |
719 | |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
720 st->name = st->literal.value; |
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
721 st->state = sw_value_len; |
8226 | 722 break; |
723 | |
724 case sw_value_len: | |
725 | |
726 st->literal.huffman = (ch & 0x80) ? 1 : 0; | |
727 st->state = sw_read_value_len; | |
728 | |
729 /* fall through */ | |
730 | |
731 case sw_read_value_len: | |
732 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
733 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
734 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
735 return rc; |
8226 | 736 } |
737 | |
738 st->literal.length = st->pint.value; | |
739 if (st->literal.length == 0) { | |
740 goto done; | |
741 } | |
742 | |
743 st->state = sw_value; | |
744 break; | |
745 | |
746 case sw_value: | |
747 | |
748 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
749 if (rc != NGX_DONE) { |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
750 return rc; |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
751 } |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
752 |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
753 st->value = st->literal.value; |
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
754 goto done; |
8226 | 755 } |
756 | |
757 return NGX_AGAIN; | |
758 | |
759 done: | |
760 | |
761 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
762 "http3 parse header l done \"%V\" \"%V\"", | |
763 &st->name, &st->value); | |
764 | |
765 st->state = sw_start; | |
766 return NGX_DONE; | |
767 } | |
768 | |
769 | |
770 ngx_int_t | |
771 ngx_http_v3_parse_header_pbi(ngx_connection_t *c, | |
772 ngx_http_v3_parse_header_t *st, u_char ch) | |
773 { | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
774 ngx_int_t rc; |
8226 | 775 enum { |
776 sw_start = 0, | |
777 sw_index | |
778 }; | |
779 | |
780 switch (st->state) { | |
781 | |
782 case sw_start: | |
783 | |
784 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header pbi"); | |
785 | |
786 st->state = sw_index; | |
787 | |
788 /* fall through */ | |
789 | |
790 case sw_index: | |
791 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
792 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 4, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
793 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
794 return rc; |
8226 | 795 } |
796 | |
797 st->index = st->pint.value; | |
798 goto done; | |
799 } | |
800 | |
801 return NGX_AGAIN; | |
802 | |
803 done: | |
804 | |
805 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
806 "http3 parse header pbi done dynamic[+%ui]", st->index); | |
807 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
808 rc = ngx_http_v3_parse_lookup(c, 1, st->base + st->index, &st->name, |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
809 &st->value); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
810 if (rc != NGX_OK) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
811 return rc; |
8226 | 812 } |
813 | |
814 st->state = sw_start; | |
815 return NGX_DONE; | |
816 } | |
817 | |
818 | |
819 ngx_int_t | |
820 ngx_http_v3_parse_header_lpbi(ngx_connection_t *c, | |
821 ngx_http_v3_parse_header_t *st, u_char ch) | |
822 { | |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
823 ngx_int_t rc; |
8226 | 824 enum { |
825 sw_start = 0, | |
826 sw_index, | |
827 sw_value_len, | |
828 sw_read_value_len, | |
829 sw_value | |
830 }; | |
831 | |
832 switch (st->state) { | |
833 | |
834 case sw_start: | |
835 | |
836 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
837 "http3 parse header lpbi"); | |
838 | |
839 st->state = sw_index; | |
840 | |
841 /* fall through */ | |
842 | |
843 case sw_index: | |
844 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
845 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 3, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
846 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
847 return rc; |
8226 | 848 } |
849 | |
850 st->index = st->pint.value; | |
851 st->state = sw_value_len; | |
852 break; | |
853 | |
854 case sw_value_len: | |
855 | |
856 st->literal.huffman = (ch & 0x80) ? 1 : 0; | |
857 st->state = sw_read_value_len; | |
858 | |
859 /* fall through */ | |
860 | |
861 case sw_read_value_len: | |
862 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
863 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
864 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
865 return rc; |
8226 | 866 } |
867 | |
868 st->literal.length = st->pint.value; | |
869 if (st->literal.length == 0) { | |
870 goto done; | |
871 } | |
872 | |
873 st->state = sw_value; | |
874 break; | |
875 | |
876 case sw_value: | |
877 | |
878 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
879 if (rc != NGX_DONE) { |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
880 return rc; |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
881 } |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
882 |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
883 st->value = st->literal.value; |
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
884 goto done; |
8226 | 885 } |
886 | |
887 return NGX_AGAIN; | |
888 | |
889 done: | |
890 | |
891 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
892 "http3 parse header lpbi done dynamic[+%ui] \"%V\"", | |
893 st->index, &st->value); | |
894 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
895 rc = ngx_http_v3_parse_lookup(c, 1, st->base + st->index, &st->name, NULL); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
896 if (rc != NGX_OK) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
897 return rc; |
8226 | 898 } |
899 | |
900 st->state = sw_start; | |
901 return NGX_DONE; | |
902 } | |
903 | |
904 | |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
905 static ngx_int_t |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
906 ngx_http_v3_parse_lookup(ngx_connection_t *c, ngx_uint_t dynamic, |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
907 ngx_uint_t index, ngx_str_t *name, ngx_str_t *value) |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
908 { |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
909 u_char *p; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
910 |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
911 if (!dynamic) { |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
912 if (ngx_http_v3_lookup_static(c, index, name, value) != NGX_OK) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
913 return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED; |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
914 } |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
915 |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
916 return NGX_OK; |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
917 } |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
918 |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
919 if (ngx_http_v3_lookup(c, index, name, value) != NGX_OK) { |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
920 return NGX_HTTP_V3_ERR_DECOMPRESSION_FAILED; |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
921 } |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
922 |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
923 if (name) { |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
924 p = ngx_pnalloc(c->pool, name->len + 1); |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
925 if (p == NULL) { |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
926 return NGX_ERROR; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
927 } |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
928 |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
929 ngx_memcpy(p, name->data, name->len); |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
930 p[name->len] = '\0'; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
931 name->data = p; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
932 } |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
933 |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
934 if (value) { |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
935 p = ngx_pnalloc(c->pool, value->len + 1); |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
936 if (p == NULL) { |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
937 return NGX_ERROR; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
938 } |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
939 |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
940 ngx_memcpy(p, value->data, value->len); |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
941 p[value->len] = '\0'; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
942 value->data = p; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
943 } |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
944 |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
945 return NGX_OK; |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
946 } |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
947 |
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
948 |
8226 | 949 ngx_int_t |
950 ngx_http_v3_parse_control(ngx_connection_t *c, void *data, u_char ch) | |
951 { | |
952 ngx_http_v3_parse_control_t *st = data; | |
953 | |
954 ngx_int_t rc; | |
955 enum { | |
956 sw_start = 0, | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
957 sw_first_type, |
8226 | 958 sw_type, |
959 sw_length, | |
8497 | 960 sw_cancel_push, |
8226 | 961 sw_settings, |
962 sw_max_push_id, | |
963 sw_skip | |
964 }; | |
965 | |
966 switch (st->state) { | |
967 | |
968 case sw_start: | |
969 | |
970 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse control"); | |
971 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
972 st->state = sw_first_type; |
8226 | 973 |
974 /* fall through */ | |
975 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
976 case sw_first_type: |
8226 | 977 case sw_type: |
978 | |
8466
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
979 rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, ch); |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
980 if (rc != NGX_DONE) { |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
981 return rc; |
8226 | 982 } |
983 | |
984 st->type = st->vlint.value; | |
985 | |
986 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
987 "http3 parse frame type:%ui", st->type); | |
988 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
989 if (st->state == sw_first_type |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
990 && st->type != NGX_HTTP_V3_FRAME_SETTINGS) |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
991 { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
992 return NGX_HTTP_V3_ERR_MISSING_SETTINGS; |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
993 } |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
994 |
8226 | 995 st->state = sw_length; |
996 break; | |
997 | |
998 case sw_length: | |
999 | |
8466
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1000 rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, ch); |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1001 if (rc != NGX_DONE) { |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1002 return rc; |
8226 | 1003 } |
1004 | |
1005 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1006 "http3 parse frame len:%uL", st->vlint.value); | |
1007 | |
1008 st->length = st->vlint.value; | |
1009 if (st->length == 0) { | |
1010 st->state = sw_type; | |
1011 break; | |
1012 } | |
1013 | |
1014 switch (st->type) { | |
1015 | |
8497 | 1016 case NGX_HTTP_V3_FRAME_CANCEL_PUSH: |
1017 st->state = sw_cancel_push; | |
1018 break; | |
1019 | |
8226 | 1020 case NGX_HTTP_V3_FRAME_SETTINGS: |
1021 st->state = sw_settings; | |
1022 break; | |
1023 | |
1024 case NGX_HTTP_V3_FRAME_MAX_PUSH_ID: | |
1025 st->state = sw_max_push_id; | |
1026 break; | |
1027 | |
1028 default: | |
1029 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1030 "http3 parse skip unknown frame"); | |
1031 st->state = sw_skip; | |
1032 } | |
1033 | |
1034 break; | |
1035 | |
8497 | 1036 case sw_cancel_push: |
1037 | |
1038 rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, ch); | |
1039 | |
1040 if (--st->length == 0 && rc == NGX_AGAIN) { | |
1041 return NGX_HTTP_V3_ERR_FRAME_ERROR; | |
1042 } | |
1043 | |
1044 if (rc != NGX_DONE) { | |
1045 return rc; | |
1046 } | |
1047 | |
1048 rc = ngx_http_v3_cancel_push(c, st->vlint.value); | |
1049 if (rc != NGX_OK) { | |
1050 return rc; | |
1051 } | |
1052 | |
1053 st->state = sw_type; | |
1054 break; | |
1055 | |
8226 | 1056 case sw_settings: |
1057 | |
1058 rc = ngx_http_v3_parse_settings(c, &st->settings, ch); | |
1059 | |
8467
e02250b55b17
HTTP/3: simplified handling return codes from parse functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8466
diff
changeset
|
1060 if (--st->length == 0 && rc == NGX_AGAIN) { |
e02250b55b17
HTTP/3: simplified handling return codes from parse functions.
Roman Arutyunyan <arut@nginx.com>
parents:
8466
diff
changeset
|
1061 return NGX_HTTP_V3_ERR_SETTINGS_ERROR; |
8226 | 1062 } |
1063 | |
1064 if (rc != NGX_DONE) { | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1065 return rc; |
8226 | 1066 } |
1067 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1068 if (st->length == 0) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1069 st->state = sw_type; |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1070 } |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1071 |
8226 | 1072 break; |
1073 | |
1074 case sw_max_push_id: | |
1075 | |
8466
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1076 rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, ch); |
8497 | 1077 |
1078 if (--st->length == 0 && rc == NGX_AGAIN) { | |
1079 return NGX_HTTP_V3_ERR_FRAME_ERROR; | |
1080 } | |
1081 | |
8466
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1082 if (rc != NGX_DONE) { |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1083 return rc; |
8226 | 1084 } |
1085 | |
8497 | 1086 rc = ngx_http_v3_set_max_push_id(c, st->vlint.value); |
1087 if (rc != NGX_OK) { | |
1088 return rc; | |
1089 } | |
8226 | 1090 |
1091 st->state = sw_type; | |
1092 break; | |
1093 | |
1094 case sw_skip: | |
1095 | |
1096 if (--st->length == 0) { | |
1097 st->state = sw_type; | |
1098 } | |
1099 | |
1100 break; | |
1101 } | |
1102 | |
1103 return NGX_AGAIN; | |
1104 } | |
1105 | |
1106 | |
1107 ngx_int_t | |
1108 ngx_http_v3_parse_settings(ngx_connection_t *c, | |
1109 ngx_http_v3_parse_settings_t *st, u_char ch) | |
1110 { | |
8466
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1111 ngx_int_t rc; |
8226 | 1112 enum { |
1113 sw_start = 0, | |
1114 sw_id, | |
1115 sw_value | |
1116 }; | |
1117 | |
1118 switch (st->state) { | |
1119 | |
1120 case sw_start: | |
1121 | |
1122 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse settings"); | |
1123 | |
1124 st->state = sw_id; | |
1125 | |
1126 /* fall through */ | |
1127 | |
1128 case sw_id: | |
1129 | |
8466
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1130 rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, ch); |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1131 if (rc != NGX_DONE) { |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1132 return rc; |
8226 | 1133 } |
1134 | |
1135 st->id = st->vlint.value; | |
1136 st->state = sw_value; | |
1137 break; | |
1138 | |
1139 case sw_value: | |
1140 | |
8466
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1141 rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, ch); |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1142 if (rc != NGX_DONE) { |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1143 return rc; |
8226 | 1144 } |
1145 | |
1146 if (ngx_http_v3_set_param(c, st->id, st->vlint.value) != NGX_OK) { | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1147 return NGX_HTTP_V3_ERR_SETTINGS_ERROR; |
8226 | 1148 } |
1149 | |
1150 goto done; | |
1151 } | |
1152 | |
1153 return NGX_AGAIN; | |
1154 | |
1155 done: | |
1156 | |
1157 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse settings done"); | |
1158 | |
1159 st->state = sw_start; | |
1160 return NGX_DONE; | |
1161 } | |
1162 | |
1163 | |
1164 ngx_int_t | |
1165 ngx_http_v3_parse_encoder(ngx_connection_t *c, void *data, u_char ch) | |
1166 { | |
1167 ngx_http_v3_parse_encoder_t *st = data; | |
1168 | |
1169 ngx_int_t rc; | |
1170 enum { | |
1171 sw_start = 0, | |
1172 sw_inr, | |
1173 sw_iwnr, | |
1174 sw_capacity, | |
1175 sw_duplicate | |
1176 }; | |
1177 | |
1178 if (st->state == sw_start) { | |
1179 | |
1180 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1181 "http3 parse encoder instruction"); | |
1182 | |
1183 if (ch & 0x80) { | |
1184 /* Insert With Name Reference */ | |
1185 | |
1186 st->state = sw_inr; | |
1187 | |
1188 } else if (ch & 0x40) { | |
1189 /* Insert Without Name Reference */ | |
1190 | |
1191 st->state = sw_iwnr; | |
1192 | |
1193 } else if (ch & 0x20) { | |
1194 /* Set Dynamic Table Capacity */ | |
1195 | |
1196 st->state = sw_capacity; | |
1197 | |
1198 } else { | |
1199 /* Duplicate */ | |
1200 | |
1201 st->state = sw_duplicate; | |
1202 } | |
1203 } | |
1204 | |
1205 switch (st->state) { | |
1206 | |
1207 case sw_inr: | |
1208 | |
1209 rc = ngx_http_v3_parse_header_inr(c, &st->header, ch); | |
1210 if (rc != NGX_DONE) { | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1211 return rc; |
8226 | 1212 } |
1213 | |
1214 goto done; | |
1215 | |
1216 case sw_iwnr: | |
1217 | |
1218 rc = ngx_http_v3_parse_header_iwnr(c, &st->header, ch); | |
1219 if (rc != NGX_DONE) { | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1220 return rc; |
8226 | 1221 } |
1222 | |
1223 goto done; | |
1224 | |
1225 case sw_capacity: | |
1226 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1227 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 5, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1228 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1229 return rc; |
8226 | 1230 } |
1231 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1232 rc = ngx_http_v3_set_capacity(c, st->pint.value); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1233 if (rc != NGX_OK) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1234 return rc; |
8226 | 1235 } |
1236 | |
1237 goto done; | |
1238 | |
1239 case sw_duplicate: | |
1240 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1241 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 5, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1242 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1243 return rc; |
8226 | 1244 } |
1245 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1246 rc = ngx_http_v3_duplicate(c, st->pint.value); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1247 if (rc != NGX_OK) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1248 return rc; |
8226 | 1249 } |
1250 | |
1251 goto done; | |
1252 } | |
1253 | |
1254 return NGX_AGAIN; | |
1255 | |
1256 done: | |
1257 | |
1258 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1259 "http3 parse encoder instruction done"); | |
1260 | |
1261 st->state = sw_start; | |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
1262 return NGX_AGAIN; |
8226 | 1263 } |
1264 | |
1265 | |
1266 ngx_int_t | |
1267 ngx_http_v3_parse_header_inr(ngx_connection_t *c, | |
1268 ngx_http_v3_parse_header_t *st, u_char ch) | |
1269 { | |
1270 ngx_int_t rc; | |
1271 enum { | |
1272 sw_start = 0, | |
1273 sw_name_index, | |
1274 sw_value_len, | |
1275 sw_read_value_len, | |
1276 sw_value | |
1277 }; | |
1278 | |
1279 switch (st->state) { | |
1280 | |
1281 case sw_start: | |
1282 | |
1283 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header inr"); | |
1284 | |
1285 st->dynamic = (ch & 0x40) ? 0 : 1; | |
1286 st->state = sw_name_index; | |
1287 | |
1288 /* fall through */ | |
1289 | |
1290 case sw_name_index: | |
1291 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1292 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 6, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1293 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1294 return rc; |
8226 | 1295 } |
1296 | |
1297 st->index = st->pint.value; | |
1298 st->state = sw_value_len; | |
1299 break; | |
1300 | |
1301 case sw_value_len: | |
1302 | |
1303 st->literal.huffman = (ch & 0x80) ? 1 : 0; | |
1304 st->state = sw_read_value_len; | |
1305 | |
1306 /* fall through */ | |
1307 | |
1308 case sw_read_value_len: | |
1309 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1310 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1311 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1312 return rc; |
8226 | 1313 } |
1314 | |
1315 st->literal.length = st->pint.value; | |
1316 if (st->literal.length == 0) { | |
1317 goto done; | |
1318 } | |
1319 | |
1320 st->state = sw_value; | |
1321 break; | |
1322 | |
1323 case sw_value: | |
1324 | |
1325 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
1326 if (rc != NGX_DONE) { |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1327 return rc; |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1328 } |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1329 |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
1330 st->value = st->literal.value; |
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
1331 goto done; |
8226 | 1332 } |
1333 | |
1334 return NGX_AGAIN; | |
1335 | |
1336 done: | |
1337 | |
1338 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1339 "http3 parse header inr done %s[%ui] \"%V\"", | |
1340 st->dynamic ? "dynamic" : "static", | |
1341 st->index, &st->value); | |
1342 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1343 rc = ngx_http_v3_ref_insert(c, st->dynamic, st->index, &st->value); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1344 if (rc != NGX_OK) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1345 return rc; |
8226 | 1346 } |
1347 | |
1348 st->state = sw_start; | |
1349 return NGX_DONE; | |
1350 } | |
1351 | |
1352 | |
1353 ngx_int_t | |
1354 ngx_http_v3_parse_header_iwnr(ngx_connection_t *c, | |
1355 ngx_http_v3_parse_header_t *st, u_char ch) | |
1356 { | |
1357 ngx_int_t rc; | |
1358 enum { | |
1359 sw_start = 0, | |
1360 sw_name_len, | |
1361 sw_name, | |
1362 sw_value_len, | |
1363 sw_read_value_len, | |
1364 sw_value | |
1365 }; | |
1366 | |
1367 switch (st->state) { | |
1368 | |
1369 case sw_start: | |
1370 | |
1371 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1372 "http3 parse header iwnr"); | |
1373 | |
1374 st->literal.huffman = (ch & 0x20) ? 1 : 0; | |
1375 st->state = sw_name_len; | |
1376 | |
1377 /* fall through */ | |
1378 | |
1379 case sw_name_len: | |
1380 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1381 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 5, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1382 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1383 return rc; |
8226 | 1384 } |
1385 | |
1386 st->literal.length = st->pint.value; | |
1387 if (st->literal.length == 0) { | |
1388 return NGX_ERROR; | |
1389 } | |
1390 | |
1391 st->state = sw_name; | |
1392 break; | |
1393 | |
1394 case sw_name: | |
1395 | |
1396 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
1397 if (rc != NGX_DONE) { |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1398 return rc; |
8226 | 1399 } |
1400 | |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
1401 st->name = st->literal.value; |
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
1402 st->state = sw_value_len; |
8226 | 1403 break; |
1404 | |
1405 case sw_value_len: | |
1406 | |
1407 st->literal.huffman = (ch & 0x80) ? 1 : 0; | |
1408 st->state = sw_read_value_len; | |
1409 | |
1410 /* fall through */ | |
1411 | |
1412 case sw_read_value_len: | |
1413 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1414 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1415 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1416 return rc; |
8226 | 1417 } |
1418 | |
1419 st->literal.length = st->pint.value; | |
1420 if (st->literal.length == 0) { | |
1421 goto done; | |
1422 } | |
1423 | |
1424 st->state = sw_value; | |
1425 break; | |
1426 | |
1427 case sw_value: | |
1428 | |
1429 rc = ngx_http_v3_parse_literal(c, &st->literal, ch); | |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
1430 if (rc != NGX_DONE) { |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1431 return rc; |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1432 } |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1433 |
8465
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
1434 st->value = st->literal.value; |
5611bbb852ce
HTTP/3: simplifed handling ngx_http_v3_parse_literal() return code.
Roman Arutyunyan <arut@nginx.com>
parents:
8464
diff
changeset
|
1435 goto done; |
8226 | 1436 } |
1437 | |
1438 return NGX_AGAIN; | |
1439 | |
1440 done: | |
1441 | |
1442 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1443 "http3 parse header iwnr done \"%V\":\"%V\"", | |
1444 &st->name, &st->value); | |
1445 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1446 rc = ngx_http_v3_insert(c, &st->name, &st->value); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1447 if (rc != NGX_OK) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1448 return rc; |
8226 | 1449 } |
1450 | |
1451 st->state = sw_start; | |
1452 return NGX_DONE; | |
1453 } | |
1454 | |
1455 | |
1456 ngx_int_t | |
1457 ngx_http_v3_parse_decoder(ngx_connection_t *c, void *data, u_char ch) | |
1458 { | |
1459 ngx_http_v3_parse_decoder_t *st = data; | |
1460 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1461 ngx_int_t rc; |
8226 | 1462 enum { |
1463 sw_start = 0, | |
1464 sw_ack_header, | |
1465 sw_cancel_stream, | |
1466 sw_inc_insert_count | |
1467 }; | |
1468 | |
1469 if (st->state == sw_start) { | |
1470 | |
1471 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1472 "http3 parse decoder instruction"); | |
1473 | |
1474 if (ch & 0x80) { | |
1475 /* Header Acknowledgement */ | |
1476 | |
1477 st->state = sw_ack_header; | |
1478 | |
1479 } else if (ch & 0x40) { | |
1480 /* Stream Cancellation */ | |
1481 | |
1482 st->state = sw_cancel_stream; | |
1483 | |
1484 } else { | |
1485 /* Insert Count Increment */ | |
1486 | |
1487 st->state = sw_inc_insert_count; | |
1488 } | |
1489 } | |
1490 | |
1491 switch (st->state) { | |
1492 | |
1493 case sw_ack_header: | |
1494 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1495 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 7, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1496 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1497 return rc; |
8226 | 1498 } |
1499 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1500 rc = ngx_http_v3_ack_header(c, st->pint.value); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1501 if (rc != NGX_OK) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1502 return rc; |
8226 | 1503 } |
1504 | |
1505 goto done; | |
1506 | |
1507 case sw_cancel_stream: | |
1508 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1509 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 6, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1510 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1511 return rc; |
8226 | 1512 } |
1513 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1514 rc = ngx_http_v3_cancel_stream(c, st->pint.value); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1515 if (rc != NGX_OK) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1516 return rc; |
8226 | 1517 } |
1518 | |
1519 goto done; | |
1520 | |
1521 case sw_inc_insert_count: | |
1522 | |
8464
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1523 rc = ngx_http_v3_parse_prefix_int(c, &st->pint, 6, ch); |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1524 if (rc != NGX_DONE) { |
fdb8edc8e496
HTTP/3: limited prefixed integer size by 62 bits.
Roman Arutyunyan <arut@nginx.com>
parents:
8463
diff
changeset
|
1525 return rc; |
8226 | 1526 } |
1527 | |
8460
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1528 rc = ngx_http_v3_inc_insert_count(c, st->pint.value); |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1529 if (rc != NGX_OK) { |
72f9ff4e0a88
HTTP/3: close QUIC connection with HTTP/QPACK errors when needed.
Roman Arutyunyan <arut@nginx.com>
parents:
8457
diff
changeset
|
1530 return rc; |
8226 | 1531 } |
1532 | |
1533 goto done; | |
1534 } | |
1535 | |
1536 return NGX_AGAIN; | |
1537 | |
1538 done: | |
1539 | |
1540 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
1541 "http3 parse decoder instruction done"); | |
1542 | |
1543 st->state = sw_start; | |
8456
c9538aef3211
HTTP/3: refactored dynamic table implementation.
Roman Arutyunyan <arut@nginx.com>
parents:
8455
diff
changeset
|
1544 return NGX_AGAIN; |
8226 | 1545 } |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1546 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1547 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1548 ngx_int_t |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1549 ngx_http_v3_parse_data(ngx_connection_t *c, ngx_http_v3_parse_data_t *st, |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1550 u_char ch) |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1551 { |
8466
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1552 ngx_int_t rc; |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1553 enum { |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1554 sw_start = 0, |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1555 sw_type, |
8549
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1556 sw_length, |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1557 sw_skip |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1558 }; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1559 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1560 switch (st->state) { |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1561 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1562 case sw_start: |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1563 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1564 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse data"); |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1565 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1566 st->state = sw_type; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1567 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1568 /* fall through */ |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1569 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1570 case sw_type: |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1571 |
8466
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1572 rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, ch); |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1573 if (rc != NGX_DONE) { |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1574 return rc; |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1575 } |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1576 |
8549
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1577 st->type = st->vlint.value; |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1578 |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1579 if (st->type == NGX_HTTP_V3_FRAME_HEADERS) { |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1580 /* trailers */ |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1581 goto done; |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1582 } |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1583 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1584 st->state = sw_length; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1585 break; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1586 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1587 case sw_length: |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1588 |
8466
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1589 rc = ngx_http_v3_parse_varlen_int(c, &st->vlint, ch); |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1590 if (rc != NGX_DONE) { |
4fd709540daf
HTTP/3: put ngx_http_v3_parse_varlen_int() return code in variable.
Roman Arutyunyan <arut@nginx.com>
parents:
8465
diff
changeset
|
1591 return rc; |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1592 } |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1593 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1594 st->length = st->vlint.value; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1595 |
8549
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1596 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1597 "http3 parse data type:%ui, len:%ui", |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1598 st->type, st->length); |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1599 |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1600 if (st->type != NGX_HTTP_V3_FRAME_DATA && st->length > 0) { |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1601 st->state = sw_skip; |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1602 break; |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1603 } |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1604 |
8549
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1605 st->state = sw_type; |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1606 return NGX_OK; |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1607 |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1608 case sw_skip: |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1609 |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1610 if (--st->length == 0) { |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1611 st->state = sw_type; |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1612 } |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1613 |
d70a38acaea0
HTTP/3: skip unknown frames on request stream.
Roman Arutyunyan <arut@nginx.com>
parents:
8497
diff
changeset
|
1614 break; |
8295
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1615 } |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1616 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1617 return NGX_AGAIN; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1618 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1619 done: |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1620 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1621 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse data done"); |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1622 |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1623 st->state = sw_start; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1624 return NGX_DONE; |
5649079a41f4
Parsing HTTP/3 request body.
Roman Arutyunyan <arut@nginx.com>
parents:
8227
diff
changeset
|
1625 } |