valgrind: stop openssl still reachable complaints
[platform/upstream/libwebsockets.git] / lib / hpack.c
1 /*
2  * lib/hpack.c
3  *
4  * Copyright (C) 2014 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  */
21
22 #include "private-libwebsockets.h"
23
24 /*
25  * Official static header table for HPACK
26  *        +-------+-----------------------------+---------------+
27           | 1     | :authority                  |               |
28           | 2     | :method                     | GET           |
29           | 3     | :method                     | POST          |
30           | 4     | :path                       | /             |
31           | 5     | :path                       | /index.html   |
32           | 6     | :scheme                     | http          |
33           | 7     | :scheme                     | https         |
34           | 8     | :status                     | 200           |
35           | 9     | :status                     | 204           |
36           | 10    | :status                     | 206           |
37           | 11    | :status                     | 304           |
38           | 12    | :status                     | 400           |
39           | 13    | :status                     | 404           |
40           | 14    | :status                     | 500           |
41           | 15    | accept-charset              |               |
42           | 16    | accept-encoding             | gzip, deflate |
43           | 17    | accept-language             |               |
44           | 18    | accept-ranges               |               |
45           | 19    | accept                      |               |
46           | 20    | access-control-allow-origin |               |
47           | 21    | age                         |               |
48           | 22    | allow                       |               |
49           | 23    | authorization               |               |
50           | 24    | cache-control               |               |
51           | 25    | content-disposition         |               |
52           | 26    | content-encoding            |               |
53           | 27    | content-language            |               |
54           | 28    | content-length              |               |
55           | 29    | content-location            |               |
56           | 30    | content-range               |               |
57           | 31    | content-type                |               |
58           | 32    | cookie                      |               |
59           | 33    | date                        |               |
60           | 34    | etag                        |               |
61           | 35    | expect                      |               |
62           | 36    | expires                     |               |
63           | 37    | from                        |               |
64           | 38    | host                        |               |
65           | 39    | if-match                    |               |
66           | 40    | if-modified-since           |               |
67           | 41    | if-none-match               |               |
68           | 42    | if-range                    |               |
69           | 43    | if-unmodified-since         |               |
70           | 44    | last-modified               |               |
71           | 45    | link                        |               |
72           | 46    | location                    |               |
73           | 47    | max-forwards                |               |
74           | 48    | proxy-authenticate          |               |
75           | 49    | proxy-authorization         |               |
76           | 50    | range                       |               |
77           | 51    | referer                     |               |
78           | 52    | refresh                     |               |
79           | 53    | retry-after                 |               |
80           | 54    | server                      |               |
81           | 55    | set-cookie                  |               |
82           | 56    | strict-transport-security   |               |
83           | 57    | transfer-encoding           |               |
84           | 58    | user-agent                  |               |
85           | 59    | vary                        |               |
86           | 60    | via                         |               |
87           | 61    | www-authenticate            |               |
88           +-------+-----------------------------+---------------+
89 */
90
91 static const unsigned char static_token[] = {
92         0,
93         WSI_TOKEN_HTTP_COLON_AUTHORITY,
94         WSI_TOKEN_HTTP_COLON_METHOD,
95         WSI_TOKEN_HTTP_COLON_METHOD,
96         WSI_TOKEN_HTTP_COLON_PATH,
97         WSI_TOKEN_HTTP_COLON_PATH,
98         WSI_TOKEN_HTTP_COLON_SCHEME,
99         WSI_TOKEN_HTTP_COLON_SCHEME,
100         WSI_TOKEN_HTTP_COLON_STATUS,
101         WSI_TOKEN_HTTP_COLON_STATUS,
102         WSI_TOKEN_HTTP_COLON_STATUS,
103         WSI_TOKEN_HTTP_COLON_STATUS,
104         WSI_TOKEN_HTTP_COLON_STATUS,
105         WSI_TOKEN_HTTP_COLON_STATUS,
106         WSI_TOKEN_HTTP_COLON_STATUS,
107         WSI_TOKEN_HTTP_ACCEPT_CHARSET,
108         WSI_TOKEN_HTTP_ACCEPT_ENCODING,
109         WSI_TOKEN_HTTP_ACCEPT_LANGUAGE,
110         WSI_TOKEN_HTTP_ACCEPT_RANGES,
111         WSI_TOKEN_HTTP_ACCEPT,
112         WSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN,
113         WSI_TOKEN_HTTP_AGE,
114         WSI_TOKEN_HTTP_ALLOW,
115         WSI_TOKEN_HTTP_AUTHORIZATION,
116         WSI_TOKEN_HTTP_CACHE_CONTROL,
117         WSI_TOKEN_HTTP_CONTENT_DISPOSITION,
118         WSI_TOKEN_HTTP_CONTENT_ENCODING,
119         WSI_TOKEN_HTTP_CONTENT_LANGUAGE,
120         WSI_TOKEN_HTTP_CONTENT_LENGTH,
121         WSI_TOKEN_HTTP_CONTENT_LOCATION,
122         WSI_TOKEN_HTTP_CONTENT_RANGE,
123         WSI_TOKEN_HTTP_CONTENT_TYPE,
124         WSI_TOKEN_HTTP_COOKIE,
125         WSI_TOKEN_HTTP_DATE,
126         WSI_TOKEN_HTTP_ETAG,
127         WSI_TOKEN_HTTP_EXPECT,
128         WSI_TOKEN_HTTP_EXPIRES,
129         WSI_TOKEN_HTTP_FROM,
130         WSI_TOKEN_HOST,
131         WSI_TOKEN_HTTP_IF_MATCH,
132         WSI_TOKEN_HTTP_IF_MODIFIED_SINCE,
133         WSI_TOKEN_HTTP_IF_NONE_MATCH,
134         WSI_TOKEN_HTTP_IF_RANGE,
135         WSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE,
136         WSI_TOKEN_HTTP_LAST_MODIFIED,
137         WSI_TOKEN_HTTP_LINK,
138         WSI_TOKEN_HTTP_LOCATION,
139         WSI_TOKEN_HTTP_MAX_FORWARDS,
140         WSI_TOKEN_HTTP_PROXY_AUTHENTICATE,
141         WSI_TOKEN_HTTP_PROXY_AUTHORIZATION,
142         WSI_TOKEN_HTTP_RANGE,
143         WSI_TOKEN_HTTP_REFERER,
144         WSI_TOKEN_HTTP_REFRESH,
145         WSI_TOKEN_HTTP_RETRY_AFTER,
146         WSI_TOKEN_HTTP_SERVER,
147         WSI_TOKEN_HTTP_SET_COOKIE,
148         WSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY,
149         WSI_TOKEN_HTTP_TRANSFER_ENCODING,
150         WSI_TOKEN_HTTP_USER_AGENT,
151         WSI_TOKEN_HTTP_VARY,
152         WSI_TOKEN_HTTP_VIA,
153         WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
154 };
155
156 /* some of the entries imply values as well as header names */
157
158 static const char * const http2_canned[] = {
159         "",
160         "",
161         "GET",
162         "POST",
163         "/",
164         "/index.html",
165         "http",
166         "https",
167         "200",
168         "204",
169         "206",
170         "304",
171         "400",
172         "404",
173         "500",
174         "",
175         "gzip, deflate"
176 };
177
178 /* see minihuf.c */
179
180 #include "huftable.h"
181
182 static int huftable_decode(int pos, char c)
183 {
184         int q = pos + !!c;
185
186         if (lextable_terms[q >> 3] & (1 << (q & 7))) /* terminal */
187                 return lextable[q] | 0x8000;
188
189         return pos + (lextable[q] << 1);
190 }
191
192 static int lws_hpack_update_table_size(struct lws *wsi, int idx)
193 {
194         lwsl_info("hpack set table size %d\n", idx);
195         return 0;
196 }
197
198 static int lws_frag_start(struct lws *wsi, int hdr_token_idx)
199 {
200         struct allocated_headers * ah = wsi->u.http2.http.ah;
201
202         if (!hdr_token_idx) {
203                 lwsl_err("%s: zero hdr_token_idx\n", __func__);
204                 return 1;
205         }
206
207         if (ah->nfrag >= ARRAY_SIZE(ah->frag_index)) {
208                 lwsl_err("%s: frag index %d too big\n", __func__, ah->nfrag);
209                 return 1;
210         }
211
212         ah->frags[ah->nfrag].offset = ah->pos;
213         ah->frags[ah->nfrag].len = 0;
214         ah->frags[ah->nfrag].nfrag = 0;
215
216         ah->frag_index[hdr_token_idx] = ah->nfrag;
217
218         return 0;
219 }
220
221 static int lws_frag_append(struct lws *wsi, unsigned char c)
222 {
223         struct allocated_headers * ah = wsi->u.http2.http.ah;
224
225         ah->data[ah->pos++] = c;
226         ah->frags[ah->nfrag].len++;
227
228         return ah->pos >= wsi->context->max_http_header_data;
229 }
230
231 static int lws_frag_end(struct lws *wsi)
232 {
233         if (lws_frag_append(wsi, 0))
234                 return 1;
235
236         wsi->u.http2.http.ah->nfrag++;
237         return 0;
238 }
239
240 static void lws_dump_header(struct lws *wsi, int hdr)
241 {
242         char s[200];
243         int len = lws_hdr_copy(wsi, s, sizeof(s) - 1, hdr);
244         s[len] = '\0';
245         lwsl_info("  hdr tok %d (%s) = '%s'\n", hdr, lws_token_to_string(hdr), s);
246 }
247
248 static int
249 lws_token_from_index(struct lws *wsi, int index, char **arg, int *len)
250 {
251         struct hpack_dynamic_table *dyn;
252
253         /* dynamic table only belongs to network wsi */
254
255         wsi = lws_http2_get_network_wsi(wsi);
256
257         dyn = wsi->u.http2.hpack_dyn_table;
258
259         if (index < ARRAY_SIZE(static_token))
260                 return static_token[index];
261
262         if (!dyn)
263                 return 0;
264
265         index -= ARRAY_SIZE(static_token);
266         if (index >= dyn->num_entries)
267                 return 0;
268
269         if (arg && len) {
270                 *arg = dyn->args + dyn->entries[index].arg_offset;
271                 *len = dyn->entries[index].arg_len;
272         }
273
274         return dyn->entries[index].token;
275 }
276
277 static int
278 lws_hpack_add_dynamic_header(struct lws *wsi, int token, char *arg, int len)
279 {
280         struct hpack_dynamic_table *dyn;
281         int ret = 1;
282
283         wsi = lws_http2_get_network_wsi(wsi);
284         dyn = wsi->u.http2.hpack_dyn_table;
285
286         if (!dyn) {
287                 dyn = lws_zalloc(sizeof(*dyn));
288                 if (!dyn)
289                         return 1;
290                 wsi->u.http2.hpack_dyn_table = dyn;
291
292                 dyn->args = lws_malloc(1024);
293                 if (!dyn->args)
294                         goto bail1;
295                 dyn->args_length = 1024;
296                 dyn->entries = lws_malloc(sizeof(dyn->entries[0]) * 20);
297                 if (!dyn->entries)
298                         goto bail2;
299                 dyn->num_entries = 20;
300         }
301
302         if (dyn->next == dyn->num_entries)
303                 return 1;
304
305         if (dyn->args_length - dyn->pos < len)
306                 return 1;
307
308         dyn->entries[dyn->next].token = token;
309         dyn->entries[dyn->next].arg_offset = dyn->pos;
310         if (len)
311                 memcpy(dyn->args + dyn->pos, arg, len);
312         dyn->entries[dyn->next].arg_len = len;
313
314         lwsl_info("%s: added dynamic hdr %d, token %d (%s), len %d\n",
315                   __func__, dyn->next, token, lws_token_to_string(token), len);
316
317         dyn->pos += len;
318         dyn->next++;
319
320         return 0;
321
322 bail2:
323         lws_free(dyn->args);
324 bail1:
325         lws_free(dyn);
326         wsi->u.http2.hpack_dyn_table = NULL;
327
328         return ret;
329 }
330
331 static int lws_write_indexed_hdr(struct lws *wsi, int idx)
332 {
333         const char *p;
334         int tok = lws_token_from_index(wsi, idx, NULL, 0);
335
336         lwsl_info("writing indexed hdr %d (tok %d '%s')\n", idx, tok,
337                   lws_token_to_string(tok));
338
339         if (lws_frag_start(wsi, tok))
340                 return 1;
341
342         if (idx < ARRAY_SIZE(http2_canned)) {
343                 p = http2_canned[idx];
344                 while (*p)
345                         if (lws_frag_append(wsi, *p++))
346                                 return 1;
347         }
348         if (lws_frag_end(wsi))
349                 return 1;
350
351         lws_dump_header(wsi, tok);
352
353         return 0;
354 }
355
356 int lws_hpack_interpret(struct lws *wsi, unsigned char c)
357 {
358         unsigned int prev;
359         unsigned char c1;
360         int n;
361
362         lwsl_debug("   state %d\n", wsi->u.http2.hpack);
363
364         switch (wsi->u.http2.hpack) {
365         case HPKS_OPT_PADDING:
366                 wsi->u.http2.padding = c;
367                 lwsl_info("padding %d\n", c);
368                 if (wsi->u.http2.flags & LWS_HTTP2_FLAG_PRIORITY) {
369                         wsi->u.http2.hpack = HKPS_OPT_E_DEPENDENCY;
370                         wsi->u.http2.hpack_m = 4;
371                 } else
372                         wsi->u.http2.hpack = HPKS_TYPE;
373                 break;
374         case HKPS_OPT_E_DEPENDENCY:
375                 wsi->u.http2.hpack_e_dep <<= 8;
376                 wsi->u.http2.hpack_e_dep |= c;
377                 if (! --wsi->u.http2.hpack_m) {
378                         lwsl_info("hpack_e_dep = 0x%x\n", wsi->u.http2.hpack_e_dep);
379                         wsi->u.http2.hpack = HKPS_OPT_WEIGHT;
380                 }
381                 break;
382         case HKPS_OPT_WEIGHT:
383                 /* weight */
384                 wsi->u.http2.hpack = HPKS_TYPE;
385                 break;
386
387         case HPKS_TYPE:
388
389                 if (wsi->u.http2.count > (wsi->u.http2.length - wsi->u.http2.padding)) {
390                         lwsl_info("padding eat\n");
391                         break;
392                 }
393
394                 if (c & 0x80) { /* indexed header field only */
395                         /* just a possibly-extended integer */
396                         wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_7;
397                         lwsl_debug("HKPS_TYPE setting header_index %d\n", c & 0x7f);
398                         wsi->u.http2.header_index = c & 0x7f;
399                         if ((c & 0x7f) == 0x7f) {
400                                 wsi->u.http2.hpack_len = c & 0x7f;
401                                 wsi->u.http2.hpack_m = 0;
402                                 wsi->u.http2.hpack = HPKS_IDX_EXT;
403                                 break;
404                         }
405                         lwsl_debug("HKPS_TYPE: %d\n", c & 0x7f);
406                         if (lws_write_indexed_hdr(wsi, c & 0x7f))
407                                 return 1;
408                         /* stay at same state */
409                         break;
410                 }
411                 if (c & 0x40) { /* literal header incr idx */
412                         /*
413                          * [possibly-extended hdr idx (6) | new literal hdr name]
414                          * H + possibly-extended value length
415                          * literal value
416                          */
417                         lwsl_debug("HKPS_TYPE 2 setting header_index %d\n", 0);
418                         wsi->u.http2.header_index = 0;
419                         if (c == 0x40) { /* literal name */
420                                 wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE_INCR;
421                                 wsi->u.http2.value = 0;
422                                 wsi->u.http2.hpack = HPKS_HLEN;
423                                 break;
424                         }
425                         /* indexed name */
426                         wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_6_VALUE_INCR;
427                         if ((c & 0x3f) == 0x3f) {
428                                 wsi->u.http2.hpack_len = c & 0x3f;
429                                 wsi->u.http2.hpack_m = 0;
430                                 wsi->u.http2.hpack = HPKS_IDX_EXT;
431                                 break;
432                         }
433                         lwsl_debug("HKPS_TYPE 3 setting header_index %d\n", c & 0x3f);
434                         wsi->u.http2.header_index = c & 0x3f;
435                         wsi->u.http2.value = 1;
436                         wsi->u.http2.hpack = HPKS_HLEN;
437                         break;
438                 }
439                 switch(c & 0xf0) {
440                 case 0x10: /* literal header never index */
441                 case 0: /* literal header without indexing */
442                         /*
443                          * follows 0x40 except 4-bit hdr idx
444                          * and don't add to index
445                          */
446                         if (c == 0) { /* literal name */
447                                 wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE;
448                                 wsi->u.http2.hpack = HPKS_HLEN;
449                                 wsi->u.http2.value = 0;
450                                 break;
451                         }
452                         //lwsl_debug("indexed\n");
453                         /* indexed name */
454                         wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_4_VALUE;
455                         wsi->u.http2.header_index = 0;
456                         if ((c & 0xf) == 0xf) {
457                                 wsi->u.http2.hpack_len = c & 0xf;
458                                 wsi->u.http2.hpack_m = 0;
459                                 wsi->u.http2.hpack = HPKS_IDX_EXT;
460                                 break;
461                         }
462                         //lwsl_err("HKPS_TYPE 5 setting header_index %d\n", c & 0xf);
463                         wsi->u.http2.header_index = c & 0xf;
464                         wsi->u.http2.value = 1;
465                         wsi->u.http2.hpack = HPKS_HLEN;
466                         break;
467
468                 case 0x20:
469                 case 0x30: /* header table size update */
470                         /* possibly-extended size value (5) */
471                         wsi->u.http2.hpack_type = HPKT_SIZE_5;
472                         if ((c & 0x1f) == 0x1f) {
473                                 wsi->u.http2.hpack_len = c & 0x1f;
474                                 wsi->u.http2.hpack_m = 0;
475                                 wsi->u.http2.hpack = HPKS_IDX_EXT;
476                                 break;
477                         }
478                         lws_hpack_update_table_size(wsi, c & 0x1f);
479                         /* stay at HPKS_TYPE state */
480                         break;
481                 }
482                 break;
483
484         case HPKS_IDX_EXT:
485                 wsi->u.http2.hpack_len += (c & 0x7f) << wsi->u.http2.hpack_m;
486                 wsi->u.http2.hpack_m += 7;
487                 if (!(c & 0x80)) {
488                         switch (wsi->u.http2.hpack_type) {
489                         case HPKT_INDEXED_HDR_7:
490                                 //lwsl_err("HKPS_IDX_EXT hdr idx %d\n", wsi->u.http2.hpack_len);
491                                 if (lws_write_indexed_hdr(wsi, wsi->u.http2.hpack_len))
492                                         return 1;
493                                 wsi->u.http2.hpack = HPKS_TYPE;
494                                 break;
495                         default:
496                                 // lwsl_err("HKPS_IDX_EXT setting header_index %d\n",
497                                 //              wsi->u.http2.hpack_len);
498                                 wsi->u.http2.header_index = wsi->u.http2.hpack_len;
499                                 wsi->u.http2.value = 1;
500                                 wsi->u.http2.hpack = HPKS_HLEN;
501                                 break;
502                         }
503                 }
504                 break;
505
506         case HPKS_HLEN: /* [ H | 7+ ] */
507                 wsi->u.http2.huff = !!(c & 0x80);
508                 wsi->u.http2.hpack_pos = 0;
509                 wsi->u.http2.hpack_len = c & 0x7f;
510                 if (wsi->u.http2.hpack_len < 0x7f) {
511 pre_data:
512                         if (wsi->u.http2.value) {
513                                 if (wsi->u.http2.header_index)
514                                 if (lws_frag_start(wsi, lws_token_from_index(wsi,
515                                                    wsi->u.http2.header_index,
516                                                    NULL, NULL))) {
517                                 //      lwsl_notice("%s: hlen failed\n", __func__);
518                                         return 1;
519                                 }
520                         } else
521                                 wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
522                         wsi->u.http2.hpack = HPKS_DATA;
523                         break;
524                 }
525                 wsi->u.http2.hpack_m = 0;
526                 wsi->u.http2.hpack = HPKS_HLEN_EXT;
527                 break;
528
529         case HPKS_HLEN_EXT:
530                 wsi->u.http2.hpack_len += (c & 0x7f) <<
531                                         wsi->u.http2.hpack_m;
532                 wsi->u.http2.hpack_m += 7;
533                 if (!(c & 0x80))
534                         goto pre_data;
535
536                 break;
537
538         case HPKS_DATA:
539                 for (n = 0; n < 8; n++) {
540                         if (wsi->u.http2.huff) {
541                                 prev = wsi->u.http2.hpack_pos;
542                                 wsi->u.http2.hpack_pos = huftable_decode(
543                                                 wsi->u.http2.hpack_pos,
544                                                 (c >> 7) & 1);
545                                 c <<= 1;
546                                 if (wsi->u.http2.hpack_pos == 0xffff)
547                                         return 1;
548                                 if (!(wsi->u.http2.hpack_pos & 0x8000))
549                                         continue;
550                                 c1 = wsi->u.http2.hpack_pos & 0x7fff;
551                                 wsi->u.http2.hpack_pos = 0;
552
553                                 if (!c1 && prev == HUFTABLE_0x100_PREV)
554                                         ; /* EOT */
555                         } else {
556                                 n = 8;
557                                 c1 = c;
558                         }
559                         if (wsi->u.http2.value) { /* value */
560                                 if (wsi->u.http2.header_index)
561                                         if (lws_frag_append(wsi, c1))
562                                                 return 1;
563                         } else { /* name */
564                                 if (lws_parse(wsi, c1))
565                                         return 1;
566
567                         }
568                 }
569                 if (--wsi->u.http2.hpack_len == 0) {
570
571                         switch (wsi->u.http2.hpack_type) {
572                         case HPKT_LITERAL_HDR_VALUE_INCR:
573                         case HPKT_INDEXED_HDR_6_VALUE_INCR: // !!!
574                                 if (lws_hpack_add_dynamic_header(wsi,
575                                      lws_token_from_index(wsi,
576                                                  wsi->u.http2.header_index,
577                                                          NULL, NULL), NULL, 0))
578                                         return 1;
579                                 break;
580                         default:
581                                 break;
582                         }
583
584                         n = 8;
585                         if (wsi->u.http2.value) {
586                                 if (lws_frag_end(wsi))
587                                         return 1;
588                                 // lwsl_err("data\n");
589                                 lws_dump_header(wsi, lws_token_from_index(
590                                                 wsi, wsi->u.http2.header_index,
591                                                 NULL, NULL));
592                                 if (wsi->u.http2.count + wsi->u.http2.padding ==
593                                     wsi->u.http2.length)
594                                         wsi->u.http2.hpack = HKPS_OPT_DISCARD_PADDING;
595                                 else
596                                         wsi->u.http2.hpack = HPKS_TYPE;
597                         } else { /* name */
598                                 //if (wsi->u.hdr.parser_state < WSI_TOKEN_COUNT)
599
600                                 wsi->u.http2.value = 1;
601                                 wsi->u.http2.hpack = HPKS_HLEN;
602                         }
603                 }
604                 break;
605         case HKPS_OPT_DISCARD_PADDING:
606                 lwsl_info("eating padding %x\n", c);
607                 if (! --wsi->u.http2.padding)
608                         wsi->u.http2.hpack = HPKS_TYPE;
609                 break;
610         }
611
612         return 0;
613 }
614
615 static int lws_http2_num(int starting_bits, unsigned long num,
616                          unsigned char **p, unsigned char *end)
617 {
618         int mask = (1 << starting_bits) - 1;
619
620         if (num < mask) {
621                 *((*p)++) |= num;
622                 return *p >= end;
623         }
624
625         *((*p)++) |= mask;
626         if (*p >= end)
627                 return 1;
628
629         num -= mask;
630         while (num >= 128) {
631                 *((*p)++) = 0x80 | (num & 0x7f);
632                 if (*p >= end)
633                         return 1;
634                 num >>= 7;
635         }
636
637         return 0;
638 }
639
640 int lws_add_http2_header_by_name(struct lws *wsi,
641                                  const unsigned char *name,
642                                  const unsigned char *value, int length,
643                                  unsigned char **p, unsigned char *end)
644 {
645         int len;
646
647         lwsl_info("%s: %p  %s:%s\n", __func__, *p, name, value);
648
649         len = strlen((char *)name);
650         if (len)
651                 if (name[len - 1] == ':')
652                         len--;
653
654         if (end - *p < len + length + 8)
655                 return 1;
656
657         *((*p)++) = 0; /* not indexed, literal name */
658
659         **p = 0; /* non-HUF */
660         if (lws_http2_num(7, len, p, end))
661                 return 1;
662         memcpy(*p, name, len);
663         *p += len;
664
665         *(*p) = 0; /* non-HUF */
666         if (lws_http2_num(7, length, p, end))
667                 return 1;
668
669         memcpy(*p, value, length);
670         *p += length;
671
672         return 0;
673 }
674
675 int lws_add_http2_header_by_token(struct lws *wsi, enum lws_token_indexes token,
676                                   const unsigned char *value, int length,
677                                   unsigned char **p, unsigned char *end)
678 {
679         const unsigned char *name;
680
681         name = lws_token_to_string(token);
682         if (!name)
683                 return 1;
684
685         return lws_add_http2_header_by_name(wsi, name, value, length, p, end);
686 }
687
688 int lws_add_http2_header_status(struct lws *wsi,
689                                 unsigned int code, unsigned char **p,
690                                 unsigned char *end)
691 {
692         unsigned char status[10];
693         int n;
694
695         wsi->u.http2.send_END_STREAM = !!(code >= 400);
696
697         n = sprintf((char *)status, "%u", code);
698         if (lws_add_http2_header_by_token(wsi, WSI_TOKEN_HTTP_COLON_STATUS,
699                                           status, n, p, end))
700
701                 return 1;
702
703         return 0;
704 }