/* * Copyright (C) Roman Arutyunyan * Copyright (C) Nginx, Inc. */ #include #include #include 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; }