/
githubmirror
/
nghttp2
Обзор
Документация
Войти
/
githubmirror
/
nghttp2
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
lib/nghttp2_helper.c
603 строки
25 KB
Tatsuhiro Tsujikawa
Reformat downcase table
06 июн 2026, 10:42
06 июн 2026, 10:42
36b2334
Код
Авторство
О чём код?
/* * nghttp2 - HTTP/2 C Library * * Copyright (c) 2012 Tatsuhiro Tsujikawa * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "nghttp2_helper.h" #include <assert.h> #include <string.h> #include "nghttp2_net.h" void nghttp2_put_uint16be(uint8_t *buf, uint16_t n) { uint16_t x = htons(n); memcpy(buf, &x, sizeof(uint16_t)); } void nghttp2_put_uint32be(uint8_t *buf, uint32_t n) { uint32_t x = htonl(n); memcpy(buf, &x, sizeof(uint32_t)); } uint16_t nghttp2_get_uint16(const uint8_t *data) { uint16_t n; memcpy(&n, data, sizeof(uint16_t)); return ntohs(n); } uint32_t nghttp2_get_uint32(const uint8_t *data) { uint32_t n; memcpy(&n, data, sizeof(uint32_t)); return ntohl(n); } /* Generated by gendowncasetbl.py */ const uint8_t nghttp2_downcase_tbl[] = { 0x00 /* NUL */, 0x01 /* SOH */, 0x02 /* STX */, 0x03 /* ETX */, 0x04 /* EOT */, 0x05 /* ENQ */, 0x06 /* ACK */, 0x07 /* BEL */, 0x08 /* BS */, 0x09 /* HT */, 0x0A /* LF */, 0x0B /* VT */, 0x0C /* FF */, 0x0D /* CR */, 0x0E /* SO */, 0x0F /* SI */, 0x10 /* DLE */, 0x11 /* DC1 */, 0x12 /* DC2 */, 0x13 /* DC3 */, 0x14 /* DC4 */, 0x15 /* NAK */, 0x16 /* SYN */, 0x17 /* ETB */, 0x18 /* CAN */, 0x19 /* EM */, 0x1A /* SUB */, 0x1B /* ESC */, 0x1C /* FS */, 0x1D /* GS */, 0x1E /* RS */, 0x1F /* US */, 0x20 /* SPC */, 0x21 /* ! */, 0x22 /* " */, 0x23 /* # */, 0x24 /* $ */, 0x25 /* % */, 0x26 /* & */, 0x27 /* ' */, 0x28 /* ( */, 0x29 /* ) */, 0x2A /* * */, 0x2B /* + */, 0x2C /* , */, 0x2D /* - */, 0x2E /* . */, 0x2F /* / */, 0x30 /* 0 */, 0x31 /* 1 */, 0x32 /* 2 */, 0x33 /* 3 */, 0x34 /* 4 */, 0x35 /* 5 */, 0x36 /* 6 */, 0x37 /* 7 */, 0x38 /* 8 */, 0x39 /* 9 */, 0x3A /* : */, 0x3B /* ; */, 0x3C /* < */, 0x3D /* = */, 0x3E /* > */, 0x3F /* ? */, 0x40 /* @ */, 0x61 /* A */, 0x62 /* B */, 0x63 /* C */, 0x64 /* D */, 0x65 /* E */, 0x66 /* F */, 0x67 /* G */, 0x68 /* H */, 0x69 /* I */, 0x6A /* J */, 0x6B /* K */, 0x6C /* L */, 0x6D /* M */, 0x6E /* N */, 0x6F /* O */, 0x70 /* P */, 0x71 /* Q */, 0x72 /* R */, 0x73 /* S */, 0x74 /* T */, 0x75 /* U */, 0x76 /* V */, 0x77 /* W */, 0x78 /* X */, 0x79 /* Y */, 0x7A /* Z */, 0x5B /* [ */, 0x5C /* \ */, 0x5D /* ] */, 0x5E /* ^ */, 0x5F /* _ */, 0x60 /* ` */, 0x61 /* a */, 0x62 /* b */, 0x63 /* c */, 0x64 /* d */, 0x65 /* e */, 0x66 /* f */, 0x67 /* g */, 0x68 /* h */, 0x69 /* i */, 0x6A /* j */, 0x6B /* k */, 0x6C /* l */, 0x6D /* m */, 0x6E /* n */, 0x6F /* o */, 0x70 /* p */, 0x71 /* q */, 0x72 /* r */, 0x73 /* s */, 0x74 /* t */, 0x75 /* u */, 0x76 /* v */, 0x77 /* w */, 0x78 /* x */, 0x79 /* y */, 0x7A /* z */, 0x7B /* { */, 0x7C /* | */, 0x7D /* } */, 0x7E /* ~ */, 0x7F /* DEL */, 0x80 /* 0x80 */, 0x81 /* 0x81 */, 0x82 /* 0x82 */, 0x83 /* 0x83 */, 0x84 /* 0x84 */, 0x85 /* 0x85 */, 0x86 /* 0x86 */, 0x87 /* 0x87 */, 0x88 /* 0x88 */, 0x89 /* 0x89 */, 0x8A /* 0x8A */, 0x8B /* 0x8B */, 0x8C /* 0x8C */, 0x8D /* 0x8D */, 0x8E /* 0x8E */, 0x8F /* 0x8F */, 0x90 /* 0x90 */, 0x91 /* 0x91 */, 0x92 /* 0x92 */, 0x93 /* 0x93 */, 0x94 /* 0x94 */, 0x95 /* 0x95 */, 0x96 /* 0x96 */, 0x97 /* 0x97 */, 0x98 /* 0x98 */, 0x99 /* 0x99 */, 0x9A /* 0x9A */, 0x9B /* 0x9B */, 0x9C /* 0x9C */, 0x9D /* 0x9D */, 0x9E /* 0x9E */, 0x9F /* 0x9F */, 0xA0 /* 0xA0 */, 0xA1 /* 0xA1 */, 0xA2 /* 0xA2 */, 0xA3 /* 0xA3 */, 0xA4 /* 0xA4 */, 0xA5 /* 0xA5 */, 0xA6 /* 0xA6 */, 0xA7 /* 0xA7 */, 0xA8 /* 0xA8 */, 0xA9 /* 0xA9 */, 0xAA /* 0xAA */, 0xAB /* 0xAB */, 0xAC /* 0xAC */, 0xAD /* 0xAD */, 0xAE /* 0xAE */, 0xAF /* 0xAF */, 0xB0 /* 0xB0 */, 0xB1 /* 0xB1 */, 0xB2 /* 0xB2 */, 0xB3 /* 0xB3 */, 0xB4 /* 0xB4 */, 0xB5 /* 0xB5 */, 0xB6 /* 0xB6 */, 0xB7 /* 0xB7 */, 0xB8 /* 0xB8 */, 0xB9 /* 0xB9 */, 0xBA /* 0xBA */, 0xBB /* 0xBB */, 0xBC /* 0xBC */, 0xBD /* 0xBD */, 0xBE /* 0xBE */, 0xBF /* 0xBF */, 0xC0 /* 0xC0 */, 0xC1 /* 0xC1 */, 0xC2 /* 0xC2 */, 0xC3 /* 0xC3 */, 0xC4 /* 0xC4 */, 0xC5 /* 0xC5 */, 0xC6 /* 0xC6 */, 0xC7 /* 0xC7 */, 0xC8 /* 0xC8 */, 0xC9 /* 0xC9 */, 0xCA /* 0xCA */, 0xCB /* 0xCB */, 0xCC /* 0xCC */, 0xCD /* 0xCD */, 0xCE /* 0xCE */, 0xCF /* 0xCF */, 0xD0 /* 0xD0 */, 0xD1 /* 0xD1 */, 0xD2 /* 0xD2 */, 0xD3 /* 0xD3 */, 0xD4 /* 0xD4 */, 0xD5 /* 0xD5 */, 0xD6 /* 0xD6 */, 0xD7 /* 0xD7 */, 0xD8 /* 0xD8 */, 0xD9 /* 0xD9 */, 0xDA /* 0xDA */, 0xDB /* 0xDB */, 0xDC /* 0xDC */, 0xDD /* 0xDD */, 0xDE /* 0xDE */, 0xDF /* 0xDF */, 0xE0 /* 0xE0 */, 0xE1 /* 0xE1 */, 0xE2 /* 0xE2 */, 0xE3 /* 0xE3 */, 0xE4 /* 0xE4 */, 0xE5 /* 0xE5 */, 0xE6 /* 0xE6 */, 0xE7 /* 0xE7 */, 0xE8 /* 0xE8 */, 0xE9 /* 0xE9 */, 0xEA /* 0xEA */, 0xEB /* 0xEB */, 0xEC /* 0xEC */, 0xED /* 0xED */, 0xEE /* 0xEE */, 0xEF /* 0xEF */, 0xF0 /* 0xF0 */, 0xF1 /* 0xF1 */, 0xF2 /* 0xF2 */, 0xF3 /* 0xF3 */, 0xF4 /* 0xF4 */, 0xF5 /* 0xF5 */, 0xF6 /* 0xF6 */, 0xF7 /* 0xF7 */, 0xF8 /* 0xF8 */, 0xF9 /* 0xF9 */, 0xFA /* 0xFA */, 0xFB /* 0xFB */, 0xFC /* 0xFC */, 0xFD /* 0xFD */, 0xFE /* 0xFE */, 0xFF /* 0xFF */, }; void nghttp2_downcase(uint8_t *s, size_t len) { size_t i; for (i = 0; i < len; ++i) { s[i] = nghttp2_downcase_byte(s[i]); } } /* * local_window_size * ^ * * | * recv_window_size * | * * ^ * | * * | * 0+++++++++ * | * * \ * | * * | This rage is hidden in flow control. But it must be * v * * / kept in order to restore it when window size is enlarged. * recv_reduction * (+ for negative direction) * * recv_window_size could be negative if we decrease * local_window_size more than recv_window_size: * * local_window_size * ^ * * | * * | * * 0++++++++ * | * ^ recv_window_size (negative) * | * | * v * * * recv_reduction */ int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr, int32_t *recv_window_size_ptr, int32_t *recv_reduction_ptr, int32_t *delta_ptr) { if (*delta_ptr > 0) { int32_t recv_reduction_delta; int32_t delta; int32_t new_recv_window_size = nghttp2_max_int32(0, *recv_window_size_ptr) - *delta_ptr; if (new_recv_window_size >= 0) { *recv_window_size_ptr = new_recv_window_size; return 0; } delta = -new_recv_window_size; /* The delta size is strictly more than received bytes. Increase local_window_size by that difference |delta|. */ if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) { return NGHTTP2_ERR_FLOW_CONTROL; } *local_window_size_ptr += delta; /* If there is recv_reduction due to earlier window_size reduction, we have to adjust it too. */ recv_reduction_delta = nghttp2_min_int32(*recv_reduction_ptr, delta); *recv_reduction_ptr -= recv_reduction_delta; if (*recv_window_size_ptr < 0) { *recv_window_size_ptr += recv_reduction_delta; } else { /* If *recv_window_size_ptr > 0, then those bytes are going to be returned to the remote peer (by WINDOW_UPDATE with the adjusted *delta_ptr), so it is effectively 0 now. We set to *recv_reduction_delta, because caller does not take into account it in *delta_ptr. */ *recv_window_size_ptr = recv_reduction_delta; } /* recv_reduction_delta must be paid from *delta_ptr, since it was added in window size reduction (see below). */ *delta_ptr -= recv_reduction_delta; return 0; } if (*local_window_size_ptr + *delta_ptr < 0 || *recv_window_size_ptr < INT32_MIN - *delta_ptr || *recv_reduction_ptr > INT32_MAX + *delta_ptr) { return NGHTTP2_ERR_FLOW_CONTROL; } /* Decreasing local window size. Note that we achieve this without noticing to the remote peer. To do this, we cut recv_window_size by -delta. This means that we don't send WINDOW_UPDATE for -delta bytes. */ *local_window_size_ptr += *delta_ptr; *recv_window_size_ptr += *delta_ptr; *recv_reduction_ptr -= *delta_ptr; *delta_ptr = 0; return 0; } int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr, int32_t *recv_window_size_ptr, int32_t *recv_reduction_ptr, int32_t *delta_ptr) { int32_t recv_reduction_delta; int32_t delta; delta = *delta_ptr; assert(delta >= 0); /* The delta size is strictly more than received bytes. Increase local_window_size by that difference |delta|. */ if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) { return NGHTTP2_ERR_FLOW_CONTROL; } *local_window_size_ptr += delta; /* If there is recv_reduction due to earlier window_size reduction, we have to adjust it too. */ recv_reduction_delta = nghttp2_min_int32(*recv_reduction_ptr, delta); *recv_reduction_ptr -= recv_reduction_delta; *recv_window_size_ptr += recv_reduction_delta; /* recv_reduction_delta must be paid from *delta_ptr, since it was added in window size reduction (see below). */ *delta_ptr -= recv_reduction_delta; return 0; } int nghttp2_should_send_window_update(int32_t local_window_size, int32_t recv_window_size) { return recv_window_size > 0 && recv_window_size >= local_window_size / 2; } const char *nghttp2_strerror(int error_code) { switch (error_code) { case 0: return "Success"; case NGHTTP2_ERR_INVALID_ARGUMENT: return "Invalid argument"; case NGHTTP2_ERR_BUFFER_ERROR: return "Out of buffer space"; case NGHTTP2_ERR_UNSUPPORTED_VERSION: return "Unsupported SPDY version"; case NGHTTP2_ERR_WOULDBLOCK: return "Operation would block"; case NGHTTP2_ERR_PROTO: return "Protocol error"; case NGHTTP2_ERR_INVALID_FRAME: return "Invalid frame octets"; case NGHTTP2_ERR_EOF: return "EOF"; case NGHTTP2_ERR_DEFERRED: return "Data transfer deferred"; case NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE: return "No more Stream ID available"; case NGHTTP2_ERR_STREAM_CLOSED: return "Stream was already closed or invalid"; case NGHTTP2_ERR_STREAM_CLOSING: return "Stream is closing"; case NGHTTP2_ERR_STREAM_SHUT_WR: return "The transmission is not allowed for this stream"; case NGHTTP2_ERR_INVALID_STREAM_ID: return "Stream ID is invalid"; case NGHTTP2_ERR_INVALID_STREAM_STATE: return "Invalid stream state"; case NGHTTP2_ERR_DEFERRED_DATA_EXIST: return "Another DATA frame has already been deferred"; case NGHTTP2_ERR_START_STREAM_NOT_ALLOWED: return "request HEADERS is not allowed"; case NGHTTP2_ERR_GOAWAY_ALREADY_SENT: return "GOAWAY has already been sent"; case NGHTTP2_ERR_INVALID_HEADER_BLOCK: return "Invalid header block"; case NGHTTP2_ERR_INVALID_STATE: return "Invalid state"; case NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE: return "The user callback function failed due to the temporal error"; case NGHTTP2_ERR_FRAME_SIZE_ERROR: return "The length of the frame is invalid"; case NGHTTP2_ERR_HEADER_COMP: return "Header compression/decompression error"; case NGHTTP2_ERR_FLOW_CONTROL: return "Flow control error"; case NGHTTP2_ERR_INSUFF_BUFSIZE: return "Insufficient buffer size given to function"; case NGHTTP2_ERR_PAUSE: return "Callback was paused by the application"; case NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS: return "Too many inflight SETTINGS"; case NGHTTP2_ERR_PUSH_DISABLED: return "Server push is disabled by peer"; case NGHTTP2_ERR_DATA_EXIST: return "DATA or HEADERS frame has already been submitted for the stream"; case NGHTTP2_ERR_SESSION_CLOSING: return "The current session is closing"; case NGHTTP2_ERR_HTTP_HEADER: return "Invalid HTTP header field was received"; case NGHTTP2_ERR_HTTP_MESSAGING: return "Violation in HTTP messaging rule"; case NGHTTP2_ERR_REFUSED_STREAM: return "Stream was refused"; case NGHTTP2_ERR_INTERNAL: return "Internal error"; case NGHTTP2_ERR_CANCEL: return "Cancel"; case NGHTTP2_ERR_SETTINGS_EXPECTED: return "When a local endpoint expects to receive SETTINGS frame, it " "receives an other type of frame"; case NGHTTP2_ERR_NOMEM: return "Out of memory"; case NGHTTP2_ERR_CALLBACK_FAILURE: return "The user callback function failed"; case NGHTTP2_ERR_BAD_CLIENT_MAGIC: return "Received bad client magic byte string"; case NGHTTP2_ERR_FLOODED: return "Flooding was detected in this HTTP/2 session, and it must be " "closed"; case NGHTTP2_ERR_TOO_MANY_SETTINGS: return "SETTINGS frame contained more than the maximum allowed entries"; case NGHTTP2_ERR_TOO_MANY_CONTINUATIONS: return "Too many CONTINUATION frames following a HEADER frame"; default: return "Unknown error code"; } } static const uint8_t VALID_HD_NAME_CHARS[256] = { ['!'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['*'] = 1, ['+'] = 1, ['-'] = 1, ['.'] = 1, ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1, ['A'] = 2, ['B'] = 2, ['C'] = 2, ['D'] = 2, ['E'] = 2, ['F'] = 2, ['G'] = 2, ['H'] = 2, ['I'] = 2, ['J'] = 2, ['K'] = 2, ['L'] = 2, ['M'] = 2, ['N'] = 2, ['O'] = 2, ['P'] = 2, ['Q'] = 2, ['R'] = 2, ['S'] = 2, ['T'] = 2, ['U'] = 2, ['V'] = 2, ['W'] = 2, ['X'] = 2, ['Y'] = 2, ['Z'] = 2, ['^'] = 1, ['_'] = 1, ['`'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['|'] = 1, ['~'] = 1, }; int nghttp2_check_header_name(const uint8_t *name, size_t len) { const uint8_t *last; if (len == 0) { return 0; } if (*name == ':') { if (len == 1) { return 0; } ++name; --len; } for (last = name + len; name != last; ++name) { if (VALID_HD_NAME_CHARS[*name] != 1) { return 0; } } return 1; } int nghttp2_check_nonempty_header_name(const uint8_t *name, size_t len) { const uint8_t *last; int rv; for (last = name + len; name != last; ++name) { rv = VALID_HD_NAME_CHARS[*name]; if (rv != 1) { return rv; } } return 1; } static const uint8_t VALID_HD_VALUE_CHARS[256] = { ['\t'] = 1, [' '] = 1, ['!'] = 1, ['"'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['('] = 1, [')'] = 1, ['*'] = 1, ['+'] = 1, [','] = 1, ['-'] = 1, ['.'] = 1, ['/'] = 1, ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1, [':'] = 1, [';'] = 1, ['<'] = 1, ['='] = 1, ['>'] = 1, ['?'] = 1, ['@'] = 1, ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 1, ['\\'] = 1, [']'] = 1, ['^'] = 1, ['_'] = 1, ['`'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['{'] = 1, ['|'] = 1, ['}'] = 1, ['~'] = 1, [0x80] = 1, [0x81] = 1, [0x82] = 1, [0x83] = 1, [0x84] = 1, [0x85] = 1, [0x86] = 1, [0x87] = 1, [0x88] = 1, [0x89] = 1, [0x8A] = 1, [0x8B] = 1, [0x8C] = 1, [0x8D] = 1, [0x8E] = 1, [0x8F] = 1, [0x90] = 1, [0x91] = 1, [0x92] = 1, [0x93] = 1, [0x94] = 1, [0x95] = 1, [0x96] = 1, [0x97] = 1, [0x98] = 1, [0x99] = 1, [0x9A] = 1, [0x9B] = 1, [0x9C] = 1, [0x9D] = 1, [0x9E] = 1, [0x9F] = 1, [0xA0] = 1, [0xA1] = 1, [0xA2] = 1, [0xA3] = 1, [0xA4] = 1, [0xA5] = 1, [0xA6] = 1, [0xA7] = 1, [0xA8] = 1, [0xA9] = 1, [0xAA] = 1, [0xAB] = 1, [0xAC] = 1, [0xAD] = 1, [0xAE] = 1, [0xAF] = 1, [0xB0] = 1, [0xB1] = 1, [0xB2] = 1, [0xB3] = 1, [0xB4] = 1, [0xB5] = 1, [0xB6] = 1, [0xB7] = 1, [0xB8] = 1, [0xB9] = 1, [0xBA] = 1, [0xBB] = 1, [0xBC] = 1, [0xBD] = 1, [0xBE] = 1, [0xBF] = 1, [0xC0] = 1, [0xC1] = 1, [0xC2] = 1, [0xC3] = 1, [0xC4] = 1, [0xC5] = 1, [0xC6] = 1, [0xC7] = 1, [0xC8] = 1, [0xC9] = 1, [0xCA] = 1, [0xCB] = 1, [0xCC] = 1, [0xCD] = 1, [0xCE] = 1, [0xCF] = 1, [0xD0] = 1, [0xD1] = 1, [0xD2] = 1, [0xD3] = 1, [0xD4] = 1, [0xD5] = 1, [0xD6] = 1, [0xD7] = 1, [0xD8] = 1, [0xD9] = 1, [0xDA] = 1, [0xDB] = 1, [0xDC] = 1, [0xDD] = 1, [0xDE] = 1, [0xDF] = 1, [0xE0] = 1, [0xE1] = 1, [0xE2] = 1, [0xE3] = 1, [0xE4] = 1, [0xE5] = 1, [0xE6] = 1, [0xE7] = 1, [0xE8] = 1, [0xE9] = 1, [0xEA] = 1, [0xEB] = 1, [0xEC] = 1, [0xED] = 1, [0xEE] = 1, [0xEF] = 1, [0xF0] = 1, [0xF1] = 1, [0xF2] = 1, [0xF3] = 1, [0xF4] = 1, [0xF5] = 1, [0xF6] = 1, [0xF7] = 1, [0xF8] = 1, [0xF9] = 1, [0xFA] = 1, [0xFB] = 1, [0xFC] = 1, [0xFD] = 1, [0xFE] = 1, [0xFF] = 1, }; int nghttp2_check_header_value(const uint8_t *value, size_t len) { const uint8_t *last; for (last = value + len; value != last; ++value) { if (!VALID_HD_VALUE_CHARS[*value]) { return 0; } } return 1; } int nghttp2_check_header_value_rfc9113(const uint8_t *value, size_t len) { if (len == 0) { return 1; } if (*value == ' ' || *value == '\t' || *(value + len - 1) == ' ' || *(value + len - 1) == '\t') { return 0; } return nghttp2_check_header_value(value, len); } static const uint8_t VALID_METHOD_CHARS[256] = { ['!'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['*'] = 1, ['+'] = 1, ['-'] = 1, ['.'] = 1, ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1, ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['^'] = 1, ['_'] = 1, ['`'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['|'] = 1, ['~'] = 1, }; int nghttp2_check_method(const uint8_t *value, size_t len) { const uint8_t *last; if (len == 0) { return 0; } for (last = value + len; value != last; ++value) { if (!VALID_METHOD_CHARS[*value]) { return 0; } } return 1; } static const uint8_t VALID_PATH_CHARS[256] = { ['!'] = 1, ['"'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['('] = 1, [')'] = 1, ['*'] = 1, ['+'] = 1, [','] = 1, ['-'] = 1, ['.'] = 1, ['/'] = 1, ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1, [':'] = 1, [';'] = 1, ['<'] = 1, ['='] = 1, ['>'] = 1, ['?'] = 1, ['@'] = 1, ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 1, ['\\'] = 1, [']'] = 1, ['^'] = 1, ['_'] = 1, ['`'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['{'] = 1, ['|'] = 1, ['}'] = 1, ['~'] = 1, [0x80] = 1, [0x81] = 1, [0x82] = 1, [0x83] = 1, [0x84] = 1, [0x85] = 1, [0x86] = 1, [0x87] = 1, [0x88] = 1, [0x89] = 1, [0x8A] = 1, [0x8B] = 1, [0x8C] = 1, [0x8D] = 1, [0x8E] = 1, [0x8F] = 1, [0x90] = 1, [0x91] = 1, [0x92] = 1, [0x93] = 1, [0x94] = 1, [0x95] = 1, [0x96] = 1, [0x97] = 1, [0x98] = 1, [0x99] = 1, [0x9A] = 1, [0x9B] = 1, [0x9C] = 1, [0x9D] = 1, [0x9E] = 1, [0x9F] = 1, [0xA0] = 1, [0xA1] = 1, [0xA2] = 1, [0xA3] = 1, [0xA4] = 1, [0xA5] = 1, [0xA6] = 1, [0xA7] = 1, [0xA8] = 1, [0xA9] = 1, [0xAA] = 1, [0xAB] = 1, [0xAC] = 1, [0xAD] = 1, [0xAE] = 1, [0xAF] = 1, [0xB0] = 1, [0xB1] = 1, [0xB2] = 1, [0xB3] = 1, [0xB4] = 1, [0xB5] = 1, [0xB6] = 1, [0xB7] = 1, [0xB8] = 1, [0xB9] = 1, [0xBA] = 1, [0xBB] = 1, [0xBC] = 1, [0xBD] = 1, [0xBE] = 1, [0xBF] = 1, [0xC0] = 1, [0xC1] = 1, [0xC2] = 1, [0xC3] = 1, [0xC4] = 1, [0xC5] = 1, [0xC6] = 1, [0xC7] = 1, [0xC8] = 1, [0xC9] = 1, [0xCA] = 1, [0xCB] = 1, [0xCC] = 1, [0xCD] = 1, [0xCE] = 1, [0xCF] = 1, [0xD0] = 1, [0xD1] = 1, [0xD2] = 1, [0xD3] = 1, [0xD4] = 1, [0xD5] = 1, [0xD6] = 1, [0xD7] = 1, [0xD8] = 1, [0xD9] = 1, [0xDA] = 1, [0xDB] = 1, [0xDC] = 1, [0xDD] = 1, [0xDE] = 1, [0xDF] = 1, [0xE0] = 1, [0xE1] = 1, [0xE2] = 1, [0xE3] = 1, [0xE4] = 1, [0xE5] = 1, [0xE6] = 1, [0xE7] = 1, [0xE8] = 1, [0xE9] = 1, [0xEA] = 1, [0xEB] = 1, [0xEC] = 1, [0xED] = 1, [0xEE] = 1, [0xEF] = 1, [0xF0] = 1, [0xF1] = 1, [0xF2] = 1, [0xF3] = 1, [0xF4] = 1, [0xF5] = 1, [0xF6] = 1, [0xF7] = 1, [0xF8] = 1, [0xF9] = 1, [0xFA] = 1, [0xFB] = 1, [0xFC] = 1, [0xFD] = 1, [0xFE] = 1, [0xFF] = 1, }; int nghttp2_check_path(const uint8_t *value, size_t len) { const uint8_t *last; for (last = value + len; value != last; ++value) { if (!VALID_PATH_CHARS[*value]) { return 0; } } return 1; } static const uint8_t VALID_AUTHORITY_CHARS[256] = { ['!'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['('] = 1, [')'] = 1, ['*'] = 1, ['+'] = 1, [','] = 1, ['-'] = 1, ['.'] = 1, ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1, [':'] = 1, [';'] = 1, ['='] = 1, ['@'] = 1, ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 1, [']'] = 1, ['_'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['~'] = 1, }; int nghttp2_check_authority(const uint8_t *value, size_t len) { const uint8_t *last; for (last = value + len; value != last; ++value) { if (!VALID_AUTHORITY_CHARS[*value]) { return 0; } } return 1; } uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len) { if (len == 0) { return dest; } memcpy(dest, src, len); return dest + len; } const char *nghttp2_http2_strerror(uint32_t error_code) { switch (error_code) { case NGHTTP2_NO_ERROR: return "NO_ERROR"; case NGHTTP2_PROTOCOL_ERROR: return "PROTOCOL_ERROR"; case NGHTTP2_INTERNAL_ERROR: return "INTERNAL_ERROR"; case NGHTTP2_FLOW_CONTROL_ERROR: return "FLOW_CONTROL_ERROR"; case NGHTTP2_SETTINGS_TIMEOUT: return "SETTINGS_TIMEOUT"; case NGHTTP2_STREAM_CLOSED: return "STREAM_CLOSED"; case NGHTTP2_FRAME_SIZE_ERROR: return "FRAME_SIZE_ERROR"; case NGHTTP2_REFUSED_STREAM: return "REFUSED_STREAM"; case NGHTTP2_CANCEL: return "CANCEL"; case NGHTTP2_COMPRESSION_ERROR: return "COMPRESSION_ERROR"; case NGHTTP2_CONNECT_ERROR: return "CONNECT_ERROR"; case NGHTTP2_ENHANCE_YOUR_CALM: return "ENHANCE_YOUR_CALM"; case NGHTTP2_INADEQUATE_SECURITY: return "INADEQUATE_SECURITY"; case NGHTTP2_HTTP_1_1_REQUIRED: return "HTTP_1_1_REQUIRED"; default: return "unknown"; } }