comparison src/http/v3/ngx_http_v3_filter_module.c @ 8542:8e8cdb7bfb17 quic

HTTP/3: response trailers support.
author Roman Arutyunyan <arut@nginx.com>
date Tue, 13 Jul 2021 22:44:03 +0300
parents 0ac25efb2da3
children 07f90cb79fec
comparison
equal deleted inserted replaced
8541:7f29db5294bd 8542:8e8cdb7bfb17
47 static void ngx_http_v3_push_request_handler(ngx_event_t *ev); 47 static void ngx_http_v3_push_request_handler(ngx_event_t *ev);
48 static ngx_chain_t *ngx_http_v3_create_push_promise(ngx_http_request_t *r, 48 static ngx_chain_t *ngx_http_v3_create_push_promise(ngx_http_request_t *r,
49 ngx_str_t *path, uint64_t push_id); 49 ngx_str_t *path, uint64_t push_id);
50 static ngx_int_t ngx_http_v3_body_filter(ngx_http_request_t *r, 50 static ngx_int_t ngx_http_v3_body_filter(ngx_http_request_t *r,
51 ngx_chain_t *in); 51 ngx_chain_t *in);
52 static ngx_chain_t *ngx_http_v3_create_trailers(ngx_http_request_t *r); 52 static ngx_chain_t *ngx_http_v3_create_trailers(ngx_http_request_t *r,
53 ngx_http_v3_filter_ctx_t *ctx);
53 static ngx_int_t ngx_http_v3_filter_init(ngx_conf_t *cf); 54 static ngx_int_t ngx_http_v3_filter_init(ngx_conf_t *cf);
54 55
55 56
56 static ngx_http_module_t ngx_http_v3_filter_module_ctx = { 57 static ngx_http_module_t ngx_http_v3_filter_module_ctx = {
57 NULL, /* preconfiguration */ 58 NULL, /* preconfiguration */
513 hl->next = cl; 514 hl->next = cl;
514 515
515 *ll = hl; 516 *ll = hl;
516 ll = &cl->next; 517 ll = &cl->next;
517 518
518 if (r->headers_out.content_length_n >= 0 && !r->header_only) { 519 if (r->headers_out.content_length_n >= 0
520 && !r->header_only && !r->expect_trailers)
521 {
519 len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_DATA) 522 len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_DATA)
520 + ngx_http_v3_encode_varlen_int(NULL, 523 + ngx_http_v3_encode_varlen_int(NULL,
521 r->headers_out.content_length_n); 524 r->headers_out.content_length_n);
522 525
523 b = ngx_create_temp_buf(c->pool, len); 526 b = ngx_create_temp_buf(c->pool, len);
1301 tl->next = out; 1304 tl->next = out;
1302 out = tl; 1305 out = tl;
1303 } 1306 }
1304 1307
1305 if (cl->buf->last_buf) { 1308 if (cl->buf->last_buf) {
1306 tl = ngx_http_v3_create_trailers(r); 1309 tl = ngx_http_v3_create_trailers(r, ctx);
1307 if (tl == NULL) { 1310 if (tl == NULL) {
1308 return NGX_ERROR; 1311 return NGX_ERROR;
1309 } 1312 }
1310 1313
1311 cl->buf->last_buf = 0; 1314 cl->buf->last_buf = 0;
1324 return rc; 1327 return rc;
1325 } 1328 }
1326 1329
1327 1330
1328 static ngx_chain_t * 1331 static ngx_chain_t *
1329 ngx_http_v3_create_trailers(ngx_http_request_t *r) 1332 ngx_http_v3_create_trailers(ngx_http_request_t *r,
1333 ngx_http_v3_filter_ctx_t *ctx)
1330 { 1334 {
1331 ngx_buf_t *b; 1335 size_t len, n;
1332 ngx_chain_t *cl; 1336 u_char *p;
1333 1337 ngx_buf_t *b;
1334 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1338 ngx_uint_t i;
1335 "http3 create trailers"); 1339 ngx_chain_t *cl, *hl;
1336 1340 ngx_list_part_t *part;
1337 /* XXX */ 1341 ngx_table_elt_t *header;
1338 1342
1339 b = ngx_calloc_buf(r->pool); 1343 len = 0;
1340 if (b == NULL) { 1344
1341 return NULL; 1345 part = &r->headers_out.trailers.part;
1342 } 1346 header = part->elts;
1343 1347
1344 b->last_buf = 1; 1348 for (i = 0; /* void */; i++) {
1345 1349
1346 cl = ngx_alloc_chain_link(r->pool); 1350 if (i >= part->nelts) {
1351 if (part->next == NULL) {
1352 break;
1353 }
1354
1355 part = part->next;
1356 header = part->elts;
1357 i = 0;
1358 }
1359
1360 if (header[i].hash == 0) {
1361 continue;
1362 }
1363
1364 len += ngx_http_v3_encode_field_l(NULL, &header[i].key,
1365 &header[i].value);
1366 }
1367
1368 cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1347 if (cl == NULL) { 1369 if (cl == NULL) {
1348 return NULL; 1370 return NULL;
1349 } 1371 }
1350 1372
1351 cl->buf = b; 1373 b = cl->buf;
1352 cl->next = NULL; 1374
1353 1375 b->tag = (ngx_buf_tag_t) &ngx_http_v3_filter_module;
1354 return cl; 1376 b->memory = 0;
1377 b->last_buf = 1;
1378
1379 if (len == 0) {
1380 b->temporary = 0;
1381 b->pos = b->last = NULL;
1382 return cl;
1383 }
1384
1385 b->temporary = 1;
1386
1387 len += ngx_http_v3_encode_field_section_prefix(NULL, 0, 0, 0);
1388
1389 b->pos = ngx_palloc(r->pool, len);
1390 if (b->pos == NULL) {
1391 return NULL;
1392 }
1393
1394 b->last = (u_char *) ngx_http_v3_encode_field_section_prefix(b->pos,
1395 0, 0, 0);
1396
1397 part = &r->headers_out.trailers.part;
1398 header = part->elts;
1399
1400 for (i = 0; /* void */; i++) {
1401
1402 if (i >= part->nelts) {
1403 if (part->next == NULL) {
1404 break;
1405 }
1406
1407 part = part->next;
1408 header = part->elts;
1409 i = 0;
1410 }
1411
1412 if (header[i].hash == 0) {
1413 continue;
1414 }
1415
1416 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1417 "http3 trailer: \"%V: %V\"",
1418 &header[i].key, &header[i].value);
1419
1420 b->last = (u_char *) ngx_http_v3_encode_field_l(b->last,
1421 &header[i].key,
1422 &header[i].value);
1423 }
1424
1425 n = b->last - b->pos;
1426
1427 hl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1428 if (hl == NULL) {
1429 return NULL;
1430 }
1431
1432 b = hl->buf;
1433 p = b->start;
1434
1435 if (p == NULL) {
1436 p = ngx_palloc(r->pool, NGX_HTTP_V3_VARLEN_INT_LEN * 2);
1437 if (p == NULL) {
1438 return NULL;
1439 }
1440
1441 b->start = p;
1442 b->end = p + NGX_HTTP_V3_VARLEN_INT_LEN * 2;
1443 }
1444
1445 b->tag = (ngx_buf_tag_t) &ngx_http_v3_filter_module;
1446 b->memory = 0;
1447 b->temporary = 1;
1448 b->pos = p;
1449
1450 b->last = (u_char *) ngx_http_v3_encode_varlen_int(p,
1451 NGX_HTTP_V3_FRAME_HEADERS);
1452 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, n);
1453
1454 hl->next = cl;
1455
1456 return hl;
1355 } 1457 }
1356 1458
1357 1459
1358 static ngx_int_t 1460 static ngx_int_t
1359 ngx_http_v3_filter_init(ngx_conf_t *cf) 1461 ngx_http_v3_filter_init(ngx_conf_t *cf)