1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2013 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_frame.h"
26 
27 #include <string.h>
28 #include <assert.h>
29 #include <stdio.h>
30 #include <errno.h>
31 
32 #include "nghttp2_helper.h"
33 #include "nghttp2_net.h"
34 #include "nghttp2_priority_spec.h"
35 #include "nghttp2_debug.h"
36 
nghttp2_frame_pack_frame_hd(uint8_t * buf,const nghttp2_frame_hd * hd)37 void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd)
38 {
39     nghttp2_put_uint32be(&buf[0], (uint32_t)(hd->length << 8));
40     buf[3] = hd->type;
41     buf[4] = hd->flags;
42     nghttp2_put_uint32be(&buf[5], (uint32_t)hd->stream_id);
43     /* ignore hd->reserved for now */
44 }
45 
nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd * hd,const uint8_t * buf)46 void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf)
47 {
48     hd->length = nghttp2_get_uint32(&buf[0]) >> 8;
49     hd->type = buf[3];
50     hd->flags = buf[4];
51     hd->stream_id = nghttp2_get_uint32(&buf[5]) & NGHTTP2_STREAM_ID_MASK;
52     hd->reserved = 0;
53 }
54 
nghttp2_frame_hd_init(nghttp2_frame_hd * hd,size_t length,uint8_t type,uint8_t flags,int32_t stream_id)55 void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type,
56                            uint8_t flags, int32_t stream_id)
57 {
58     hd->length = length;
59     hd->type = type;
60     hd->flags = flags;
61     hd->stream_id = stream_id;
62     hd->reserved = 0;
63 }
64 
nghttp2_frame_headers_init(nghttp2_headers * frame,uint8_t flags,int32_t stream_id,nghttp2_headers_category cat,const nghttp2_priority_spec * pri_spec,nghttp2_nv * nva,size_t nvlen)65 void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags,
66                                 int32_t stream_id, nghttp2_headers_category cat,
67                                 const nghttp2_priority_spec *pri_spec,
68                                 nghttp2_nv *nva, size_t nvlen)
69 {
70     nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_HEADERS, flags, stream_id);
71     frame->padlen = 0;
72     frame->nva = nva;
73     frame->nvlen = nvlen;
74     frame->cat = cat;
75 
76     if (pri_spec) {
77         frame->pri_spec = *pri_spec;
78     } else {
79         nghttp2_priority_spec_default_init(&frame->pri_spec);
80     }
81 }
82 
nghttp2_frame_headers_free(nghttp2_headers * frame,nghttp2_mem * mem)83 void nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem)
84 {
85     nghttp2_nv_array_del(frame->nva, mem);
86 }
87 
nghttp2_frame_priority_init(nghttp2_priority * frame,int32_t stream_id,const nghttp2_priority_spec * pri_spec)88 void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
89                                  const nghttp2_priority_spec *pri_spec)
90 {
91     nghttp2_frame_hd_init(&frame->hd, NGHTTP2_PRIORITY_SPECLEN,
92                           NGHTTP2_PRIORITY, NGHTTP2_FLAG_NONE, stream_id);
93     frame->pri_spec = *pri_spec;
94 }
95 
nghttp2_frame_priority_free(nghttp2_priority * frame)96 void nghttp2_frame_priority_free(nghttp2_priority *frame)
97 {
98     (void)frame;
99 }
100 
nghttp2_frame_rst_stream_init(nghttp2_rst_stream * frame,int32_t stream_id,uint32_t error_code)101 void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
102                                    uint32_t error_code)
103 {
104     nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE,
105                           stream_id);
106     frame->error_code = error_code;
107 }
108 
nghttp2_frame_rst_stream_free(nghttp2_rst_stream * frame)109 void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame)
110 {
111     (void)frame;
112 }
113 
nghttp2_frame_settings_init(nghttp2_settings * frame,uint8_t flags,nghttp2_settings_entry * iv,size_t niv)114 void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
115                                  nghttp2_settings_entry *iv, size_t niv)
116 {
117     nghttp2_frame_hd_init(&frame->hd, niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH,
118                           NGHTTP2_SETTINGS, flags, 0);
119     frame->niv = niv;
120     frame->iv = iv;
121 }
122 
nghttp2_frame_settings_free(nghttp2_settings * frame,nghttp2_mem * mem)123 void nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem)
124 {
125     nghttp2_mem_free(mem, frame->iv);
126 }
127 
nghttp2_frame_push_promise_init(nghttp2_push_promise * frame,uint8_t flags,int32_t stream_id,int32_t promised_stream_id,nghttp2_nv * nva,size_t nvlen)128 void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags,
129                                      int32_t stream_id,
130                                      int32_t promised_stream_id,
131                                      nghttp2_nv *nva, size_t nvlen)
132 {
133     nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_PUSH_PROMISE, flags,
134                           stream_id);
135     frame->padlen = 0;
136     frame->nva = nva;
137     frame->nvlen = nvlen;
138     frame->promised_stream_id = promised_stream_id;
139     frame->reserved = 0;
140 }
141 
nghttp2_frame_push_promise_free(nghttp2_push_promise * frame,nghttp2_mem * mem)142 void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame,
143                                      nghttp2_mem *mem)
144 {
145     nghttp2_nv_array_del(frame->nva, mem);
146 }
147 
nghttp2_frame_ping_init(nghttp2_ping * frame,uint8_t flags,const uint8_t * opaque_data)148 void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags,
149                              const uint8_t *opaque_data)
150 {
151     nghttp2_frame_hd_init(&frame->hd, 8, NGHTTP2_PING, flags, 0);
152     if (opaque_data) {
153         memcpy(frame->opaque_data, opaque_data, sizeof(frame->opaque_data));
154     } else {
155         memset(frame->opaque_data, 0, sizeof(frame->opaque_data));
156     }
157 }
158 
nghttp2_frame_ping_free(nghttp2_ping * frame)159 void nghttp2_frame_ping_free(nghttp2_ping *frame)
160 {
161     (void)frame;
162 }
163 
nghttp2_frame_goaway_init(nghttp2_goaway * frame,int32_t last_stream_id,uint32_t error_code,uint8_t * opaque_data,size_t opaque_data_len)164 void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
165                                uint32_t error_code, uint8_t *opaque_data,
166                                size_t opaque_data_len)
167 {
168     nghttp2_frame_hd_init(&frame->hd, 8 + opaque_data_len, NGHTTP2_GOAWAY,
169                           NGHTTP2_FLAG_NONE, 0);
170     frame->last_stream_id = last_stream_id;
171     frame->error_code = error_code;
172     frame->opaque_data = opaque_data;
173     frame->opaque_data_len = opaque_data_len;
174     frame->reserved = 0;
175 }
176 
nghttp2_frame_goaway_free(nghttp2_goaway * frame,nghttp2_mem * mem)177 void nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem)
178 {
179     nghttp2_mem_free(mem, frame->opaque_data);
180 }
181 
nghttp2_frame_window_update_init(nghttp2_window_update * frame,uint8_t flags,int32_t stream_id,int32_t window_size_increment)182 void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
183                                       uint8_t flags, int32_t stream_id,
184                                       int32_t window_size_increment)
185 {
186     nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_WINDOW_UPDATE, flags,
187                           stream_id);
188     frame->window_size_increment = window_size_increment;
189     frame->reserved = 0;
190 }
191 
nghttp2_frame_window_update_free(nghttp2_window_update * frame)192 void nghttp2_frame_window_update_free(nghttp2_window_update *frame)
193 {
194     (void)frame;
195 }
196 
nghttp2_frame_trail_padlen(nghttp2_frame * frame,size_t padlen)197 size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen)
198 {
199     /* We have iframe->padlen == 0, but iframe->frame.hd.flags may have
200        NGHTTP2_FLAG_PADDED set.  This happens when receiving
201        CONTINUATION frame, since we don't reset flags after HEADERS was
202        received. */
203     if (padlen == 0) {
204         return 0;
205     }
206     return padlen - ((frame->hd.flags & NGHTTP2_FLAG_PADDED) > 0);
207 }
208 
nghttp2_frame_data_init(nghttp2_data * frame,uint8_t flags,int32_t stream_id)209 void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
210                              int32_t stream_id)
211 {
212     /* At this moment, the length of DATA frame is unknown */
213     nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_DATA, flags, stream_id);
214     frame->padlen = 0;
215 }
216 
nghttp2_frame_data_free(nghttp2_data * frame)217 void nghttp2_frame_data_free(nghttp2_data *frame)
218 {
219     (void)frame;
220 }
221 
nghttp2_frame_extension_init(nghttp2_extension * frame,uint8_t type,uint8_t flags,int32_t stream_id,void * payload)222 void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
223                                   uint8_t flags, int32_t stream_id,
224                                   void *payload)
225 {
226     nghttp2_frame_hd_init(&frame->hd, 0, type, flags, stream_id);
227     frame->payload = payload;
228 }
229 
nghttp2_frame_extension_free(nghttp2_extension * frame)230 void nghttp2_frame_extension_free(nghttp2_extension *frame)
231 {
232     (void)frame;
233 }
234 
nghttp2_frame_altsvc_init(nghttp2_extension * frame,int32_t stream_id,uint8_t * origin,size_t origin_len,uint8_t * field_value,size_t field_value_len)235 void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
236                                uint8_t *origin, size_t origin_len,
237                                uint8_t *field_value, size_t field_value_len)
238 {
239     nghttp2_ext_altsvc *altsvc;
240 
241     nghttp2_frame_hd_init(&frame->hd, 2 + origin_len + field_value_len,
242                           NGHTTP2_ALTSVC, NGHTTP2_FLAG_NONE, stream_id);
243 
244     altsvc = frame->payload;
245     altsvc->origin = origin;
246     altsvc->origin_len = origin_len;
247     altsvc->field_value = field_value;
248     altsvc->field_value_len = field_value_len;
249 }
250 
nghttp2_frame_altsvc_free(nghttp2_extension * frame,nghttp2_mem * mem)251 void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem)
252 {
253     nghttp2_ext_altsvc *altsvc;
254 
255     altsvc = frame->payload;
256     /* We use the same buffer for altsvc->origin and
257        altsvc->field_value. */
258     nghttp2_mem_free(mem, altsvc->origin);
259 }
260 
nghttp2_frame_priority_len(uint8_t flags)261 size_t nghttp2_frame_priority_len(uint8_t flags)
262 {
263     if (flags & NGHTTP2_FLAG_PRIORITY) {
264         return NGHTTP2_PRIORITY_SPECLEN;
265     }
266 
267     return 0;
268 }
269 
nghttp2_frame_headers_payload_nv_offset(nghttp2_headers * frame)270 size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame)
271 {
272     return nghttp2_frame_priority_len(frame->hd.flags);
273 }
274 
275 /*
276  * Call this function after payload was serialized, but not before
277  * changing buf->pos and serializing frame header.
278  *
279  * This function assumes bufs->cur points to the last buf chain of the
280  * frame(s).
281  *
282  * This function serializes frame header for HEADERS/PUSH_PROMISE and
283  * handles their successive CONTINUATION frames.
284  *
285  * We don't process any padding here.
286  */
frame_pack_headers_shared(nghttp2_bufs * bufs,nghttp2_frame_hd * frame_hd)287 static int frame_pack_headers_shared(nghttp2_bufs *bufs,
288                                      nghttp2_frame_hd *frame_hd)
289 {
290     nghttp2_buf *buf;
291     nghttp2_buf_chain *ci, *ce;
292     nghttp2_frame_hd hd;
293 
294     buf = &bufs->head->buf;
295 
296     hd = *frame_hd;
297     hd.length = nghttp2_buf_len(buf);
298 
299     DEBUGF("send: HEADERS/PUSH_PROMISE, payloadlen=%zu\n", hd.length);
300 
301     /* We have multiple frame buffers, which means one or more
302        CONTINUATION frame is involved. Remove END_HEADERS flag from the
303        first frame. */
304     if (bufs->head != bufs->cur) {
305         hd.flags = (uint8_t)(hd.flags & ~NGHTTP2_FLAG_END_HEADERS);
306     }
307 
308     buf->pos -= NGHTTP2_FRAME_HDLEN;
309     nghttp2_frame_pack_frame_hd(buf->pos, &hd);
310 
311     if (bufs->head != bufs->cur) {
312         /* 2nd and later frames are CONTINUATION frames. */
313         hd.type = NGHTTP2_CONTINUATION;
314         /* We don't have no flags except for last CONTINUATION */
315         hd.flags = NGHTTP2_FLAG_NONE;
316 
317         ce = bufs->cur;
318 
319         for (ci = bufs->head->next; ci != ce; ci = ci->next) {
320             buf = &ci->buf;
321 
322             hd.length = nghttp2_buf_len(buf);
323 
324             DEBUGF("send: int CONTINUATION, payloadlen=%zu\n", hd.length);
325 
326             buf->pos -= NGHTTP2_FRAME_HDLEN;
327             nghttp2_frame_pack_frame_hd(buf->pos, &hd);
328         }
329 
330         buf = &ci->buf;
331         hd.length = nghttp2_buf_len(buf);
332         /* Set END_HEADERS flag for last CONTINUATION */
333         hd.flags = NGHTTP2_FLAG_END_HEADERS;
334 
335         DEBUGF("send: last CONTINUATION, payloadlen=%zu\n", hd.length);
336 
337         buf->pos -= NGHTTP2_FRAME_HDLEN;
338         nghttp2_frame_pack_frame_hd(buf->pos, &hd);
339     }
340 
341     return 0;
342 }
343 
nghttp2_frame_pack_headers(nghttp2_bufs * bufs,nghttp2_headers * frame,nghttp2_hd_deflater * deflater)344 int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
345                                nghttp2_hd_deflater *deflater)
346 {
347     size_t nv_offset;
348     int rv;
349     nghttp2_buf *buf;
350 
351     assert(bufs->head == bufs->cur);
352 
353     nv_offset = nghttp2_frame_headers_payload_nv_offset(frame);
354 
355     buf = &bufs->cur->buf;
356 
357     buf->pos += nv_offset;
358     buf->last = buf->pos;
359 
360     /* This call will adjust buf->last to the correct position */
361     rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen);
362 
363     if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
364         rv = NGHTTP2_ERR_HEADER_COMP;
365     }
366 
367     buf->pos -= nv_offset;
368 
369     if (rv != 0) {
370         return rv;
371     }
372 
373     if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
374         nghttp2_frame_pack_priority_spec(buf->pos, &frame->pri_spec);
375     }
376 
377     frame->padlen = 0;
378     frame->hd.length = nghttp2_bufs_len(bufs);
379 
380     return frame_pack_headers_shared(bufs, &frame->hd);
381 }
382 
nghttp2_frame_pack_priority_spec(uint8_t * buf,const nghttp2_priority_spec * pri_spec)383 void nghttp2_frame_pack_priority_spec(uint8_t *buf,
384                                       const nghttp2_priority_spec *pri_spec)
385 {
386     nghttp2_put_uint32be(buf, (uint32_t)pri_spec->stream_id);
387     if (pri_spec->exclusive) {
388         buf[0] |= 0x80;
389     }
390     buf[4] = (uint8_t)(pri_spec->weight - 1);
391 }
392 
nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec * pri_spec,const uint8_t * payload)393 void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
394                                         const uint8_t *payload)
395 {
396     int32_t dep_stream_id;
397     uint8_t exclusive;
398     int32_t weight;
399 
400     dep_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
401     exclusive = (payload[0] & 0x80) > 0;
402     weight = payload[4] + 1;
403 
404     nghttp2_priority_spec_init(pri_spec, dep_stream_id, weight, exclusive);
405 }
406 
nghttp2_frame_unpack_headers_payload(nghttp2_headers * frame,const uint8_t * payload)407 int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
408                                          const uint8_t *payload)
409 {
410     if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
411         nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload);
412     } else {
413         nghttp2_priority_spec_default_init(&frame->pri_spec);
414     }
415 
416     frame->nva = NULL;
417     frame->nvlen = 0;
418 
419     return 0;
420 }
421 
nghttp2_frame_pack_priority(nghttp2_bufs * bufs,nghttp2_priority * frame)422 int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame)
423 {
424     nghttp2_buf *buf;
425 
426     assert(bufs->head == bufs->cur);
427 
428     buf = &bufs->head->buf;
429 
430     assert(nghttp2_buf_avail(buf) >= NGHTTP2_PRIORITY_SPECLEN);
431 
432     buf->pos -= NGHTTP2_FRAME_HDLEN;
433 
434     nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
435 
436     nghttp2_frame_pack_priority_spec(buf->last, &frame->pri_spec);
437 
438     buf->last += NGHTTP2_PRIORITY_SPECLEN;
439 
440     return 0;
441 }
442 
nghttp2_frame_unpack_priority_payload(nghttp2_priority * frame,const uint8_t * payload)443 void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
444                                            const uint8_t *payload)
445 {
446     nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload);
447 }
448 
nghttp2_frame_pack_rst_stream(nghttp2_bufs * bufs,nghttp2_rst_stream * frame)449 int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs, nghttp2_rst_stream *frame)
450 {
451     nghttp2_buf *buf;
452 
453     assert(bufs->head == bufs->cur);
454 
455     buf = &bufs->head->buf;
456 
457     assert(nghttp2_buf_avail(buf) >= 4);
458 
459     buf->pos -= NGHTTP2_FRAME_HDLEN;
460 
461     nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
462 
463     nghttp2_put_uint32be(buf->last, frame->error_code);
464     buf->last += 4;
465 
466     return 0;
467 }
468 
nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream * frame,const uint8_t * payload)469 void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
470                                              const uint8_t *payload)
471 {
472     frame->error_code = nghttp2_get_uint32(payload);
473 }
474 
nghttp2_frame_pack_settings(nghttp2_bufs * bufs,nghttp2_settings * frame)475 int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame)
476 {
477     nghttp2_buf *buf;
478 
479     assert(bufs->head == bufs->cur);
480 
481     buf = &bufs->head->buf;
482 
483     if (nghttp2_buf_avail(buf) < frame->hd.length) {
484         return NGHTTP2_ERR_FRAME_SIZE_ERROR;
485     }
486 
487     buf->pos -= NGHTTP2_FRAME_HDLEN;
488 
489     nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
490 
491     buf->last +=
492         nghttp2_frame_pack_settings_payload(buf->last, frame->iv, frame->niv);
493 
494     return 0;
495 }
496 
nghttp2_frame_pack_settings_payload(uint8_t * buf,const nghttp2_settings_entry * iv,size_t niv)497 size_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
498                                            const nghttp2_settings_entry *iv,
499                                            size_t niv)
500 {
501     size_t i;
502     for (i = 0; i < niv; ++i, buf += NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) {
503         nghttp2_put_uint16be(buf, (uint16_t)iv[i].settings_id);
504         nghttp2_put_uint32be(buf + 2, iv[i].value);
505     }
506     return NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH * niv;
507 }
508 
nghttp2_frame_unpack_settings_payload(nghttp2_settings * frame,nghttp2_settings_entry * iv,size_t niv)509 void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
510                                            nghttp2_settings_entry *iv,
511                                            size_t niv)
512 {
513     frame->iv = iv;
514     frame->niv = niv;
515 }
516 
nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry * iv,const uint8_t * payload)517 void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
518                                          const uint8_t *payload)
519 {
520     iv->settings_id = nghttp2_get_uint16(&payload[0]);
521     iv->value = nghttp2_get_uint32(&payload[2]);
522 }
523 
nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry ** iv_ptr,size_t * niv_ptr,const uint8_t * payload,size_t payloadlen,nghttp2_mem * mem)524 int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
525                                            size_t *niv_ptr,
526                                            const uint8_t *payload,
527                                            size_t payloadlen, nghttp2_mem *mem)
528 {
529     size_t i;
530 
531     *niv_ptr = payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH;
532 
533     if (*niv_ptr == 0) {
534         *iv_ptr = NULL;
535 
536         return 0;
537     }
538 
539     *iv_ptr =
540         nghttp2_mem_malloc(mem, (*niv_ptr) * sizeof(nghttp2_settings_entry));
541 
542     if (*iv_ptr == NULL) {
543         return NGHTTP2_ERR_NOMEM;
544     }
545 
546     for (i = 0; i < *niv_ptr; ++i) {
547         size_t off = i * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH;
548         nghttp2_frame_unpack_settings_entry(&(*iv_ptr)[i], &payload[off]);
549     }
550 
551     return 0;
552 }
553 
nghttp2_frame_pack_push_promise(nghttp2_bufs * bufs,nghttp2_push_promise * frame,nghttp2_hd_deflater * deflater)554 int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
555                                     nghttp2_push_promise *frame,
556                                     nghttp2_hd_deflater *deflater)
557 {
558     size_t nv_offset = 4;
559     int rv;
560     nghttp2_buf *buf;
561 
562     assert(bufs->head == bufs->cur);
563 
564     buf = &bufs->cur->buf;
565 
566     buf->pos += nv_offset;
567     buf->last = buf->pos;
568 
569     /* This call will adjust buf->last to the correct position */
570     rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen);
571 
572     if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
573         rv = NGHTTP2_ERR_HEADER_COMP;
574     }
575 
576     buf->pos -= nv_offset;
577 
578     if (rv != 0) {
579         return rv;
580     }
581 
582     nghttp2_put_uint32be(buf->pos, (uint32_t)frame->promised_stream_id);
583 
584     frame->padlen = 0;
585     frame->hd.length = nghttp2_bufs_len(bufs);
586 
587     return frame_pack_headers_shared(bufs, &frame->hd);
588 }
589 
nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise * frame,const uint8_t * payload)590 int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
591                                               const uint8_t *payload)
592 {
593     frame->promised_stream_id =
594         nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
595     frame->nva = NULL;
596     frame->nvlen = 0;
597     return 0;
598 }
599 
nghttp2_frame_pack_ping(nghttp2_bufs * bufs,nghttp2_ping * frame)600 int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame)
601 {
602     nghttp2_buf *buf;
603 
604     assert(bufs->head == bufs->cur);
605 
606     buf = &bufs->head->buf;
607 
608     assert(nghttp2_buf_avail(buf) >= 8);
609 
610     buf->pos -= NGHTTP2_FRAME_HDLEN;
611 
612     nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
613 
614     buf->last = nghttp2_cpymem(buf->last, frame->opaque_data,
615                                sizeof(frame->opaque_data));
616 
617     return 0;
618 }
619 
nghttp2_frame_unpack_ping_payload(nghttp2_ping * frame,const uint8_t * payload)620 void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
621                                        const uint8_t *payload)
622 {
623     memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data));
624 }
625 
nghttp2_frame_pack_goaway(nghttp2_bufs * bufs,nghttp2_goaway * frame)626 int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame)
627 {
628     int rv;
629     nghttp2_buf *buf;
630 
631     assert(bufs->head == bufs->cur);
632 
633     buf = &bufs->head->buf;
634 
635     buf->pos -= NGHTTP2_FRAME_HDLEN;
636 
637     nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
638 
639     nghttp2_put_uint32be(buf->last, (uint32_t)frame->last_stream_id);
640     buf->last += 4;
641 
642     nghttp2_put_uint32be(buf->last, frame->error_code);
643     buf->last += 4;
644 
645     rv = nghttp2_bufs_add(bufs, frame->opaque_data, frame->opaque_data_len);
646 
647     if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
648         return NGHTTP2_ERR_FRAME_SIZE_ERROR;
649     }
650 
651     if (rv != 0) {
652         return rv;
653     }
654 
655     return 0;
656 }
657 
nghttp2_frame_unpack_goaway_payload(nghttp2_goaway * frame,const uint8_t * payload,uint8_t * var_gift_payload,size_t var_gift_payloadlen)658 void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
659                                          const uint8_t *payload,
660                                          uint8_t *var_gift_payload,
661                                          size_t var_gift_payloadlen)
662 {
663     frame->last_stream_id =
664         nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
665     frame->error_code = nghttp2_get_uint32(payload + 4);
666 
667     frame->opaque_data = var_gift_payload;
668     frame->opaque_data_len = var_gift_payloadlen;
669 }
670 
nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway * frame,const uint8_t * payload,size_t payloadlen,nghttp2_mem * mem)671 int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
672                                          const uint8_t *payload,
673                                          size_t payloadlen, nghttp2_mem *mem)
674 {
675     uint8_t *var_gift_payload;
676     size_t var_gift_payloadlen;
677 
678     if (payloadlen > 8) {
679         var_gift_payloadlen = payloadlen - 8;
680     } else {
681         var_gift_payloadlen = 0;
682     }
683 
684     payloadlen -= var_gift_payloadlen;
685 
686     if (!var_gift_payloadlen) {
687         var_gift_payload = NULL;
688     } else {
689         var_gift_payload = nghttp2_mem_malloc(mem, var_gift_payloadlen);
690 
691         if (var_gift_payload == NULL) {
692             return NGHTTP2_ERR_NOMEM;
693         }
694 
695         memcpy(var_gift_payload, payload + 8, var_gift_payloadlen);
696     }
697 
698     nghttp2_frame_unpack_goaway_payload(frame, payload, var_gift_payload,
699                                         var_gift_payloadlen);
700 
701     return 0;
702 }
703 
nghttp2_frame_pack_window_update(nghttp2_bufs * bufs,nghttp2_window_update * frame)704 int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
705                                      nghttp2_window_update *frame)
706 {
707     nghttp2_buf *buf;
708 
709     assert(bufs->head == bufs->cur);
710 
711     buf = &bufs->head->buf;
712 
713     assert(nghttp2_buf_avail(buf) >= 4);
714 
715     buf->pos -= NGHTTP2_FRAME_HDLEN;
716 
717     nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
718 
719     nghttp2_put_uint32be(buf->last, (uint32_t)frame->window_size_increment);
720     buf->last += 4;
721 
722     return 0;
723 }
724 
nghttp2_frame_unpack_window_update_payload(nghttp2_window_update * frame,const uint8_t * payload)725 void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
726                                                 const uint8_t *payload)
727 {
728     frame->window_size_increment =
729         nghttp2_get_uint32(payload) & NGHTTP2_WINDOW_SIZE_INCREMENT_MASK;
730 }
731 
nghttp2_frame_pack_altsvc(nghttp2_bufs * bufs,nghttp2_extension * frame)732 int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame)
733 {
734     int rv;
735     nghttp2_buf *buf;
736     nghttp2_ext_altsvc *altsvc;
737 
738     /* This is required with --disable-assert. */
739     (void)rv;
740 
741     altsvc = frame->payload;
742 
743     buf = &bufs->head->buf;
744 
745     assert(nghttp2_buf_avail(buf) >=
746            2 + altsvc->origin_len + altsvc->field_value_len);
747 
748     buf->pos -= NGHTTP2_FRAME_HDLEN;
749 
750     nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
751 
752     nghttp2_put_uint16be(buf->last, (uint16_t)altsvc->origin_len);
753     buf->last += 2;
754 
755     rv = nghttp2_bufs_add(bufs, altsvc->origin, altsvc->origin_len);
756 
757     assert(rv == 0);
758 
759     rv = nghttp2_bufs_add(bufs, altsvc->field_value, altsvc->field_value_len);
760 
761     assert(rv == 0);
762 
763     return 0;
764 }
765 
nghttp2_frame_unpack_altsvc_payload(nghttp2_extension * frame,size_t origin_len,uint8_t * payload,size_t payloadlen)766 void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
767                                          size_t origin_len, uint8_t *payload,
768                                          size_t payloadlen)
769 {
770     nghttp2_ext_altsvc *altsvc;
771     uint8_t *p;
772 
773     altsvc = frame->payload;
774     p = payload;
775 
776     altsvc->origin = p;
777 
778     p += origin_len;
779 
780     altsvc->origin_len = origin_len;
781 
782     altsvc->field_value = p;
783     altsvc->field_value_len = (size_t)(payload + payloadlen - p);
784 }
785 
nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension * frame,const uint8_t * payload,size_t payloadlen,nghttp2_mem * mem)786 int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame,
787                                          const uint8_t *payload,
788                                          size_t payloadlen, nghttp2_mem *mem)
789 {
790     uint8_t *buf;
791     size_t origin_len;
792 
793     if (payloadlen < 2) {
794         return NGHTTP2_FRAME_SIZE_ERROR;
795     }
796 
797     origin_len = nghttp2_get_uint16(payload);
798 
799     buf = nghttp2_mem_malloc(mem, payloadlen - 2);
800     if (!buf) {
801         return NGHTTP2_ERR_NOMEM;
802     }
803 
804     nghttp2_cpymem(buf, payload + 2, payloadlen - 2);
805 
806     nghttp2_frame_unpack_altsvc_payload(frame, origin_len, buf, payloadlen - 2);
807 
808     return 0;
809 }
810 
nghttp2_frame_iv_copy(const nghttp2_settings_entry * iv,size_t niv,nghttp2_mem * mem)811 nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
812                                               size_t niv, nghttp2_mem *mem)
813 {
814     nghttp2_settings_entry *iv_copy;
815     size_t len = niv * sizeof(nghttp2_settings_entry);
816 
817     if (len == 0) {
818         return NULL;
819     }
820 
821     iv_copy = nghttp2_mem_malloc(mem, len);
822 
823     if (iv_copy == NULL) {
824         return NULL;
825     }
826 
827     memcpy(iv_copy, iv, len);
828 
829     return iv_copy;
830 }
831 
nghttp2_nv_equal(const nghttp2_nv * a,const nghttp2_nv * b)832 int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b)
833 {
834     return a->namelen == b->namelen && a->valuelen == b->valuelen &&
835            memcmp(a->name, b->name, a->namelen) == 0 &&
836            memcmp(a->value, b->value, a->valuelen) == 0;
837 }
838 
nghttp2_nv_array_del(nghttp2_nv * nva,nghttp2_mem * mem)839 void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem)
840 {
841     nghttp2_mem_free(mem, nva);
842 }
843 
bytes_compar(const uint8_t * a,size_t alen,const uint8_t * b,size_t blen)844 static int bytes_compar(const uint8_t *a, size_t alen, const uint8_t *b,
845                         size_t blen)
846 {
847     int rv;
848 
849     if (alen == blen) {
850         return memcmp(a, b, alen);
851     }
852 
853     if (alen < blen) {
854         rv = memcmp(a, b, alen);
855 
856         if (rv == 0) {
857             return -1;
858         }
859 
860         return rv;
861     }
862 
863     rv = memcmp(a, b, blen);
864 
865     if (rv == 0) {
866         return 1;
867     }
868 
869     return rv;
870 }
871 
nghttp2_nv_compare_name(const nghttp2_nv * lhs,const nghttp2_nv * rhs)872 int nghttp2_nv_compare_name(const nghttp2_nv *lhs, const nghttp2_nv *rhs)
873 {
874     return bytes_compar(lhs->name, lhs->namelen, rhs->name, rhs->namelen);
875 }
876 
nv_compar(const void * lhs,const void * rhs)877 static int nv_compar(const void *lhs, const void *rhs)
878 {
879     const nghttp2_nv *a = (const nghttp2_nv *)lhs;
880     const nghttp2_nv *b = (const nghttp2_nv *)rhs;
881     int rv;
882 
883     rv = bytes_compar(a->name, a->namelen, b->name, b->namelen);
884 
885     if (rv == 0) {
886         return bytes_compar(a->value, a->valuelen, b->value, b->valuelen);
887     }
888 
889     return rv;
890 }
891 
nghttp2_nv_array_sort(nghttp2_nv * nva,size_t nvlen)892 void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen)
893 {
894     qsort(nva, nvlen, sizeof(nghttp2_nv), nv_compar);
895 }
896 
nghttp2_nv_array_copy(nghttp2_nv ** nva_ptr,const nghttp2_nv * nva,size_t nvlen,nghttp2_mem * mem)897 int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
898                           size_t nvlen, nghttp2_mem *mem)
899 {
900     size_t i;
901     uint8_t *data = NULL;
902     size_t buflen = 0;
903     nghttp2_nv *p;
904 
905     if (nvlen == 0) {
906         *nva_ptr = NULL;
907 
908         return 0;
909     }
910 
911     for (i = 0; i < nvlen; ++i) {
912         /* + 1 for null-termination */
913         if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) == 0) {
914             buflen += nva[i].namelen + 1;
915         }
916         if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) == 0) {
917             buflen += nva[i].valuelen + 1;
918         }
919     }
920 
921     buflen += sizeof(nghttp2_nv) * nvlen;
922 
923     *nva_ptr = nghttp2_mem_malloc(mem, buflen);
924 
925     if (*nva_ptr == NULL) {
926         return NGHTTP2_ERR_NOMEM;
927     }
928 
929     p = *nva_ptr;
930     data = (uint8_t *)(*nva_ptr) + sizeof(nghttp2_nv) * nvlen;
931 
932     for (i = 0; i < nvlen; ++i) {
933         p->flags = nva[i].flags;
934 
935         if (nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) {
936             p->name = nva[i].name;
937             p->namelen = nva[i].namelen;
938         } else {
939             if (nva[i].namelen) {
940                 memcpy(data, nva[i].name, nva[i].namelen);
941             }
942             p->name = data;
943             p->namelen = nva[i].namelen;
944             data[p->namelen] = '\0';
945             nghttp2_downcase(p->name, p->namelen);
946             data += nva[i].namelen + 1;
947         }
948 
949         if (nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) {
950             p->value = nva[i].value;
951             p->valuelen = nva[i].valuelen;
952         } else {
953             if (nva[i].valuelen) {
954                 memcpy(data, nva[i].value, nva[i].valuelen);
955             }
956             p->value = data;
957             p->valuelen = nva[i].valuelen;
958             data[p->valuelen] = '\0';
959             data += nva[i].valuelen + 1;
960         }
961 
962         ++p;
963     }
964     return 0;
965 }
966 
nghttp2_iv_check(const nghttp2_settings_entry * iv,size_t niv)967 int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv)
968 {
969     size_t i;
970     for (i = 0; i < niv; ++i) {
971         switch (iv[i].settings_id) {
972         case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE:
973             break;
974         case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:
975             break;
976         case NGHTTP2_SETTINGS_ENABLE_PUSH:
977             if (iv[i].value != 0 && iv[i].value != 1) {
978                 return 0;
979             }
980             break;
981         case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
982             if (iv[i].value > (uint32_t)NGHTTP2_MAX_WINDOW_SIZE) {
983                 return 0;
984             }
985             break;
986         case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
987             if (iv[i].value < NGHTTP2_MAX_FRAME_SIZE_MIN ||
988                 iv[i].value > NGHTTP2_MAX_FRAME_SIZE_MAX) {
989                 return 0;
990             }
991             break;
992         case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
993             break;
994         }
995     }
996     return 1;
997 }
998 
frame_set_pad(nghttp2_buf * buf,size_t padlen,int framehd_only)999 static void frame_set_pad(nghttp2_buf *buf, size_t padlen, int framehd_only)
1000 {
1001     size_t trail_padlen;
1002     size_t newlen;
1003 
1004     DEBUGF("send: padlen=%zu, shift left 1 bytes\n", padlen);
1005 
1006     memmove(buf->pos - 1, buf->pos, NGHTTP2_FRAME_HDLEN);
1007 
1008     --buf->pos;
1009 
1010     buf->pos[4] |= NGHTTP2_FLAG_PADDED;
1011 
1012     newlen = (nghttp2_get_uint32(buf->pos) >> 8) + padlen;
1013     nghttp2_put_uint32be(buf->pos, (uint32_t)((newlen << 8) + buf->pos[3]));
1014 
1015     if (framehd_only) {
1016         return;
1017     }
1018 
1019     trail_padlen = padlen - 1;
1020     buf->pos[NGHTTP2_FRAME_HDLEN] = (uint8_t)trail_padlen;
1021 
1022     /* zero out padding */
1023     memset(buf->last, 0, trail_padlen);
1024     /* extend buffers trail_padlen bytes, since we ate previous padlen -
1025        trail_padlen byte(s) */
1026     buf->last += trail_padlen;
1027 }
1028 
nghttp2_frame_add_pad(nghttp2_bufs * bufs,nghttp2_frame_hd * hd,size_t padlen,int framehd_only)1029 int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
1030                           size_t padlen, int framehd_only)
1031 {
1032     nghttp2_buf *buf;
1033 
1034     if (padlen == 0) {
1035         DEBUGF("send: padlen = 0, nothing to do\n");
1036 
1037         return 0;
1038     }
1039 
1040     /*
1041      * We have arranged bufs like this:
1042      *
1043      *  0                   1                   2                   3
1044      *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1045      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1046      * | |Frame header     | Frame payload...                          :
1047      * +-+-----------------+-------------------------------------------+
1048      * | |Frame header     | Frame payload...                          :
1049      * +-+-----------------+-------------------------------------------+
1050      * | |Frame header     | Frame payload...                          :
1051      * +-+-----------------+-------------------------------------------+
1052      *
1053      * We arranged padding so that it is included in the first frame
1054      * completely.  For padded frame, we are going to adjust buf->pos of
1055      * frame which includes padding and serialize (memmove) frame header
1056      * in the correct position.  Also extends buf->last to include
1057      * padding.
1058      */
1059 
1060     buf = &bufs->head->buf;
1061 
1062     assert(nghttp2_buf_avail(buf) >= padlen - 1);
1063 
1064     frame_set_pad(buf, padlen, framehd_only);
1065 
1066     hd->length += padlen;
1067     hd->flags |= NGHTTP2_FLAG_PADDED;
1068 
1069     DEBUGF("send: final payloadlen=%zu, padlen=%zu\n", hd->length, padlen);
1070 
1071     return 0;
1072 }
1073