comparison src/http/v3/ngx_http_v3_request.c @ 8679:e1eb7f4ca9f1 quic

HTTP/3: refactored request parser. The change reduces diff to the default branch for src/http/ngx_http_request.c and src/http/ngx_http_parse.c.
author Roman Arutyunyan <arut@nginx.com>
date Fri, 22 Jan 2021 16:34:06 +0300
parents 96eb6915d244
children 58acdba9b3b2
comparison
equal deleted inserted replaced
8678:3443ee341cc1 8679:e1eb7f4ca9f1
8 #include <ngx_config.h> 8 #include <ngx_config.h>
9 #include <ngx_core.h> 9 #include <ngx_core.h>
10 #include <ngx_http.h> 10 #include <ngx_http.h>
11 11
12 12
13 static void ngx_http_v3_process_request(ngx_event_t *rev);
14 static ngx_int_t ngx_http_v3_process_header(ngx_http_request_t *r,
15 ngx_str_t *name, ngx_str_t *value);
13 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, 16 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r,
14 ngx_str_t *name, ngx_str_t *value); 17 ngx_str_t *name, ngx_str_t *value);
18 static ngx_int_t ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r);
19 static ngx_int_t ngx_http_v3_process_request_header(ngx_http_request_t *r);
15 20
16 21
17 static const struct { 22 static const struct {
18 ngx_str_t name; 23 ngx_str_t name;
19 ngx_uint_t method; 24 ngx_uint_t method;
35 { ngx_string("PATCH"), NGX_HTTP_PATCH }, 40 { ngx_string("PATCH"), NGX_HTTP_PATCH },
36 { ngx_string("TRACE"), NGX_HTTP_TRACE } 41 { ngx_string("TRACE"), NGX_HTTP_TRACE }
37 }; 42 };
38 43
39 44
40 ngx_int_t 45 void
41 ngx_http_v3_parse_request(ngx_http_request_t *r, ngx_buf_t *b) 46 ngx_http_v3_init(ngx_connection_t *c)
42 { 47 {
43 size_t len; 48 size_t size;
44 u_char *p; 49 ngx_buf_t *b;
45 ngx_int_t rc, n; 50 ngx_event_t *rev;
46 ngx_str_t *name, *value; 51 ngx_http_request_t *r;
52 ngx_http_connection_t *hc;
53 ngx_http_core_srv_conf_t *cscf;
54
55 if (ngx_http_v3_init_session(c) != NGX_OK) {
56 ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
57 "internal error");
58 ngx_http_close_connection(c);
59 return;
60 }
61
62 if (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) {
63 ngx_http_v3_init_uni_stream(c);
64 return;
65 }
66
67 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init request stream");
68
69 hc = c->data;
70
71 cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module);
72
73 size = cscf->client_header_buffer_size;
74
75 b = c->buffer;
76
77 if (b == NULL) {
78 b = ngx_create_temp_buf(c->pool, size);
79 if (b == NULL) {
80 ngx_http_close_connection(c);
81 return;
82 }
83
84 c->buffer = b;
85
86 } else if (b->start == NULL) {
87
88 b->start = ngx_palloc(c->pool, size);
89 if (b->start == NULL) {
90 ngx_http_close_connection(c);
91 return;
92 }
93
94 b->pos = b->start;
95 b->last = b->start;
96 b->end = b->last + size;
97 }
98
99 c->log->action = "reading client request";
100
101 r = ngx_http_create_request(c);
102 if (r == NULL) {
103 ngx_http_close_connection(c);
104 return;
105 }
106
107 r->http_version = NGX_HTTP_VERSION_30;
108
109 c->data = r;
110
111 rev = c->read;
112 rev->handler = ngx_http_v3_process_request;
113
114 ngx_http_v3_process_request(rev);
115 }
116
117
118 static void
119 ngx_http_v3_process_request(ngx_event_t *rev)
120 {
121 ssize_t n;
122 ngx_buf_t *b;
123 ngx_int_t rc;
47 ngx_connection_t *c; 124 ngx_connection_t *c;
125 ngx_http_request_t *r;
126 ngx_http_core_srv_conf_t *cscf;
48 ngx_http_v3_parse_headers_t *st; 127 ngx_http_v3_parse_headers_t *st;
49 128
50 c = r->connection; 129 c = rev->data;
130 r = c->data;
131
132 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http3 process request");
133
134 if (rev->timedout) {
135 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
136 c->timedout = 1;
137 ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
138 return;
139 }
140
51 st = r->h3_parse; 141 st = r->h3_parse;
52 142
53 if (st == NULL) { 143 if (st == NULL) {
54 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header");
55
56 st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_headers_t)); 144 st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_headers_t));
57 if (st == NULL) { 145 if (st == NULL) {
58 goto failed; 146 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
147 return;
59 } 148 }
60 149
61 r->h3_parse = st; 150 r->h3_parse = st;
62 r->parse_start = b->pos; 151 }
63 r->state = 1; 152
64 } 153 b = r->header_in;
65 154
66 while (b->pos < b->last) { 155 for ( ;; ) {
156
157 if (b->pos == b->last) {
158
159 if (!rev->ready) {
160 break;
161 }
162
163 n = c->recv(c, b->start, b->end - b->start);
164
165 if (n == NGX_AGAIN) {
166 if (!rev->timer_set) {
167 cscf = ngx_http_get_module_srv_conf(r,
168 ngx_http_core_module);
169 ngx_add_timer(rev, cscf->client_header_timeout);
170 }
171
172 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
173 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
174 }
175
176 break;
177 }
178
179 if (n == 0) {
180 ngx_log_error(NGX_LOG_INFO, c->log, 0,
181 "client prematurely closed connection");
182 }
183
184 if (n == 0 || n == NGX_ERROR) {
185 c->error = 1;
186 c->log->action = "reading client request";
187
188 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
189 break;
190 }
191
192 b->pos = b->start;
193 b->last = b->start + n;
194 }
195
67 rc = ngx_http_v3_parse_headers(c, st, *b->pos); 196 rc = ngx_http_v3_parse_headers(c, st, *b->pos);
68 197
69 if (rc > 0) { 198 if (rc > 0) {
70 ngx_http_v3_finalize_connection(c, rc, 199 ngx_http_v3_finalize_connection(c, rc,
71 "could not parse request headers"); 200 "could not parse request headers");
72 goto failed; 201 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
202 break;
73 } 203 }
74 204
75 if (rc == NGX_ERROR) { 205 if (rc == NGX_ERROR) {
76 goto failed; 206 ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
207 "internal error");
208 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
209 break;
77 } 210 }
78 211
79 if (rc == NGX_BUSY) { 212 if (rc == NGX_BUSY) {
80 return NGX_BUSY; 213 if (rev->error) {
214 ngx_http_close_request(r, NGX_HTTP_CLOSE);
215 break;
216 }
217
218 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
219 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
220 }
221
222 break;
81 } 223 }
82 224
83 b->pos++; 225 b->pos++;
226 r->request_length++;
84 227
85 if (rc == NGX_AGAIN) { 228 if (rc == NGX_AGAIN) {
86 continue; 229 continue;
87 } 230 }
88 231
89 name = &st->header_rep.header.name; 232 /* rc == NGX_OK || rc == NGX_DONE */
90 value = &st->header_rep.header.value; 233
91 234 if (ngx_http_v3_process_header(r, &st->header_rep.header.name,
92 n = ngx_http_v3_process_pseudo_header(r, name, value); 235 &st->header_rep.header.value)
93 236 != NGX_OK)
94 if (n == NGX_ERROR) { 237 {
95 goto failed; 238 break;
96 }
97
98 if (n == NGX_OK && rc == NGX_OK) {
99 continue;
100 }
101
102 len = r->method_name.len + 1
103 + (r->uri_end - r->uri_start) + 1
104 + sizeof("HTTP/3.0") - 1;
105
106 p = ngx_pnalloc(c->pool, len);
107 if (p == NULL) {
108 goto failed;
109 }
110
111 r->request_start = p;
112
113 p = ngx_cpymem(p, r->method_name.data, r->method_name.len);
114 r->method_end = p - 1;
115 *p++ = ' ';
116 p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start);
117 *p++ = ' ';
118 r->http_protocol.data = p;
119 p = ngx_cpymem(p, "HTTP/3.0", sizeof("HTTP/3.0") - 1);
120
121 r->request_end = p;
122 r->state = 0;
123
124 return NGX_OK;
125 }
126
127 return NGX_AGAIN;
128
129 failed:
130
131 return NGX_HTTP_PARSE_INVALID_REQUEST;
132 }
133
134
135 ngx_int_t
136 ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b,
137 ngx_uint_t allow_underscores)
138 {
139 u_char ch;
140 ngx_int_t rc;
141 ngx_str_t *name, *value;
142 ngx_uint_t hash, i, n;
143 ngx_connection_t *c;
144 ngx_http_v3_parse_headers_t *st;
145 enum {
146 sw_start = 0,
147 sw_done,
148 sw_next,
149 sw_header
150 };
151
152 c = r->connection;
153 st = r->h3_parse;
154
155 switch (r->state) {
156
157 case sw_start:
158 r->parse_start = b->pos;
159
160 if (st->state) {
161 r->state = sw_next;
162 goto done;
163 }
164
165 name = &st->header_rep.header.name;
166
167 if (name->len && name->data[0] != ':') {
168 r->state = sw_done;
169 goto done;
170 }
171
172 /* fall through */
173
174 case sw_done:
175 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
176 "http3 parse header done");
177 return NGX_HTTP_PARSE_HEADER_DONE;
178
179 case sw_next:
180 r->parse_start = b->pos;
181 r->invalid_header = 0;
182 break;
183
184 case sw_header:
185 break;
186 }
187
188 while (b->pos < b->last) {
189 rc = ngx_http_v3_parse_headers(c, st, *b->pos++);
190
191 if (rc > 0) {
192 ngx_http_v3_finalize_connection(c, rc,
193 "could not parse request headers");
194 return NGX_HTTP_PARSE_INVALID_HEADER;
195 }
196
197 if (rc == NGX_ERROR) {
198 return NGX_HTTP_PARSE_INVALID_HEADER;
199 } 239 }
200 240
201 if (rc == NGX_DONE) { 241 if (rc == NGX_DONE) {
202 r->state = sw_done; 242 if (ngx_http_v3_process_request_header(r) != NGX_OK) {
203 goto done; 243 break;
204 } 244 }
205 245
206 if (rc == NGX_OK) { 246 ngx_http_process_request(r);
207 r->state = sw_next; 247 break;
208 goto done; 248 }
209 } 249 }
210 } 250
211 251 ngx_http_run_posted_requests(c);
212 r->state = sw_header; 252
213 return NGX_AGAIN; 253 return;
214 254 }
215 done: 255
216 256
217 name = &st->header_rep.header.name; 257 static ngx_int_t
218 value = &st->header_rep.header.value; 258 ngx_http_v3_process_header(ngx_http_request_t *r, ngx_str_t *name,
219 259 ngx_str_t *value)
220 r->header_name_start = name->data; 260 {
221 r->header_name_end = name->data + name->len; 261 ngx_table_elt_t *h;
222 r->header_start = value->data; 262 ngx_http_header_t *hh;
223 r->header_end = value->data + value->len; 263 ngx_http_core_main_conf_t *cmcf;
224 264
225 hash = 0; 265 if (name->len && name->data[0] == ':') {
226 i = 0; 266 return ngx_http_v3_process_pseudo_header(r, name, value);
227 267 }
228 for (n = 0; n < name->len; n++) { 268
229 ch = name->data[n]; 269 if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) {
230 270 return NGX_ERROR;
231 if (ch >= 'A' && ch <= 'Z') { 271 }
232 /* 272
233 * A request or response containing uppercase 273 h = ngx_list_push(&r->headers_in.headers);
234 * header field names MUST be treated as malformed 274 if (h == NULL) {
235 */ 275 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
236 return NGX_HTTP_PARSE_INVALID_HEADER; 276 return NGX_ERROR;
237 } 277 }
238 278
239 if (ch == '\0') { 279 h->key = *name;
240 return NGX_HTTP_PARSE_INVALID_HEADER; 280 h->value = *value;
241 } 281 h->lowcase_key = h->key.data;
242 282 h->hash = ngx_hash_key(h->key.data, h->key.len);
243 if (ch == '_' && !allow_underscores) { 283
244 r->invalid_header = 1; 284 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
245 continue; 285
246 } 286 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
247 287 h->lowcase_key, h->key.len);
248 if ((ch < 'a' || ch > 'z') 288
249 && (ch < '0' || ch > '9') 289 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
250 && ch != '-' && ch != '_') 290 return NGX_ERROR;
251 { 291 }
252 r->invalid_header = 1; 292
253 continue; 293 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
254 } 294 "http3 header: \"%V: %V\"", name, value);
255
256 hash = ngx_hash(hash, ch);
257 r->lowcase_header[i++] = ch;
258 i &= (NGX_HTTP_LC_HEADER_LEN - 1);
259 }
260
261 r->header_hash = hash;
262 r->lowcase_index = i;
263
264 return NGX_OK; 295 return NGX_OK;
265 } 296 }
266 297
267 298
268 static ngx_int_t 299 static ngx_int_t
269 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name, 300 ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name,
270 ngx_str_t *value) 301 ngx_str_t *value)
271 { 302 {
272 ngx_uint_t i; 303 ngx_uint_t i;
273 ngx_connection_t *c; 304
274 305 if (r->request_line.len) {
275 if (name->len == 0 || name->data[0] != ':') { 306 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
276 return NGX_DONE; 307 "client sent out of order pseudo-headers");
277 } 308 goto failed;
278 309 }
279 c = r->connection;
280 310
281 if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) { 311 if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) {
312
282 r->method_name = *value; 313 r->method_name = *value;
283 314
284 for (i = 0; i < sizeof(ngx_http_v3_methods) 315 for (i = 0; i < sizeof(ngx_http_v3_methods)
285 / sizeof(ngx_http_v3_methods[0]); i++) 316 / sizeof(ngx_http_v3_methods[0]); i++)
286 { 317 {
287 if (value->len == ngx_http_v3_methods[i].name.len 318 if (value->len == ngx_http_v3_methods[i].name.len
288 && ngx_strncmp(value->data, ngx_http_v3_methods[i].name.data, 319 && ngx_strncmp(value->data,
289 value->len) == 0) 320 ngx_http_v3_methods[i].name.data, value->len)
321 == 0)
290 { 322 {
291 r->method = ngx_http_v3_methods[i].method; 323 r->method = ngx_http_v3_methods[i].method;
292 break; 324 break;
293 } 325 }
294 } 326 }
295 327
296 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, 328 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
297 "http3 method \"%V\" %ui", value, r->method); 329 "http3 method \"%V\" %ui", value, r->method);
298 return NGX_OK; 330 return NGX_OK;
299 } 331 }
300 332
301 if (name->len == 5 && ngx_strncmp(name->data, ":path", 5) == 0) { 333 if (name->len == 5 && ngx_strncmp(name->data, ":path", 5) == 0) {
334
302 r->uri_start = value->data; 335 r->uri_start = value->data;
303 r->uri_end = value->data + value->len; 336 r->uri_end = value->data + value->len;
304 337
305 if (ngx_http_parse_uri(r) != NGX_OK) { 338 if (ngx_http_parse_uri(r) != NGX_OK) {
306 ngx_log_error(NGX_LOG_INFO, c->log, 0, 339 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
307 "client sent invalid :path header: \"%V\"", value); 340 "client sent invalid \":path\" header: \"%V\"",
308 return NGX_ERROR; 341 value);
309 } 342 goto failed;
310 343 }
311 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, 344
345 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
312 "http3 path \"%V\"", value); 346 "http3 path \"%V\"", value);
313
314 return NGX_OK; 347 return NGX_OK;
315 } 348 }
316 349
317 if (name->len == 7 && ngx_strncmp(name->data, ":scheme", 7) == 0) { 350 if (name->len == 7 && ngx_strncmp(name->data, ":scheme", 7) == 0) {
318 r->schema_start = value->data; 351
319 r->schema_end = value->data + value->len; 352 r->schema = *value;
320 353
321 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, 354 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
322 "http3 schema \"%V\"", value); 355 "http3 schema \"%V\"", value);
323
324 return NGX_OK; 356 return NGX_OK;
325 } 357 }
326 358
327 if (name->len == 10 && ngx_strncmp(name->data, ":authority", 10) == 0) { 359 if (name->len == 10 && ngx_strncmp(name->data, ":authority", 10) == 0) {
360
328 r->host_start = value->data; 361 r->host_start = value->data;
329 r->host_end = value->data + value->len; 362 r->host_end = value->data + value->len;
330 363
331 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, 364 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
332 "http3 authority \"%V\"", value); 365 "http3 authority \"%V\"", value);
333
334 return NGX_OK; 366 return NGX_OK;
335 } 367 }
336 368
337 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, 369 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
338 "http3 unknown pseudo header \"%V\" \"%V\"", name, value); 370 "client sent unknown pseudo-header \"%V\"", name);
371
372 failed:
373
374 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
375 return NGX_ERROR;
376 }
377
378
379 static ngx_int_t
380 ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r)
381 {
382 size_t len;
383 u_char *p;
384 ngx_int_t rc;
385 ngx_str_t host;
386
387 if (r->request_line.len) {
388 return NGX_OK;
389 }
390
391 len = r->method_name.len + 1
392 + (r->uri_end - r->uri_start) + 1
393 + sizeof("HTTP/3.0") - 1;
394
395 p = ngx_pnalloc(r->pool, len);
396 if (p == NULL) {
397 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
398 return NGX_ERROR;
399 }
400
401 r->request_line.data = p;
402
403 p = ngx_cpymem(p, r->method_name.data, r->method_name.len);
404 *p++ = ' ';
405 p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start);
406 *p++ = ' ';
407 p = ngx_cpymem(p, "HTTP/3.0", sizeof("HTTP/3.0") - 1);
408
409 r->request_line.len = p - r->request_line.data;
410
411 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
412 "http3 request line: \"%V\"", &r->request_line);
413
414 ngx_str_set(&r->http_protocol, "HTTP/3.0");
415
416 if (ngx_http_process_request_uri(r) != NGX_OK) {
417 return NGX_ERROR;
418 }
419
420 if (r->host_end) {
421
422 host.len = r->host_end - r->host_start;
423 host.data = r->host_start;
424
425 rc = ngx_http_validate_host(&host, r->pool, 0);
426
427 if (rc == NGX_DECLINED) {
428 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
429 "client sent invalid host in request line");
430 goto failed;
431 }
432
433 if (rc == NGX_ERROR) {
434 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
435 return NGX_ERROR;
436 }
437
438 if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) {
439 return NGX_ERROR;
440 }
441
442 r->headers_in.server = host;
443 }
444
445 if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
446 sizeof(ngx_table_elt_t))
447 != NGX_OK)
448 {
449 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
450 return NGX_ERROR;
451 }
339 452
340 return NGX_OK; 453 return NGX_OK;
454
455 failed:
456
457 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
458 return NGX_ERROR;
459 }
460
461
462 static ngx_int_t
463 ngx_http_v3_process_request_header(ngx_http_request_t *r)
464 {
465 if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) {
466 return NGX_ERROR;
467 }
468
469 if (r->headers_in.server.len == 0) {
470 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
471 "client sent neither \":authority\" nor \"Host\" header");
472 goto failed;
473 }
474
475 if (r->headers_in.host) {
476 if (r->headers_in.host->value.len != r->headers_in.server.len
477 || ngx_memcmp(r->headers_in.host->value.data,
478 r->headers_in.server.data,
479 r->headers_in.server.len)
480 != 0)
481 {
482 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
483 "client sent \":authority\" and \"Host\" headers "
484 "with different values");
485 goto failed;
486 }
487 }
488
489 if (r->headers_in.content_length) {
490 r->headers_in.content_length_n =
491 ngx_atoof(r->headers_in.content_length->value.data,
492 r->headers_in.content_length->value.len);
493
494 if (r->headers_in.content_length_n == NGX_ERROR) {
495 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
496 "client sent invalid \"Content-Length\" header");
497 goto failed;
498 }
499 }
500
501 return NGX_OK;
502
503 failed:
504
505 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
506 return NGX_ERROR;
341 } 507 }
342 508
343 509
344 ngx_int_t 510 ngx_int_t
345 ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b, 511 ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b,