Mercurial > hg > nginx-quic
view src/http/v3/ngx_http_v3_encode.c @ 8824:81a3429db8b0 quic
HTTP/3: delayed Insert Count Increment instruction.
Sending the instruction is delayed until the end of the current event cycle.
Delaying the instruction is allowed by quic-qpack-21, section 2.2.2.3.
The goal is to reduce the amount of data sent back to client by accumulating
several inserts in one instruction and sometimes not sending the instruction at
all, if Section Acknowledgement was sent just before it.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Thu, 27 Jan 2022 12:20:47 +0300 |
parents | 5c86189a1c1b |
children |
line wrap: on
line source
/* * Copyright (C) Roman Arutyunyan * Copyright (C) Nginx, Inc. */ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_http.h> uintptr_t ngx_http_v3_encode_varlen_int(u_char *p, uint64_t value) { if (value <= 63) { if (p == NULL) { return 1; } *p++ = value; return (uintptr_t) p; } if (value <= 16383) { if (p == NULL) { return 2; } *p++ = 0x40 | (value >> 8); *p++ = value; return (uintptr_t) p; } if (value <= 1073741823) { if (p == NULL) { return 4; } *p++ = 0x80 | (value >> 24); *p++ = (value >> 16); *p++ = (value >> 8); *p++ = value; return (uintptr_t) p; } if (p == NULL) { return 8; } *p++ = 0xc0 | (value >> 56); *p++ = (value >> 48); *p++ = (value >> 40); *p++ = (value >> 32); *p++ = (value >> 24); *p++ = (value >> 16); *p++ = (value >> 8); *p++ = value; return (uintptr_t) p; } uintptr_t ngx_http_v3_encode_prefix_int(u_char *p, uint64_t value, ngx_uint_t prefix) { ngx_uint_t thresh, n; thresh = (1 << prefix) - 1; if (value < thresh) { if (p == NULL) { return 1; } *p++ |= value; return (uintptr_t) p; } value -= thresh; if (p == NULL) { for (n = 2; value >= 128; n++) { value >>= 7; } return n; } *p++ |= thresh; while (value >= 128) { *p++ = 0x80 | value; value >>= 7; } *p++ = value; return (uintptr_t) p; } uintptr_t ngx_http_v3_encode_field_section_prefix(u_char *p, ngx_uint_t insert_count, ngx_uint_t sign, ngx_uint_t delta_base) { if (p == NULL) { return ngx_http_v3_encode_prefix_int(NULL, insert_count, 8) + ngx_http_v3_encode_prefix_int(NULL, delta_base, 7); } *p = 0; p = (u_char *) ngx_http_v3_encode_prefix_int(p, insert_count, 8); *p = sign ? 0x80 : 0; p = (u_char *) ngx_http_v3_encode_prefix_int(p, delta_base, 7); return (uintptr_t) p; } uintptr_t ngx_http_v3_encode_field_ri(u_char *p, ngx_uint_t dynamic, ngx_uint_t index) { /* Indexed Field Line */ if (p == NULL) { return ngx_http_v3_encode_prefix_int(NULL, index, 6); } *p = dynamic ? 0x80 : 0xc0; return ngx_http_v3_encode_prefix_int(p, index, 6); } uintptr_t ngx_http_v3_encode_field_lri(u_char *p, ngx_uint_t dynamic, ngx_uint_t index, u_char *data, size_t len) { size_t hlen; u_char *p1, *p2; /* Literal Field Line With Name Reference */ if (p == NULL) { return ngx_http_v3_encode_prefix_int(NULL, index, 4) + ngx_http_v3_encode_prefix_int(NULL, len, 7) + len; } *p = dynamic ? 0x40 : 0x50; p = (u_char *) ngx_http_v3_encode_prefix_int(p, index, 4); p1 = p; *p = 0; p = (u_char *) ngx_http_v3_encode_prefix_int(p, len, 7); if (data) { p2 = p; hlen = ngx_http_huff_encode(data, len, p, 0); if (hlen) { p = p1; *p = 0x80; p = (u_char *) ngx_http_v3_encode_prefix_int(p, hlen, 7); if (p != p2) { ngx_memmove(p, p2, hlen); } p += hlen; } else { p = ngx_cpymem(p, data, len); } } return (uintptr_t) p; } uintptr_t ngx_http_v3_encode_field_l(u_char *p, ngx_str_t *name, ngx_str_t *value) { size_t hlen; u_char *p1, *p2; /* Literal Field Line With Literal Name */ if (p == NULL) { return ngx_http_v3_encode_prefix_int(NULL, name->len, 3) + name->len + ngx_http_v3_encode_prefix_int(NULL, value->len, 7) + value->len; } p1 = p; *p = 0x20; p = (u_char *) ngx_http_v3_encode_prefix_int(p, name->len, 3); p2 = p; hlen = ngx_http_huff_encode(name->data, name->len, p, 1); if (hlen) { p = p1; *p = 0x28; p = (u_char *) ngx_http_v3_encode_prefix_int(p, hlen, 3); if (p != p2) { ngx_memmove(p, p2, hlen); } p += hlen; } else { ngx_strlow(p, name->data, name->len); p += name->len; } p1 = p; *p = 0; p = (u_char *) ngx_http_v3_encode_prefix_int(p, value->len, 7); p2 = p; hlen = ngx_http_huff_encode(value->data, value->len, p, 0); if (hlen) { p = p1; *p = 0x80; p = (u_char *) ngx_http_v3_encode_prefix_int(p, hlen, 7); if (p != p2) { ngx_memmove(p, p2, hlen); } p += hlen; } else { p = ngx_cpymem(p, value->data, value->len); } return (uintptr_t) p; } uintptr_t ngx_http_v3_encode_field_pbi(u_char *p, ngx_uint_t index) { /* Indexed Field Line With Post-Base Index */ if (p == NULL) { return ngx_http_v3_encode_prefix_int(NULL, index, 4); } *p = 0x10; return ngx_http_v3_encode_prefix_int(p, index, 4); } uintptr_t ngx_http_v3_encode_field_lpbi(u_char *p, ngx_uint_t index, u_char *data, size_t len) { size_t hlen; u_char *p1, *p2; /* Literal Field Line With Post-Base Name Reference */ if (p == NULL) { return ngx_http_v3_encode_prefix_int(NULL, index, 3) + ngx_http_v3_encode_prefix_int(NULL, len, 7) + len; } *p = 0; p = (u_char *) ngx_http_v3_encode_prefix_int(p, index, 3); p1 = p; *p = 0; p = (u_char *) ngx_http_v3_encode_prefix_int(p, len, 7); if (data) { p2 = p; hlen = ngx_http_huff_encode(data, len, p, 0); if (hlen) { p = p1; *p = 0x80; p = (u_char *) ngx_http_v3_encode_prefix_int(p, hlen, 7); if (p != p2) { ngx_memmove(p, p2, hlen); } p += hlen; } else { p = ngx_cpymem(p, data, len); } } return (uintptr_t) p; }