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;