09c6e7b5e3baccd5dc0bc5abb50c8a68bb03699b
[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                 return 1;
204         
205         if (ah->next_frag_index >= ARRAY_SIZE(ah->frag_index))
206                 return 1;
207         
208         ah->frags[ah->next_frag_index].offset = ah->pos;
209         ah->frags[ah->next_frag_index].len = 0;
210         ah->frags[ah->next_frag_index].next_frag_index = 0;
211
212         ah->frag_index[hdr_token_idx] = ah->next_frag_index;
213         
214         return 0;
215 }
216
217 static int lws_frag_append(struct lws *wsi, unsigned char c)
218 {
219         struct allocated_headers * ah = wsi->u.http2.http.ah;
220
221         ah->data[ah->pos++] = c;
222         ah->frags[ah->next_frag_index].len++;
223         
224         return ah->pos >= sizeof(ah->data);
225 }
226
227 static int lws_frag_end(struct lws *wsi)
228 {
229         if (lws_frag_append(wsi, 0))
230                 return 1;
231
232         wsi->u.http2.http.ah->next_frag_index++;
233         return 0;
234 }
235
236 static void lws_dump_header(struct lws *wsi, int hdr)
237 {
238         char s[200];
239         int len = lws_hdr_copy(wsi, s, sizeof(s) - 1, hdr);
240         s[len] = '\0';
241         lwsl_info("  hdr tok %d (%s) = '%s'\n", hdr, lws_token_to_string(hdr), s);
242 }
243
244 static int lws_token_from_index(struct lws *wsi, int index, char **arg, int *len)
245 {
246         struct hpack_dynamic_table *dyn;
247         
248         /* dynamic table only belongs to network wsi */
249         
250         wsi = lws_http2_get_network_wsi(wsi);
251         
252         dyn = wsi->u.http2.hpack_dyn_table;
253
254         if (index < ARRAY_SIZE(static_token))
255                 return static_token[index];
256
257         if (!dyn)
258                 return 0;
259         
260         index -= ARRAY_SIZE(static_token);
261         if (index >= dyn->num_entries)
262                 return 0;
263         
264         if (arg && len) {
265                 *arg = dyn->args + dyn->entries[index].arg_offset;
266                 *len = dyn->entries[index].arg_len;
267         }
268         
269         return dyn->entries[index].token;
270 }
271
272 static int lws_hpack_add_dynamic_header(struct lws *wsi, int token, char *arg, int len)
273 {
274         struct hpack_dynamic_table *dyn;
275         int ret = 1;
276         
277         wsi = lws_http2_get_network_wsi(wsi);
278         dyn = wsi->u.http2.hpack_dyn_table;
279
280         if (!dyn) {
281                 dyn = lws_zalloc(sizeof(*dyn));
282                 if (!dyn)
283                         return 1;
284                 wsi->u.http2.hpack_dyn_table = dyn;
285                 
286                 dyn->args = lws_malloc(1024);
287                 if (!dyn->args)
288                         goto bail1;
289                 dyn->args_length = 1024;
290                 dyn->entries = lws_malloc(sizeof(dyn->entries[0]) * 20);
291                 if (!dyn->entries)
292                         goto bail2;
293                 dyn->num_entries = 20;
294         }
295         
296         if (dyn->next == dyn->num_entries)
297                 return 1;
298         
299         if (dyn->args_length - dyn->pos < len)
300                 return 1;
301         
302         dyn->entries[dyn->next].token = token;
303         dyn->entries[dyn->next].arg_offset = dyn->pos;
304         if (len)
305                 memcpy(dyn->args + dyn->pos, arg, len);
306         dyn->entries[dyn->next].arg_len = len;
307         
308         lwsl_info("%s: added dynamic hdr %d, token %d (%s), len %d\n", __func__, dyn->next, token, lws_token_to_string(token), len);
309         
310         dyn->pos += len;
311         dyn->next++;
312         
313         return 0;
314
315 bail2:
316         lws_free(dyn->args);
317 bail1:
318         lws_free(dyn);
319         wsi->u.http2.hpack_dyn_table = NULL;
320
321         return ret;
322 }
323
324 static int lws_write_indexed_hdr(struct lws *wsi, int idx)
325 {
326         const char *p;
327         int tok = lws_token_from_index(wsi, idx, NULL, 0);
328
329         lwsl_info("writing indexed hdr %d (tok %d '%s')\n", idx, tok, lws_token_to_string(tok));
330
331         if (lws_frag_start(wsi, tok))
332                 return 1;
333
334         if (idx < ARRAY_SIZE(http2_canned)) {
335                 p = http2_canned[idx];
336                 while (*p)
337                         if (lws_frag_append(wsi, *p++))
338                                 return 1;
339         }
340         if (lws_frag_end(wsi))
341                 return 1;
342         
343         lws_dump_header(wsi, tok);
344
345         return 0;
346 }
347
348 int lws_hpack_interpret(struct lws_context *context,
349                         struct lws *wsi, unsigned char c)
350 {
351         unsigned int prev;
352         unsigned char c1;
353         int n;
354
355         switch (wsi->u.http2.hpack) {
356         case HPKS_OPT_PADDING:
357                 wsi->u.http2.padding = c;
358                 lwsl_info("padding %d\n", c);
359                 if (wsi->u.http2.flags & LWS_HTTP2_FLAG_PRIORITY) {
360                         wsi->u.http2.hpack = HKPS_OPT_E_DEPENDENCY;
361                         wsi->u.http2.hpack_m = 4;
362                 } else
363                         wsi->u.http2.hpack = HPKS_TYPE;
364                 break;
365         case HKPS_OPT_E_DEPENDENCY:
366                 wsi->u.http2.hpack_e_dep <<= 8;
367                 wsi->u.http2.hpack_e_dep |= c;
368                 if (! --wsi->u.http2.hpack_m) {
369                         lwsl_info("hpack_e_dep = 0x%x\n", wsi->u.http2.hpack_e_dep);
370                         wsi->u.http2.hpack = HKPS_OPT_WEIGHT;
371                 }
372                 break;
373         case HKPS_OPT_WEIGHT:
374                 /* weight */
375                 wsi->u.http2.hpack = HPKS_TYPE;
376                 break;
377                         
378         case HPKS_TYPE:
379                 
380                 if (wsi->u.http2.count > (wsi->u.http2.length - wsi->u.http2.padding)) {
381                         lwsl_info("padding eat\n");
382                         break;
383                 }
384                 
385                 if (c & 0x80) { /* indexed header field only */
386                         /* just a possibly-extended integer */
387                         wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_7;
388                         wsi->u.http2.header_index = c & 0x7f;
389                         if ((c & 0x7f) == 0x7f) {
390                                 wsi->u.http2.hpack_len = c & 0x7f;
391                                 wsi->u.http2.hpack_m = 0;
392                                 wsi->u.http2.hpack = HPKS_IDX_EXT;
393                                 break;
394                         }
395                         if (lws_write_indexed_hdr(wsi, c & 0x7f))
396                                 return 1;
397                         /* stay at same state */
398                         break;
399                 }
400                 if (c & 0x40) { /* literal header incr idx */
401                         /*
402                          * [possibly-extended hdr idx (6) | new literal hdr name]
403                          * H + possibly-extended value length
404                          * literal value
405                          */
406                         wsi->u.http2.header_index = 0;
407                         if (c == 0x40) { /* literal name */
408                                 wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE_INCR;
409                                 wsi->u.http2.value = 0;
410                                 wsi->u.http2.hpack = HPKS_HLEN;
411                                 break;
412                         }
413                         /* indexed name */
414                         wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_6_VALUE_INCR;
415                         if ((c & 0x3f) == 0x3f) {
416                                 wsi->u.http2.hpack_len = c & 0x3f;
417                                 wsi->u.http2.hpack_m = 0;
418                                 wsi->u.http2.hpack = HPKS_IDX_EXT;
419                                 break;
420                         }
421                         wsi->u.http2.header_index = c & 0x3f;
422                         wsi->u.http2.value = 1;
423                         wsi->u.http2.hpack = HPKS_HLEN;
424                         break;
425                 }
426                 switch(c & 0xf0) {
427                 case 0x10: /* literal header never index */
428                 case 0: /* literal header without indexing */
429                         /* 
430                          * follows 0x40 except 4-bit hdr idx
431                          * and don't add to index
432                          */
433                         if (c == 0) { /* literal name */
434                                 wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE;
435                                 wsi->u.http2.hpack = HPKS_HLEN;
436                                 wsi->u.http2.value = 0;
437                                 break;
438                         }
439                         /* indexed name */
440                         wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_4_VALUE;
441                         wsi->u.http2.header_index = 0;
442                         if ((c & 0xf) == 0xf) {
443                                 wsi->u.http2.hpack_len = c & 0xf;
444                                 wsi->u.http2.hpack_m = 0;
445                                 wsi->u.http2.hpack = HPKS_IDX_EXT;
446                                 break;
447                         }
448                         wsi->u.http2.header_index = c & 0xf;
449                         wsi->u.http2.value = 1;
450                         wsi->u.http2.hpack = HPKS_HLEN;
451                         break;
452
453                 case 0x20:
454                 case 0x30: /* header table size update */
455                         /* possibly-extended size value (5) */
456                         wsi->u.http2.hpack_type = HPKT_SIZE_5;
457                         if ((c & 0x1f) == 0x1f) {
458                                 wsi->u.http2.hpack_len = c & 0x1f;
459                                 wsi->u.http2.hpack_m = 0;
460                                 wsi->u.http2.hpack = HPKS_IDX_EXT;
461                                 break;
462                         }
463                         lws_hpack_update_table_size(wsi, c & 0x1f);
464                         /* stay at HPKS_TYPE state */
465                         break;
466                 }
467                 break;
468                 
469         case HPKS_IDX_EXT:
470                 wsi->u.http2.hpack_len += (c & 0x7f) << wsi->u.http2.hpack_m;
471                 wsi->u.http2.hpack_m += 7;
472                 if (!(c & 0x80)) {
473                         switch (wsi->u.http2.hpack_type) {
474                         case HPKT_INDEXED_HDR_7:
475                                 if (lws_write_indexed_hdr(wsi, wsi->u.http2.hpack_len))
476                                         return 1;
477                                 wsi->u.http2.hpack = HPKS_TYPE;
478                                 break;
479                         default:
480                                 wsi->u.http2.header_index = wsi->u.http2.hpack_len;
481                                 wsi->u.http2.value = 1;
482                                 wsi->u.http2.hpack = HPKS_HLEN;
483                                 break;
484                         }
485                 }
486                 break;
487
488         case HPKS_HLEN: /* [ H | 7+ ] */
489                 wsi->u.http2.huff = !!(c & 0x80);
490                 wsi->u.http2.hpack_pos = 0;
491                 wsi->u.http2.hpack_len = c & 0x7f;
492                 if (wsi->u.http2.hpack_len < 0x7f) {
493 pre_data:
494                         if (wsi->u.http2.value) {
495                                 if (lws_frag_start(wsi,
496                                         lws_token_from_index(wsi,
497                                                 wsi->u.http2.header_index, NULL, NULL)))
498                                         return 1;
499                         } else
500                                 wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
501                         wsi->u.http2.hpack = HPKS_DATA;
502                         break;
503                 }
504                 wsi->u.http2.hpack_m = 0;
505                 wsi->u.http2.hpack = HPKS_HLEN_EXT;
506                 break;
507                 
508         case HPKS_HLEN_EXT:
509                 wsi->u.http2.hpack_len += (c & 0x7f) <<
510                                         wsi->u.http2.hpack_m;
511                 wsi->u.http2.hpack_m += 7;
512                 if (!(c & 0x80))
513                         goto pre_data;
514
515                 break;
516
517         case HPKS_DATA:
518                 for (n = 0; n < 8; n++) {
519                         if (wsi->u.http2.huff) {
520                                 prev = wsi->u.http2.hpack_pos;
521                                 wsi->u.http2.hpack_pos = 
522                                         huftable_decode(
523                                                 wsi->u.http2.hpack_pos,
524                                                         (c >> 7) & 1);
525                                 c <<= 1;
526                                 if (wsi->u.http2.hpack_pos == 0xffff)
527                                         return 1;
528                                 if (!(wsi->u.http2.hpack_pos & 0x8000))
529                                         continue;
530                                 c1 = wsi->u.http2.hpack_pos & 0x7fff;
531                                 wsi->u.http2.hpack_pos = 0;
532         
533                                 if (!c1 && prev == HUFTABLE_0x100_PREV)
534                                         ; /* EOT */
535                         } else {
536                                 n = 8;
537                                 c1 = c;
538                         }
539                         if (wsi->u.http2.value) { /* value */
540                                 if (lws_frag_append(wsi, c1))
541                                         return 1;
542                         } else { /* name */
543                                 if (lws_parse(context, wsi, c1))
544                                         return 1;
545                                 
546                         }
547                 }
548                 if (--wsi->u.http2.hpack_len == 0) {
549                         
550                         switch (wsi->u.http2.hpack_type) {
551                         case HPKT_LITERAL_HDR_VALUE_INCR:
552                         case HPKT_INDEXED_HDR_6_VALUE_INCR: // !!!
553                                 if (lws_hpack_add_dynamic_header(wsi, lws_token_from_index(wsi, wsi->u.http2.header_index, NULL, NULL), NULL, 0))
554                                         return 1;
555                                 break;
556                         default:
557                                 break;
558                         }
559                         
560                         n = 8;
561                         if (wsi->u.http2.value) {
562                                 if (lws_frag_end(wsi))
563                                         return 1;
564
565                                 lws_dump_header(wsi, lws_token_from_index(wsi, wsi->u.http2.header_index, NULL, NULL));
566                                 if (wsi->u.http2.count + wsi->u.http2.padding == wsi->u.http2.length)
567                                         wsi->u.http2.hpack = HKPS_OPT_DISCARD_PADDING;
568                                 else
569                                         wsi->u.http2.hpack = HPKS_TYPE;
570                         } else { /* name */
571                                 if (wsi->u.hdr.parser_state < WSI_TOKEN_COUNT)
572                                         
573                                 wsi->u.http2.value = 1;
574                                 wsi->u.http2.hpack = HPKS_HLEN;
575                         }
576                 }
577                 break;
578         case HKPS_OPT_DISCARD_PADDING:
579                 lwsl_info("eating padding %x\n", c);
580                 if (! --wsi->u.http2.padding)
581                         wsi->u.http2.hpack = HPKS_TYPE;
582                 break;
583         }
584         
585         return 0;
586 }
587
588 static int lws_http2_num(int starting_bits, unsigned long num,
589                          unsigned char **p, unsigned char *end)
590 {
591         int mask = (1 << starting_bits) - 1;
592
593         if (num < mask) {
594                 *((*p)++) |= num;
595                 return *p >= end;
596         }
597         
598         *((*p)++) |= mask;
599         if (*p >= end)
600                 return 1;
601         
602         num -= mask;
603         while (num >= 128) {
604                 *((*p)++) = 0x80 | (num & 0x7f);
605                 if (*p >= end)
606                         return 1;
607                 num >>= 7;
608         }
609         
610         return 0;
611 }
612
613 int lws_add_http2_header_by_name(struct lws_context *context,
614                                  struct lws *wsi,
615                                  const unsigned char *name,
616                                  const unsigned char *value,
617                                  int length,
618                                  unsigned char **p,
619                                  unsigned char *end)
620 {
621         int len;
622         
623         lwsl_info("%s: %p  %s:%s\n", __func__, *p, name, value);
624         
625         len = strlen((char *)name);
626         if (len)
627                 if (name[len - 1] == ':')
628                         len--;
629
630         if (end - *p < len + length + 8)
631                 return 1;
632
633         *((*p)++) = 0; /* not indexed, literal name */
634
635         **p = 0; /* non-HUF */
636         if (lws_http2_num(7, len, p, end))
637                 return 1;
638         memcpy(*p, name, len);
639         *p += len;
640
641         *(*p) = 0; /* non-HUF */
642         if (lws_http2_num(7, length, p, end))
643                 return 1;
644         
645         memcpy(*p, value, length);
646         *p += length;
647         
648         return 0;
649 }
650
651 int lws_add_http2_header_by_token(struct lws_context *context, struct lws *wsi,
652                             enum lws_token_indexes token,
653                             const unsigned char *value, int length,
654                             unsigned char **p, unsigned char *end)
655 {
656         const unsigned char *name;
657
658         name = lws_token_to_string(token);
659         if (!name)
660                 return 1;
661         
662         return lws_add_http2_header_by_name(context, wsi, name, value,
663                                             length, p, end);
664 }
665
666 int lws_add_http2_header_status(struct lws_context *context, struct lws *wsi,
667                                 unsigned int code, unsigned char **p,
668                                 unsigned char *end)
669 {
670         unsigned char status[10];
671         int n;
672         
673         wsi->u.http2.send_END_STREAM = !!(code >= 400);
674         
675         n = sprintf((char *)status, "%u", code);
676         if (lws_add_http2_header_by_token(context, wsi,
677                                           WSI_TOKEN_HTTP_COLON_STATUS, status,
678                                           n, p, end))
679                 return 1;
680
681         return 0;
682 }