Mercurial > hg > nginx
comparison src/http/v3/ngx_http_v3_request.c @ 8680:58acdba9b3b2 quic
HTTP/3: client pseudo-headers restrictions.
- :method, :path and :scheme are expected exactly once and not empty
- :method and :scheme character validation is added
- :authority cannot appear more than once
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Fri, 22 Jan 2021 15:57:41 +0300 |
parents | e1eb7f4ca9f1 |
children | 916a2e1d6617 |
comparison
equal
deleted
inserted
replaced
8679:e1eb7f4ca9f1 | 8680:58acdba9b3b2 |
---|---|
298 | 298 |
299 static ngx_int_t | 299 static ngx_int_t |
300 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, |
301 ngx_str_t *value) | 301 ngx_str_t *value) |
302 { | 302 { |
303 u_char ch, c; | |
303 ngx_uint_t i; | 304 ngx_uint_t i; |
304 | 305 |
305 if (r->request_line.len) { | 306 if (r->request_line.len) { |
306 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | 307 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
307 "client sent out of order pseudo-headers"); | 308 "client sent out of order pseudo-headers"); |
308 goto failed; | 309 goto failed; |
309 } | 310 } |
310 | 311 |
311 if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) { | 312 if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) { |
313 | |
314 if (r->method_name.len) { | |
315 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
316 "client sent duplicate \":method\" header"); | |
317 goto failed; | |
318 } | |
319 | |
320 if (value->len == 0) { | |
321 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
322 "client sent empty \":method\" header"); | |
323 goto failed; | |
324 } | |
312 | 325 |
313 r->method_name = *value; | 326 r->method_name = *value; |
314 | 327 |
315 for (i = 0; i < sizeof(ngx_http_v3_methods) | 328 for (i = 0; i < sizeof(ngx_http_v3_methods) |
316 / sizeof(ngx_http_v3_methods[0]); i++) | 329 / sizeof(ngx_http_v3_methods[0]); i++) |
323 r->method = ngx_http_v3_methods[i].method; | 336 r->method = ngx_http_v3_methods[i].method; |
324 break; | 337 break; |
325 } | 338 } |
326 } | 339 } |
327 | 340 |
341 for (i = 0; i < value->len; i++) { | |
342 ch = value->data[i]; | |
343 | |
344 if ((ch < 'A' || ch > 'Z') && ch != '_' && ch != '-') { | |
345 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
346 "client sent invalid method: \"%V\"", value); | |
347 goto failed; | |
348 } | |
349 } | |
350 | |
328 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 351 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
329 "http3 method \"%V\" %ui", value, r->method); | 352 "http3 method \"%V\" %ui", value, r->method); |
330 return NGX_OK; | 353 return NGX_OK; |
331 } | 354 } |
332 | 355 |
333 if (name->len == 5 && ngx_strncmp(name->data, ":path", 5) == 0) { | 356 if (name->len == 5 && ngx_strncmp(name->data, ":path", 5) == 0) { |
334 | 357 |
358 if (r->uri_start) { | |
359 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
360 "client sent duplicate \":path\" header"); | |
361 goto failed; | |
362 } | |
363 | |
364 if (value->len == 0) { | |
365 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
366 "client sent empty \":path\" header"); | |
367 goto failed; | |
368 } | |
369 | |
335 r->uri_start = value->data; | 370 r->uri_start = value->data; |
336 r->uri_end = value->data + value->len; | 371 r->uri_end = value->data + value->len; |
337 | 372 |
338 if (ngx_http_parse_uri(r) != NGX_OK) { | 373 if (ngx_http_parse_uri(r) != NGX_OK) { |
339 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | 374 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, |
347 return NGX_OK; | 382 return NGX_OK; |
348 } | 383 } |
349 | 384 |
350 if (name->len == 7 && ngx_strncmp(name->data, ":scheme", 7) == 0) { | 385 if (name->len == 7 && ngx_strncmp(name->data, ":scheme", 7) == 0) { |
351 | 386 |
387 if (r->schema.len) { | |
388 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
389 "client sent duplicate \":scheme\" header"); | |
390 goto failed; | |
391 } | |
392 | |
393 if (value->len == 0) { | |
394 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
395 "client sent empty \":scheme\" header"); | |
396 goto failed; | |
397 } | |
398 | |
399 for (i = 0; i < value->len; i++) { | |
400 ch = value->data[i]; | |
401 | |
402 c = (u_char) (ch | 0x20); | |
403 if (c >= 'a' && c <= 'z') { | |
404 continue; | |
405 } | |
406 | |
407 if (((ch >= '0' && ch <= '9') | |
408 || ch == '+' || ch == '-' || ch == '.') | |
409 && i > 0) | |
410 { | |
411 continue; | |
412 } | |
413 | |
414 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
415 "client sent invalid \":scheme\" header: \"%V\"", | |
416 value); | |
417 goto failed; | |
418 } | |
419 | |
352 r->schema = *value; | 420 r->schema = *value; |
353 | 421 |
354 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 422 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
355 "http3 schema \"%V\"", value); | 423 "http3 schema \"%V\"", value); |
356 return NGX_OK; | 424 return NGX_OK; |
357 } | 425 } |
358 | 426 |
359 if (name->len == 10 && ngx_strncmp(name->data, ":authority", 10) == 0) { | 427 if (name->len == 10 && ngx_strncmp(name->data, ":authority", 10) == 0) { |
428 | |
429 if (r->host_start) { | |
430 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
431 "client sent duplicate \":authority\" header"); | |
432 goto failed; | |
433 } | |
360 | 434 |
361 r->host_start = value->data; | 435 r->host_start = value->data; |
362 r->host_end = value->data + value->len; | 436 r->host_end = value->data + value->len; |
363 | 437 |
364 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 438 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
384 ngx_int_t rc; | 458 ngx_int_t rc; |
385 ngx_str_t host; | 459 ngx_str_t host; |
386 | 460 |
387 if (r->request_line.len) { | 461 if (r->request_line.len) { |
388 return NGX_OK; | 462 return NGX_OK; |
463 } | |
464 | |
465 if (r->method_name.len == 0) { | |
466 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
467 "client sent no \":method\" header"); | |
468 goto failed; | |
469 } | |
470 | |
471 if (r->schema.len == 0) { | |
472 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
473 "client sent no \":scheme\" header"); | |
474 goto failed; | |
475 } | |
476 | |
477 if (r->uri_start == NULL) { | |
478 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | |
479 "client sent no \":path\" header"); | |
480 goto failed; | |
389 } | 481 } |
390 | 482 |
391 len = r->method_name.len + 1 | 483 len = r->method_name.len + 1 |
392 + (r->uri_end - r->uri_start) + 1 | 484 + (r->uri_end - r->uri_start) + 1 |
393 + sizeof("HTTP/3.0") - 1; | 485 + sizeof("HTTP/3.0") - 1; |