/src/nghttp2/lib/nghttp2_helper.c
Line | Count | Source |
1 | | /* |
2 | | * nghttp2 - HTTP/2 C Library |
3 | | * |
4 | | * Copyright (c) 2012 Tatsuhiro Tsujikawa |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person obtaining |
7 | | * a copy of this software and associated documentation files (the |
8 | | * "Software"), to deal in the Software without restriction, including |
9 | | * without limitation the rights to use, copy, modify, merge, publish, |
10 | | * distribute, sublicense, and/or sell copies of the Software, and to |
11 | | * permit persons to whom the Software is furnished to do so, subject to |
12 | | * the following conditions: |
13 | | * |
14 | | * The above copyright notice and this permission notice shall be |
15 | | * included in all copies or substantial portions of the Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
18 | | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
19 | | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
20 | | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
21 | | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
22 | | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
23 | | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
24 | | */ |
25 | | #include "nghttp2_helper.h" |
26 | | |
27 | | #include <assert.h> |
28 | | #include <string.h> |
29 | | |
30 | | #include "nghttp2_net.h" |
31 | | |
32 | 9.07k | void nghttp2_put_uint16be(uint8_t *buf, uint16_t n) { |
33 | 9.07k | uint16_t x = htons(n); |
34 | 9.07k | memcpy(buf, &x, sizeof(uint16_t)); |
35 | 9.07k | } |
36 | | |
37 | 76.1k | void nghttp2_put_uint32be(uint8_t *buf, uint32_t n) { |
38 | 76.1k | uint32_t x = htonl(n); |
39 | 76.1k | memcpy(buf, &x, sizeof(uint32_t)); |
40 | 76.1k | } |
41 | | |
42 | 4.86k | uint16_t nghttp2_get_uint16(const uint8_t *data) { |
43 | 4.86k | uint16_t n; |
44 | 4.86k | memcpy(&n, data, sizeof(uint16_t)); |
45 | 4.86k | return ntohs(n); |
46 | 4.86k | } |
47 | | |
48 | 71.6k | uint32_t nghttp2_get_uint32(const uint8_t *data) { |
49 | 71.6k | uint32_t n; |
50 | 71.6k | memcpy(&n, data, sizeof(uint32_t)); |
51 | 71.6k | return ntohl(n); |
52 | 71.6k | } |
53 | | |
54 | | /* Generated by gendowncasetbl.py */ |
55 | | const uint8_t nghttp2_downcase_tbl[] = { |
56 | | 0x00 /* NUL */, 0x01 /* SOH */, 0x02 /* STX */, 0x03 /* ETX */, |
57 | | 0x04 /* EOT */, 0x05 /* ENQ */, 0x06 /* ACK */, 0x07 /* BEL */, |
58 | | 0x08 /* BS */, 0x09 /* HT */, 0x0A /* LF */, 0x0B /* VT */, |
59 | | 0x0C /* FF */, 0x0D /* CR */, 0x0E /* SO */, 0x0F /* SI */, |
60 | | 0x10 /* DLE */, 0x11 /* DC1 */, 0x12 /* DC2 */, 0x13 /* DC3 */, |
61 | | 0x14 /* DC4 */, 0x15 /* NAK */, 0x16 /* SYN */, 0x17 /* ETB */, |
62 | | 0x18 /* CAN */, 0x19 /* EM */, 0x1A /* SUB */, 0x1B /* ESC */, |
63 | | 0x1C /* FS */, 0x1D /* GS */, 0x1E /* RS */, 0x1F /* US */, |
64 | | 0x20 /* SPC */, 0x21 /* ! */, 0x22 /* " */, 0x23 /* # */, |
65 | | 0x24 /* $ */, 0x25 /* % */, 0x26 /* & */, 0x27 /* ' */, |
66 | | 0x28 /* ( */, 0x29 /* ) */, 0x2A /* * */, 0x2B /* + */, |
67 | | 0x2C /* , */, 0x2D /* - */, 0x2E /* . */, 0x2F /* / */, |
68 | | 0x30 /* 0 */, 0x31 /* 1 */, 0x32 /* 2 */, 0x33 /* 3 */, |
69 | | 0x34 /* 4 */, 0x35 /* 5 */, 0x36 /* 6 */, 0x37 /* 7 */, |
70 | | 0x38 /* 8 */, 0x39 /* 9 */, 0x3A /* : */, 0x3B /* ; */, |
71 | | 0x3C /* < */, 0x3D /* = */, 0x3E /* > */, 0x3F /* ? */, |
72 | | 0x40 /* @ */, 0x61 /* A */, 0x62 /* B */, 0x63 /* C */, |
73 | | 0x64 /* D */, 0x65 /* E */, 0x66 /* F */, 0x67 /* G */, |
74 | | 0x68 /* H */, 0x69 /* I */, 0x6A /* J */, 0x6B /* K */, |
75 | | 0x6C /* L */, 0x6D /* M */, 0x6E /* N */, 0x6F /* O */, |
76 | | 0x70 /* P */, 0x71 /* Q */, 0x72 /* R */, 0x73 /* S */, |
77 | | 0x74 /* T */, 0x75 /* U */, 0x76 /* V */, 0x77 /* W */, |
78 | | 0x78 /* X */, 0x79 /* Y */, 0x7A /* Z */, 0x5B /* [ */, |
79 | | 0x5C /* \ */, 0x5D /* ] */, 0x5E /* ^ */, 0x5F /* _ */, |
80 | | 0x60 /* ` */, 0x61 /* a */, 0x62 /* b */, 0x63 /* c */, |
81 | | 0x64 /* d */, 0x65 /* e */, 0x66 /* f */, 0x67 /* g */, |
82 | | 0x68 /* h */, 0x69 /* i */, 0x6A /* j */, 0x6B /* k */, |
83 | | 0x6C /* l */, 0x6D /* m */, 0x6E /* n */, 0x6F /* o */, |
84 | | 0x70 /* p */, 0x71 /* q */, 0x72 /* r */, 0x73 /* s */, |
85 | | 0x74 /* t */, 0x75 /* u */, 0x76 /* v */, 0x77 /* w */, |
86 | | 0x78 /* x */, 0x79 /* y */, 0x7A /* z */, 0x7B /* { */, |
87 | | 0x7C /* | */, 0x7D /* } */, 0x7E /* ~ */, 0x7F /* DEL */, |
88 | | 0x80 /* 0x80 */, 0x81 /* 0x81 */, 0x82 /* 0x82 */, 0x83 /* 0x83 */, |
89 | | 0x84 /* 0x84 */, 0x85 /* 0x85 */, 0x86 /* 0x86 */, 0x87 /* 0x87 */, |
90 | | 0x88 /* 0x88 */, 0x89 /* 0x89 */, 0x8A /* 0x8A */, 0x8B /* 0x8B */, |
91 | | 0x8C /* 0x8C */, 0x8D /* 0x8D */, 0x8E /* 0x8E */, 0x8F /* 0x8F */, |
92 | | 0x90 /* 0x90 */, 0x91 /* 0x91 */, 0x92 /* 0x92 */, 0x93 /* 0x93 */, |
93 | | 0x94 /* 0x94 */, 0x95 /* 0x95 */, 0x96 /* 0x96 */, 0x97 /* 0x97 */, |
94 | | 0x98 /* 0x98 */, 0x99 /* 0x99 */, 0x9A /* 0x9A */, 0x9B /* 0x9B */, |
95 | | 0x9C /* 0x9C */, 0x9D /* 0x9D */, 0x9E /* 0x9E */, 0x9F /* 0x9F */, |
96 | | 0xA0 /* 0xA0 */, 0xA1 /* 0xA1 */, 0xA2 /* 0xA2 */, 0xA3 /* 0xA3 */, |
97 | | 0xA4 /* 0xA4 */, 0xA5 /* 0xA5 */, 0xA6 /* 0xA6 */, 0xA7 /* 0xA7 */, |
98 | | 0xA8 /* 0xA8 */, 0xA9 /* 0xA9 */, 0xAA /* 0xAA */, 0xAB /* 0xAB */, |
99 | | 0xAC /* 0xAC */, 0xAD /* 0xAD */, 0xAE /* 0xAE */, 0xAF /* 0xAF */, |
100 | | 0xB0 /* 0xB0 */, 0xB1 /* 0xB1 */, 0xB2 /* 0xB2 */, 0xB3 /* 0xB3 */, |
101 | | 0xB4 /* 0xB4 */, 0xB5 /* 0xB5 */, 0xB6 /* 0xB6 */, 0xB7 /* 0xB7 */, |
102 | | 0xB8 /* 0xB8 */, 0xB9 /* 0xB9 */, 0xBA /* 0xBA */, 0xBB /* 0xBB */, |
103 | | 0xBC /* 0xBC */, 0xBD /* 0xBD */, 0xBE /* 0xBE */, 0xBF /* 0xBF */, |
104 | | 0xC0 /* 0xC0 */, 0xC1 /* 0xC1 */, 0xC2 /* 0xC2 */, 0xC3 /* 0xC3 */, |
105 | | 0xC4 /* 0xC4 */, 0xC5 /* 0xC5 */, 0xC6 /* 0xC6 */, 0xC7 /* 0xC7 */, |
106 | | 0xC8 /* 0xC8 */, 0xC9 /* 0xC9 */, 0xCA /* 0xCA */, 0xCB /* 0xCB */, |
107 | | 0xCC /* 0xCC */, 0xCD /* 0xCD */, 0xCE /* 0xCE */, 0xCF /* 0xCF */, |
108 | | 0xD0 /* 0xD0 */, 0xD1 /* 0xD1 */, 0xD2 /* 0xD2 */, 0xD3 /* 0xD3 */, |
109 | | 0xD4 /* 0xD4 */, 0xD5 /* 0xD5 */, 0xD6 /* 0xD6 */, 0xD7 /* 0xD7 */, |
110 | | 0xD8 /* 0xD8 */, 0xD9 /* 0xD9 */, 0xDA /* 0xDA */, 0xDB /* 0xDB */, |
111 | | 0xDC /* 0xDC */, 0xDD /* 0xDD */, 0xDE /* 0xDE */, 0xDF /* 0xDF */, |
112 | | 0xE0 /* 0xE0 */, 0xE1 /* 0xE1 */, 0xE2 /* 0xE2 */, 0xE3 /* 0xE3 */, |
113 | | 0xE4 /* 0xE4 */, 0xE5 /* 0xE5 */, 0xE6 /* 0xE6 */, 0xE7 /* 0xE7 */, |
114 | | 0xE8 /* 0xE8 */, 0xE9 /* 0xE9 */, 0xEA /* 0xEA */, 0xEB /* 0xEB */, |
115 | | 0xEC /* 0xEC */, 0xED /* 0xED */, 0xEE /* 0xEE */, 0xEF /* 0xEF */, |
116 | | 0xF0 /* 0xF0 */, 0xF1 /* 0xF1 */, 0xF2 /* 0xF2 */, 0xF3 /* 0xF3 */, |
117 | | 0xF4 /* 0xF4 */, 0xF5 /* 0xF5 */, 0xF6 /* 0xF6 */, 0xF7 /* 0xF7 */, |
118 | | 0xF8 /* 0xF8 */, 0xF9 /* 0xF9 */, 0xFA /* 0xFA */, 0xFB /* 0xFB */, |
119 | | 0xFC /* 0xFC */, 0xFD /* 0xFD */, 0xFE /* 0xFE */, 0xFF /* 0xFF */, |
120 | | }; |
121 | | |
122 | 0 | void nghttp2_downcase(uint8_t *s, size_t len) { |
123 | 0 | size_t i; |
124 | 0 | for (i = 0; i < len; ++i) { |
125 | 0 | s[i] = nghttp2_downcase_byte(s[i]); |
126 | 0 | } |
127 | 0 | } |
128 | | |
129 | | /* |
130 | | * local_window_size |
131 | | * ^ * |
132 | | * | * recv_window_size |
133 | | * | * * ^ |
134 | | * | * * | |
135 | | * 0+++++++++ |
136 | | * | * * \ |
137 | | * | * * | This rage is hidden in flow control. But it must be |
138 | | * v * * / kept in order to restore it when window size is enlarged. |
139 | | * recv_reduction |
140 | | * (+ for negative direction) |
141 | | * |
142 | | * recv_window_size could be negative if we decrease |
143 | | * local_window_size more than recv_window_size: |
144 | | * |
145 | | * local_window_size |
146 | | * ^ * |
147 | | * | * |
148 | | * | * |
149 | | * 0++++++++ |
150 | | * | * ^ recv_window_size (negative) |
151 | | * | * | |
152 | | * v * * |
153 | | * recv_reduction |
154 | | */ |
155 | | int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr, |
156 | | int32_t *recv_window_size_ptr, |
157 | | int32_t *recv_reduction_ptr, |
158 | 0 | int32_t *delta_ptr) { |
159 | 0 | if (*delta_ptr > 0) { |
160 | 0 | int32_t recv_reduction_delta; |
161 | 0 | int32_t delta; |
162 | 0 | int32_t new_recv_window_size = |
163 | 0 | nghttp2_max_int32(0, *recv_window_size_ptr) - *delta_ptr; |
164 | |
|
165 | 0 | if (new_recv_window_size >= 0) { |
166 | 0 | *recv_window_size_ptr = new_recv_window_size; |
167 | 0 | return 0; |
168 | 0 | } |
169 | | |
170 | 0 | delta = -new_recv_window_size; |
171 | | |
172 | | /* The delta size is strictly more than received bytes. Increase |
173 | | local_window_size by that difference |delta|. */ |
174 | 0 | if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) { |
175 | 0 | return NGHTTP2_ERR_FLOW_CONTROL; |
176 | 0 | } |
177 | 0 | *local_window_size_ptr += delta; |
178 | | /* If there is recv_reduction due to earlier window_size |
179 | | reduction, we have to adjust it too. */ |
180 | 0 | recv_reduction_delta = nghttp2_min_int32(*recv_reduction_ptr, delta); |
181 | 0 | *recv_reduction_ptr -= recv_reduction_delta; |
182 | 0 | if (*recv_window_size_ptr < 0) { |
183 | 0 | *recv_window_size_ptr += recv_reduction_delta; |
184 | 0 | } else { |
185 | | /* If *recv_window_size_ptr > 0, then those bytes are going to |
186 | | be returned to the remote peer (by WINDOW_UPDATE with the |
187 | | adjusted *delta_ptr), so it is effectively 0 now. We set to |
188 | | *recv_reduction_delta, because caller does not take into |
189 | | account it in *delta_ptr. */ |
190 | 0 | *recv_window_size_ptr = recv_reduction_delta; |
191 | 0 | } |
192 | | /* recv_reduction_delta must be paid from *delta_ptr, since it was |
193 | | added in window size reduction (see below). */ |
194 | 0 | *delta_ptr -= recv_reduction_delta; |
195 | |
|
196 | 0 | return 0; |
197 | 0 | } |
198 | | |
199 | 0 | if (*local_window_size_ptr + *delta_ptr < 0 || |
200 | 0 | *recv_window_size_ptr < INT32_MIN - *delta_ptr || |
201 | 0 | *recv_reduction_ptr > INT32_MAX + *delta_ptr) { |
202 | 0 | return NGHTTP2_ERR_FLOW_CONTROL; |
203 | 0 | } |
204 | | /* Decreasing local window size. Note that we achieve this without |
205 | | noticing to the remote peer. To do this, we cut |
206 | | recv_window_size by -delta. This means that we don't send |
207 | | WINDOW_UPDATE for -delta bytes. */ |
208 | 0 | *local_window_size_ptr += *delta_ptr; |
209 | 0 | *recv_window_size_ptr += *delta_ptr; |
210 | 0 | *recv_reduction_ptr -= *delta_ptr; |
211 | 0 | *delta_ptr = 0; |
212 | |
|
213 | 0 | return 0; |
214 | 0 | } |
215 | | |
216 | | int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr, |
217 | | int32_t *recv_window_size_ptr, |
218 | | int32_t *recv_reduction_ptr, |
219 | 0 | int32_t *delta_ptr) { |
220 | 0 | int32_t recv_reduction_delta; |
221 | 0 | int32_t delta; |
222 | |
|
223 | 0 | delta = *delta_ptr; |
224 | |
|
225 | 0 | assert(delta >= 0); |
226 | | |
227 | | /* The delta size is strictly more than received bytes. Increase |
228 | | local_window_size by that difference |delta|. */ |
229 | 0 | if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) { |
230 | 0 | return NGHTTP2_ERR_FLOW_CONTROL; |
231 | 0 | } |
232 | | |
233 | 0 | *local_window_size_ptr += delta; |
234 | | /* If there is recv_reduction due to earlier window_size |
235 | | reduction, we have to adjust it too. */ |
236 | 0 | recv_reduction_delta = nghttp2_min_int32(*recv_reduction_ptr, delta); |
237 | 0 | *recv_reduction_ptr -= recv_reduction_delta; |
238 | |
|
239 | 0 | *recv_window_size_ptr += recv_reduction_delta; |
240 | | |
241 | | /* recv_reduction_delta must be paid from *delta_ptr, since it was |
242 | | added in window size reduction (see below). */ |
243 | 0 | *delta_ptr -= recv_reduction_delta; |
244 | |
|
245 | 0 | return 0; |
246 | 0 | } |
247 | | |
248 | | int nghttp2_should_send_window_update(int32_t local_window_size, |
249 | 1.68k | int32_t recv_window_size) { |
250 | 1.68k | return recv_window_size > 0 && recv_window_size >= local_window_size / 2; |
251 | 1.68k | } |
252 | | |
253 | 0 | const char *nghttp2_strerror(int error_code) { |
254 | 0 | switch (error_code) { |
255 | 0 | case 0: |
256 | 0 | return "Success"; |
257 | 0 | case NGHTTP2_ERR_INVALID_ARGUMENT: |
258 | 0 | return "Invalid argument"; |
259 | 0 | case NGHTTP2_ERR_BUFFER_ERROR: |
260 | 0 | return "Out of buffer space"; |
261 | 0 | case NGHTTP2_ERR_UNSUPPORTED_VERSION: |
262 | 0 | return "Unsupported SPDY version"; |
263 | 0 | case NGHTTP2_ERR_WOULDBLOCK: |
264 | 0 | return "Operation would block"; |
265 | 0 | case NGHTTP2_ERR_PROTO: |
266 | 0 | return "Protocol error"; |
267 | 0 | case NGHTTP2_ERR_INVALID_FRAME: |
268 | 0 | return "Invalid frame octets"; |
269 | 0 | case NGHTTP2_ERR_EOF: |
270 | 0 | return "EOF"; |
271 | 0 | case NGHTTP2_ERR_DEFERRED: |
272 | 0 | return "Data transfer deferred"; |
273 | 0 | case NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE: |
274 | 0 | return "No more Stream ID available"; |
275 | 0 | case NGHTTP2_ERR_STREAM_CLOSED: |
276 | 0 | return "Stream was already closed or invalid"; |
277 | 0 | case NGHTTP2_ERR_STREAM_CLOSING: |
278 | 0 | return "Stream is closing"; |
279 | 0 | case NGHTTP2_ERR_STREAM_SHUT_WR: |
280 | 0 | return "The transmission is not allowed for this stream"; |
281 | 0 | case NGHTTP2_ERR_INVALID_STREAM_ID: |
282 | 0 | return "Stream ID is invalid"; |
283 | 0 | case NGHTTP2_ERR_INVALID_STREAM_STATE: |
284 | 0 | return "Invalid stream state"; |
285 | 0 | case NGHTTP2_ERR_DEFERRED_DATA_EXIST: |
286 | 0 | return "Another DATA frame has already been deferred"; |
287 | 0 | case NGHTTP2_ERR_START_STREAM_NOT_ALLOWED: |
288 | 0 | return "request HEADERS is not allowed"; |
289 | 0 | case NGHTTP2_ERR_GOAWAY_ALREADY_SENT: |
290 | 0 | return "GOAWAY has already been sent"; |
291 | 0 | case NGHTTP2_ERR_INVALID_HEADER_BLOCK: |
292 | 0 | return "Invalid header block"; |
293 | 0 | case NGHTTP2_ERR_INVALID_STATE: |
294 | 0 | return "Invalid state"; |
295 | 0 | case NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE: |
296 | 0 | return "The user callback function failed due to the temporal error"; |
297 | 0 | case NGHTTP2_ERR_FRAME_SIZE_ERROR: |
298 | 0 | return "The length of the frame is invalid"; |
299 | 0 | case NGHTTP2_ERR_HEADER_COMP: |
300 | 0 | return "Header compression/decompression error"; |
301 | 0 | case NGHTTP2_ERR_FLOW_CONTROL: |
302 | 0 | return "Flow control error"; |
303 | 0 | case NGHTTP2_ERR_INSUFF_BUFSIZE: |
304 | 0 | return "Insufficient buffer size given to function"; |
305 | 0 | case NGHTTP2_ERR_PAUSE: |
306 | 0 | return "Callback was paused by the application"; |
307 | 0 | case NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS: |
308 | 0 | return "Too many inflight SETTINGS"; |
309 | 0 | case NGHTTP2_ERR_PUSH_DISABLED: |
310 | 0 | return "Server push is disabled by peer"; |
311 | 0 | case NGHTTP2_ERR_DATA_EXIST: |
312 | 0 | return "DATA or HEADERS frame has already been submitted for the stream"; |
313 | 0 | case NGHTTP2_ERR_SESSION_CLOSING: |
314 | 0 | return "The current session is closing"; |
315 | 0 | case NGHTTP2_ERR_HTTP_HEADER: |
316 | 0 | return "Invalid HTTP header field was received"; |
317 | 0 | case NGHTTP2_ERR_HTTP_MESSAGING: |
318 | 0 | return "Violation in HTTP messaging rule"; |
319 | 0 | case NGHTTP2_ERR_REFUSED_STREAM: |
320 | 0 | return "Stream was refused"; |
321 | 0 | case NGHTTP2_ERR_INTERNAL: |
322 | 0 | return "Internal error"; |
323 | 0 | case NGHTTP2_ERR_CANCEL: |
324 | 0 | return "Cancel"; |
325 | 0 | case NGHTTP2_ERR_SETTINGS_EXPECTED: |
326 | 0 | return "When a local endpoint expects to receive SETTINGS frame, it " |
327 | 0 | "receives an other type of frame"; |
328 | 0 | case NGHTTP2_ERR_NOMEM: |
329 | 0 | return "Out of memory"; |
330 | 0 | case NGHTTP2_ERR_CALLBACK_FAILURE: |
331 | 0 | return "The user callback function failed"; |
332 | 0 | case NGHTTP2_ERR_BAD_CLIENT_MAGIC: |
333 | 0 | return "Received bad client magic byte string"; |
334 | 0 | case NGHTTP2_ERR_FLOODED: |
335 | 0 | return "Flooding was detected in this HTTP/2 session, and it must be " |
336 | 0 | "closed"; |
337 | 0 | case NGHTTP2_ERR_TOO_MANY_SETTINGS: |
338 | 0 | return "SETTINGS frame contained more than the maximum allowed entries"; |
339 | 0 | case NGHTTP2_ERR_TOO_MANY_CONTINUATIONS: |
340 | 0 | return "Too many CONTINUATION frames following a HEADER frame"; |
341 | 0 | default: |
342 | 0 | return "Unknown error code"; |
343 | 0 | } |
344 | 0 | } |
345 | | |
346 | | static const uint8_t VALID_HD_NAME_CHARS[256] = { |
347 | | ['!'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['*'] = 1, |
348 | | ['+'] = 1, ['-'] = 1, ['.'] = 1, ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, |
349 | | ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1, ['A'] = 2, |
350 | | ['B'] = 2, ['C'] = 2, ['D'] = 2, ['E'] = 2, ['F'] = 2, ['G'] = 2, ['H'] = 2, |
351 | | ['I'] = 2, ['J'] = 2, ['K'] = 2, ['L'] = 2, ['M'] = 2, ['N'] = 2, ['O'] = 2, |
352 | | ['P'] = 2, ['Q'] = 2, ['R'] = 2, ['S'] = 2, ['T'] = 2, ['U'] = 2, ['V'] = 2, |
353 | | ['W'] = 2, ['X'] = 2, ['Y'] = 2, ['Z'] = 2, ['^'] = 1, ['_'] = 1, ['`'] = 1, |
354 | | ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, |
355 | | ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, |
356 | | ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1, |
357 | | ['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['|'] = 1, ['~'] = 1, |
358 | | }; |
359 | | |
360 | 0 | int nghttp2_check_header_name(const uint8_t *name, size_t len) { |
361 | 0 | const uint8_t *last; |
362 | 0 | if (len == 0) { |
363 | 0 | return 0; |
364 | 0 | } |
365 | 0 | if (*name == ':') { |
366 | 0 | if (len == 1) { |
367 | 0 | return 0; |
368 | 0 | } |
369 | 0 | ++name; |
370 | 0 | --len; |
371 | 0 | } |
372 | 0 | for (last = name + len; name != last; ++name) { |
373 | 0 | if (VALID_HD_NAME_CHARS[*name] != 1) { |
374 | 0 | return 0; |
375 | 0 | } |
376 | 0 | } |
377 | 0 | return 1; |
378 | 0 | } |
379 | | |
380 | 30.9k | int nghttp2_check_nonempty_header_name(const uint8_t *name, size_t len) { |
381 | 30.9k | const uint8_t *last; |
382 | 30.9k | int rv; |
383 | | |
384 | 318k | for (last = name + len; name != last; ++name) { |
385 | 290k | rv = VALID_HD_NAME_CHARS[*name]; |
386 | 290k | if (rv != 1) { |
387 | 3.06k | return rv; |
388 | 3.06k | } |
389 | 290k | } |
390 | | |
391 | 27.9k | return 1; |
392 | 30.9k | } |
393 | | |
394 | | static const uint8_t VALID_HD_VALUE_CHARS[256] = { |
395 | | ['\t'] = 1, [' '] = 1, ['!'] = 1, ['"'] = 1, ['#'] = 1, ['$'] = 1, |
396 | | ['%'] = 1, ['&'] = 1, ['\''] = 1, ['('] = 1, [')'] = 1, ['*'] = 1, |
397 | | ['+'] = 1, [','] = 1, ['-'] = 1, ['.'] = 1, ['/'] = 1, ['0'] = 1, |
398 | | ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1, |
399 | | ['7'] = 1, ['8'] = 1, ['9'] = 1, [':'] = 1, [';'] = 1, ['<'] = 1, |
400 | | ['='] = 1, ['>'] = 1, ['?'] = 1, ['@'] = 1, ['A'] = 1, ['B'] = 1, |
401 | | ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1, ['H'] = 1, |
402 | | ['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, |
403 | | ['O'] = 1, ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, |
404 | | ['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1, ['Y'] = 1, ['Z'] = 1, |
405 | | ['['] = 1, ['\\'] = 1, [']'] = 1, ['^'] = 1, ['_'] = 1, ['`'] = 1, |
406 | | ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, |
407 | | ['g'] = 1, ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, |
408 | | ['m'] = 1, ['n'] = 1, ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, |
409 | | ['s'] = 1, ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1, |
410 | | ['y'] = 1, ['z'] = 1, ['{'] = 1, ['|'] = 1, ['}'] = 1, ['~'] = 1, |
411 | | [0x80] = 1, [0x81] = 1, [0x82] = 1, [0x83] = 1, [0x84] = 1, [0x85] = 1, |
412 | | [0x86] = 1, [0x87] = 1, [0x88] = 1, [0x89] = 1, [0x8A] = 1, [0x8B] = 1, |
413 | | [0x8C] = 1, [0x8D] = 1, [0x8E] = 1, [0x8F] = 1, [0x90] = 1, [0x91] = 1, |
414 | | [0x92] = 1, [0x93] = 1, [0x94] = 1, [0x95] = 1, [0x96] = 1, [0x97] = 1, |
415 | | [0x98] = 1, [0x99] = 1, [0x9A] = 1, [0x9B] = 1, [0x9C] = 1, [0x9D] = 1, |
416 | | [0x9E] = 1, [0x9F] = 1, [0xA0] = 1, [0xA1] = 1, [0xA2] = 1, [0xA3] = 1, |
417 | | [0xA4] = 1, [0xA5] = 1, [0xA6] = 1, [0xA7] = 1, [0xA8] = 1, [0xA9] = 1, |
418 | | [0xAA] = 1, [0xAB] = 1, [0xAC] = 1, [0xAD] = 1, [0xAE] = 1, [0xAF] = 1, |
419 | | [0xB0] = 1, [0xB1] = 1, [0xB2] = 1, [0xB3] = 1, [0xB4] = 1, [0xB5] = 1, |
420 | | [0xB6] = 1, [0xB7] = 1, [0xB8] = 1, [0xB9] = 1, [0xBA] = 1, [0xBB] = 1, |
421 | | [0xBC] = 1, [0xBD] = 1, [0xBE] = 1, [0xBF] = 1, [0xC0] = 1, [0xC1] = 1, |
422 | | [0xC2] = 1, [0xC3] = 1, [0xC4] = 1, [0xC5] = 1, [0xC6] = 1, [0xC7] = 1, |
423 | | [0xC8] = 1, [0xC9] = 1, [0xCA] = 1, [0xCB] = 1, [0xCC] = 1, [0xCD] = 1, |
424 | | [0xCE] = 1, [0xCF] = 1, [0xD0] = 1, [0xD1] = 1, [0xD2] = 1, [0xD3] = 1, |
425 | | [0xD4] = 1, [0xD5] = 1, [0xD6] = 1, [0xD7] = 1, [0xD8] = 1, [0xD9] = 1, |
426 | | [0xDA] = 1, [0xDB] = 1, [0xDC] = 1, [0xDD] = 1, [0xDE] = 1, [0xDF] = 1, |
427 | | [0xE0] = 1, [0xE1] = 1, [0xE2] = 1, [0xE3] = 1, [0xE4] = 1, [0xE5] = 1, |
428 | | [0xE6] = 1, [0xE7] = 1, [0xE8] = 1, [0xE9] = 1, [0xEA] = 1, [0xEB] = 1, |
429 | | [0xEC] = 1, [0xED] = 1, [0xEE] = 1, [0xEF] = 1, [0xF0] = 1, [0xF1] = 1, |
430 | | [0xF2] = 1, [0xF3] = 1, [0xF4] = 1, [0xF5] = 1, [0xF6] = 1, [0xF7] = 1, |
431 | | [0xF8] = 1, [0xF9] = 1, [0xFA] = 1, [0xFB] = 1, [0xFC] = 1, [0xFD] = 1, |
432 | | [0xFE] = 1, [0xFF] = 1, |
433 | | }; |
434 | | |
435 | 10.8k | int nghttp2_check_header_value(const uint8_t *value, size_t len) { |
436 | 10.8k | const uint8_t *last; |
437 | 132k | for (last = value + len; value != last; ++value) { |
438 | 122k | if (!VALID_HD_VALUE_CHARS[*value]) { |
439 | 338 | return 0; |
440 | 338 | } |
441 | 122k | } |
442 | 10.4k | return 1; |
443 | 10.8k | } |
444 | | |
445 | 25.0k | int nghttp2_check_header_value_rfc9113(const uint8_t *value, size_t len) { |
446 | 25.0k | if (len == 0) { |
447 | 13.2k | return 1; |
448 | 13.2k | } |
449 | | |
450 | 11.7k | if (*value == ' ' || *value == '\t' || *(value + len - 1) == ' ' || |
451 | 11.0k | *(value + len - 1) == '\t') { |
452 | 969 | return 0; |
453 | 969 | } |
454 | | |
455 | 10.8k | return nghttp2_check_header_value(value, len); |
456 | 11.7k | } |
457 | | |
458 | | static const uint8_t VALID_METHOD_CHARS[256] = { |
459 | | ['!'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['*'] = 1, |
460 | | ['+'] = 1, ['-'] = 1, ['.'] = 1, ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, |
461 | | ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1, ['A'] = 1, |
462 | | ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1, ['H'] = 1, |
463 | | ['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1, |
464 | | ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, |
465 | | ['W'] = 1, ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['^'] = 1, ['_'] = 1, ['`'] = 1, |
466 | | ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, |
467 | | ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, |
468 | | ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1, |
469 | | ['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['|'] = 1, ['~'] = 1, |
470 | | }; |
471 | | |
472 | 3.36k | int nghttp2_check_method(const uint8_t *value, size_t len) { |
473 | 3.36k | const uint8_t *last; |
474 | 3.36k | if (len == 0) { |
475 | 86 | return 0; |
476 | 86 | } |
477 | 16.9k | for (last = value + len; value != last; ++value) { |
478 | 13.7k | if (!VALID_METHOD_CHARS[*value]) { |
479 | 43 | return 0; |
480 | 43 | } |
481 | 13.7k | } |
482 | 3.23k | return 1; |
483 | 3.28k | } |
484 | | |
485 | | static const uint8_t VALID_PATH_CHARS[256] = { |
486 | | ['!'] = 1, ['"'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, |
487 | | ['\''] = 1, ['('] = 1, [')'] = 1, ['*'] = 1, ['+'] = 1, [','] = 1, |
488 | | ['-'] = 1, ['.'] = 1, ['/'] = 1, ['0'] = 1, ['1'] = 1, ['2'] = 1, |
489 | | ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, |
490 | | ['9'] = 1, [':'] = 1, [';'] = 1, ['<'] = 1, ['='] = 1, ['>'] = 1, |
491 | | ['?'] = 1, ['@'] = 1, ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, |
492 | | ['E'] = 1, ['F'] = 1, ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1, |
493 | | ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1, |
494 | | ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, |
495 | | ['W'] = 1, ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 1, ['\\'] = 1, |
496 | | [']'] = 1, ['^'] = 1, ['_'] = 1, ['`'] = 1, ['a'] = 1, ['b'] = 1, |
497 | | ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, ['h'] = 1, |
498 | | ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, |
499 | | ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, |
500 | | ['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, |
501 | | ['{'] = 1, ['|'] = 1, ['}'] = 1, ['~'] = 1, [0x80] = 1, [0x81] = 1, |
502 | | [0x82] = 1, [0x83] = 1, [0x84] = 1, [0x85] = 1, [0x86] = 1, [0x87] = 1, |
503 | | [0x88] = 1, [0x89] = 1, [0x8A] = 1, [0x8B] = 1, [0x8C] = 1, [0x8D] = 1, |
504 | | [0x8E] = 1, [0x8F] = 1, [0x90] = 1, [0x91] = 1, [0x92] = 1, [0x93] = 1, |
505 | | [0x94] = 1, [0x95] = 1, [0x96] = 1, [0x97] = 1, [0x98] = 1, [0x99] = 1, |
506 | | [0x9A] = 1, [0x9B] = 1, [0x9C] = 1, [0x9D] = 1, [0x9E] = 1, [0x9F] = 1, |
507 | | [0xA0] = 1, [0xA1] = 1, [0xA2] = 1, [0xA3] = 1, [0xA4] = 1, [0xA5] = 1, |
508 | | [0xA6] = 1, [0xA7] = 1, [0xA8] = 1, [0xA9] = 1, [0xAA] = 1, [0xAB] = 1, |
509 | | [0xAC] = 1, [0xAD] = 1, [0xAE] = 1, [0xAF] = 1, [0xB0] = 1, [0xB1] = 1, |
510 | | [0xB2] = 1, [0xB3] = 1, [0xB4] = 1, [0xB5] = 1, [0xB6] = 1, [0xB7] = 1, |
511 | | [0xB8] = 1, [0xB9] = 1, [0xBA] = 1, [0xBB] = 1, [0xBC] = 1, [0xBD] = 1, |
512 | | [0xBE] = 1, [0xBF] = 1, [0xC0] = 1, [0xC1] = 1, [0xC2] = 1, [0xC3] = 1, |
513 | | [0xC4] = 1, [0xC5] = 1, [0xC6] = 1, [0xC7] = 1, [0xC8] = 1, [0xC9] = 1, |
514 | | [0xCA] = 1, [0xCB] = 1, [0xCC] = 1, [0xCD] = 1, [0xCE] = 1, [0xCF] = 1, |
515 | | [0xD0] = 1, [0xD1] = 1, [0xD2] = 1, [0xD3] = 1, [0xD4] = 1, [0xD5] = 1, |
516 | | [0xD6] = 1, [0xD7] = 1, [0xD8] = 1, [0xD9] = 1, [0xDA] = 1, [0xDB] = 1, |
517 | | [0xDC] = 1, [0xDD] = 1, [0xDE] = 1, [0xDF] = 1, [0xE0] = 1, [0xE1] = 1, |
518 | | [0xE2] = 1, [0xE3] = 1, [0xE4] = 1, [0xE5] = 1, [0xE6] = 1, [0xE7] = 1, |
519 | | [0xE8] = 1, [0xE9] = 1, [0xEA] = 1, [0xEB] = 1, [0xEC] = 1, [0xED] = 1, |
520 | | [0xEE] = 1, [0xEF] = 1, [0xF0] = 1, [0xF1] = 1, [0xF2] = 1, [0xF3] = 1, |
521 | | [0xF4] = 1, [0xF5] = 1, [0xF6] = 1, [0xF7] = 1, [0xF8] = 1, [0xF9] = 1, |
522 | | [0xFA] = 1, [0xFB] = 1, [0xFC] = 1, [0xFD] = 1, [0xFE] = 1, [0xFF] = 1, |
523 | | }; |
524 | | |
525 | 3.10k | int nghttp2_check_path(const uint8_t *value, size_t len) { |
526 | 3.10k | const uint8_t *last; |
527 | 13.6k | for (last = value + len; value != last; ++value) { |
528 | 10.5k | if (!VALID_PATH_CHARS[*value]) { |
529 | 38 | return 0; |
530 | 38 | } |
531 | 10.5k | } |
532 | 3.07k | return 1; |
533 | 3.10k | } |
534 | | |
535 | | static const uint8_t VALID_AUTHORITY_CHARS[256] = { |
536 | | ['!'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['('] = 1, [')'] = 1, |
537 | | ['*'] = 1, ['+'] = 1, [','] = 1, ['-'] = 1, ['.'] = 1, ['0'] = 1, ['1'] = 1, |
538 | | ['2'] = 1, ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, |
539 | | ['9'] = 1, [':'] = 1, [';'] = 1, ['='] = 1, ['@'] = 1, ['A'] = 1, ['B'] = 1, |
540 | | ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1, ['H'] = 1, ['I'] = 1, |
541 | | ['J'] = 1, ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1, |
542 | | ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1, |
543 | | ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 1, [']'] = 1, ['_'] = 1, ['a'] = 1, |
544 | | ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, ['h'] = 1, |
545 | | ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1, |
546 | | ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1, ['v'] = 1, |
547 | | ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['~'] = 1, |
548 | | }; |
549 | | |
550 | 0 | int nghttp2_check_authority(const uint8_t *value, size_t len) { |
551 | 0 | const uint8_t *last; |
552 | 0 | for (last = value + len; value != last; ++value) { |
553 | 0 | if (!VALID_AUTHORITY_CHARS[*value]) { |
554 | 0 | return 0; |
555 | 0 | } |
556 | 0 | } |
557 | 0 | return 1; |
558 | 0 | } |
559 | | |
560 | 91.2k | uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len) { |
561 | 91.2k | if (len == 0) { |
562 | 38.2k | return dest; |
563 | 38.2k | } |
564 | | |
565 | 52.9k | memcpy(dest, src, len); |
566 | | |
567 | 52.9k | return dest + len; |
568 | 91.2k | } |
569 | | |
570 | 0 | const char *nghttp2_http2_strerror(uint32_t error_code) { |
571 | 0 | switch (error_code) { |
572 | 0 | case NGHTTP2_NO_ERROR: |
573 | 0 | return "NO_ERROR"; |
574 | 0 | case NGHTTP2_PROTOCOL_ERROR: |
575 | 0 | return "PROTOCOL_ERROR"; |
576 | 0 | case NGHTTP2_INTERNAL_ERROR: |
577 | 0 | return "INTERNAL_ERROR"; |
578 | 0 | case NGHTTP2_FLOW_CONTROL_ERROR: |
579 | 0 | return "FLOW_CONTROL_ERROR"; |
580 | 0 | case NGHTTP2_SETTINGS_TIMEOUT: |
581 | 0 | return "SETTINGS_TIMEOUT"; |
582 | 0 | case NGHTTP2_STREAM_CLOSED: |
583 | 0 | return "STREAM_CLOSED"; |
584 | 0 | case NGHTTP2_FRAME_SIZE_ERROR: |
585 | 0 | return "FRAME_SIZE_ERROR"; |
586 | 0 | case NGHTTP2_REFUSED_STREAM: |
587 | 0 | return "REFUSED_STREAM"; |
588 | 0 | case NGHTTP2_CANCEL: |
589 | 0 | return "CANCEL"; |
590 | 0 | case NGHTTP2_COMPRESSION_ERROR: |
591 | 0 | return "COMPRESSION_ERROR"; |
592 | 0 | case NGHTTP2_CONNECT_ERROR: |
593 | 0 | return "CONNECT_ERROR"; |
594 | 0 | case NGHTTP2_ENHANCE_YOUR_CALM: |
595 | 0 | return "ENHANCE_YOUR_CALM"; |
596 | 0 | case NGHTTP2_INADEQUATE_SECURITY: |
597 | 0 | return "INADEQUATE_SECURITY"; |
598 | 0 | case NGHTTP2_HTTP_1_1_REQUIRED: |
599 | 0 | return "HTTP_1_1_REQUIRED"; |
600 | 0 | default: |
601 | 0 | return "unknown"; |
602 | 0 | } |
603 | 0 | } |