12c593315Sopenharmony_ci/*
22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library
32c593315Sopenharmony_ci *
42c593315Sopenharmony_ci * Copyright (c) 2013 Tatsuhiro Tsujikawa
52c593315Sopenharmony_ci *
62c593315Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
72c593315Sopenharmony_ci * a copy of this software and associated documentation files (the
82c593315Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
92c593315Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
102c593315Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
112c593315Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
122c593315Sopenharmony_ci * the following conditions:
132c593315Sopenharmony_ci *
142c593315Sopenharmony_ci * The above copyright notice and this permission notice shall be
152c593315Sopenharmony_ci * included in all copies or substantial portions of the Software.
162c593315Sopenharmony_ci *
172c593315Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
182c593315Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
192c593315Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
202c593315Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
212c593315Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
222c593315Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
232c593315Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
242c593315Sopenharmony_ci */
252c593315Sopenharmony_ci#include "nghttp2_frame.h"
262c593315Sopenharmony_ci
272c593315Sopenharmony_ci#include <string.h>
282c593315Sopenharmony_ci#include <assert.h>
292c593315Sopenharmony_ci#include <stdio.h>
302c593315Sopenharmony_ci#include <errno.h>
312c593315Sopenharmony_ci
322c593315Sopenharmony_ci#include "nghttp2_helper.h"
332c593315Sopenharmony_ci#include "nghttp2_net.h"
342c593315Sopenharmony_ci#include "nghttp2_priority_spec.h"
352c593315Sopenharmony_ci#include "nghttp2_debug.h"
362c593315Sopenharmony_ci
372c593315Sopenharmony_civoid nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd) {
382c593315Sopenharmony_ci  nghttp2_put_uint32be(&buf[0], (uint32_t)(hd->length << 8));
392c593315Sopenharmony_ci  buf[3] = hd->type;
402c593315Sopenharmony_ci  buf[4] = hd->flags;
412c593315Sopenharmony_ci  nghttp2_put_uint32be(&buf[5], (uint32_t)hd->stream_id);
422c593315Sopenharmony_ci  /* ignore hd->reserved for now */
432c593315Sopenharmony_ci}
442c593315Sopenharmony_ci
452c593315Sopenharmony_civoid nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf) {
462c593315Sopenharmony_ci  hd->length = nghttp2_get_uint32(&buf[0]) >> 8;
472c593315Sopenharmony_ci  hd->type = buf[3];
482c593315Sopenharmony_ci  hd->flags = buf[4];
492c593315Sopenharmony_ci  hd->stream_id = nghttp2_get_uint32(&buf[5]) & NGHTTP2_STREAM_ID_MASK;
502c593315Sopenharmony_ci  hd->reserved = 0;
512c593315Sopenharmony_ci}
522c593315Sopenharmony_ci
532c593315Sopenharmony_civoid nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type,
542c593315Sopenharmony_ci                           uint8_t flags, int32_t stream_id) {
552c593315Sopenharmony_ci  hd->length = length;
562c593315Sopenharmony_ci  hd->type = type;
572c593315Sopenharmony_ci  hd->flags = flags;
582c593315Sopenharmony_ci  hd->stream_id = stream_id;
592c593315Sopenharmony_ci  hd->reserved = 0;
602c593315Sopenharmony_ci}
612c593315Sopenharmony_ci
622c593315Sopenharmony_civoid nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags,
632c593315Sopenharmony_ci                                int32_t stream_id, nghttp2_headers_category cat,
642c593315Sopenharmony_ci                                const nghttp2_priority_spec *pri_spec,
652c593315Sopenharmony_ci                                nghttp2_nv *nva, size_t nvlen) {
662c593315Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_HEADERS, flags, stream_id);
672c593315Sopenharmony_ci  frame->padlen = 0;
682c593315Sopenharmony_ci  frame->nva = nva;
692c593315Sopenharmony_ci  frame->nvlen = nvlen;
702c593315Sopenharmony_ci  frame->cat = cat;
712c593315Sopenharmony_ci
722c593315Sopenharmony_ci  if (pri_spec) {
732c593315Sopenharmony_ci    frame->pri_spec = *pri_spec;
742c593315Sopenharmony_ci  } else {
752c593315Sopenharmony_ci    nghttp2_priority_spec_default_init(&frame->pri_spec);
762c593315Sopenharmony_ci  }
772c593315Sopenharmony_ci}
782c593315Sopenharmony_ci
792c593315Sopenharmony_civoid nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem) {
802c593315Sopenharmony_ci  nghttp2_nv_array_del(frame->nva, mem);
812c593315Sopenharmony_ci}
822c593315Sopenharmony_ci
832c593315Sopenharmony_civoid nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
842c593315Sopenharmony_ci                                 const nghttp2_priority_spec *pri_spec) {
852c593315Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, NGHTTP2_PRIORITY_SPECLEN, NGHTTP2_PRIORITY,
862c593315Sopenharmony_ci                        NGHTTP2_FLAG_NONE, stream_id);
872c593315Sopenharmony_ci  frame->pri_spec = *pri_spec;
882c593315Sopenharmony_ci}
892c593315Sopenharmony_ci
902c593315Sopenharmony_civoid nghttp2_frame_priority_free(nghttp2_priority *frame) { (void)frame; }
912c593315Sopenharmony_ci
922c593315Sopenharmony_civoid nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
932c593315Sopenharmony_ci                                   uint32_t error_code) {
942c593315Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE,
952c593315Sopenharmony_ci                        stream_id);
962c593315Sopenharmony_ci  frame->error_code = error_code;
972c593315Sopenharmony_ci}
982c593315Sopenharmony_ci
992c593315Sopenharmony_civoid nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame) { (void)frame; }
1002c593315Sopenharmony_ci
1012c593315Sopenharmony_civoid nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
1022c593315Sopenharmony_ci                                 nghttp2_settings_entry *iv, size_t niv) {
1032c593315Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH,
1042c593315Sopenharmony_ci                        NGHTTP2_SETTINGS, flags, 0);
1052c593315Sopenharmony_ci  frame->niv = niv;
1062c593315Sopenharmony_ci  frame->iv = iv;
1072c593315Sopenharmony_ci}
1082c593315Sopenharmony_ci
1092c593315Sopenharmony_civoid nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem) {
1102c593315Sopenharmony_ci  nghttp2_mem_free(mem, frame->iv);
1112c593315Sopenharmony_ci}
1122c593315Sopenharmony_ci
1132c593315Sopenharmony_civoid nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags,
1142c593315Sopenharmony_ci                                     int32_t stream_id,
1152c593315Sopenharmony_ci                                     int32_t promised_stream_id,
1162c593315Sopenharmony_ci                                     nghttp2_nv *nva, size_t nvlen) {
1172c593315Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_PUSH_PROMISE, flags, stream_id);
1182c593315Sopenharmony_ci  frame->padlen = 0;
1192c593315Sopenharmony_ci  frame->nva = nva;
1202c593315Sopenharmony_ci  frame->nvlen = nvlen;
1212c593315Sopenharmony_ci  frame->promised_stream_id = promised_stream_id;
1222c593315Sopenharmony_ci  frame->reserved = 0;
1232c593315Sopenharmony_ci}
1242c593315Sopenharmony_ci
1252c593315Sopenharmony_civoid nghttp2_frame_push_promise_free(nghttp2_push_promise *frame,
1262c593315Sopenharmony_ci                                     nghttp2_mem *mem) {
1272c593315Sopenharmony_ci  nghttp2_nv_array_del(frame->nva, mem);
1282c593315Sopenharmony_ci}
1292c593315Sopenharmony_ci
1302c593315Sopenharmony_civoid nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags,
1312c593315Sopenharmony_ci                             const uint8_t *opaque_data) {
1322c593315Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 8, NGHTTP2_PING, flags, 0);
1332c593315Sopenharmony_ci  if (opaque_data) {
1342c593315Sopenharmony_ci    memcpy(frame->opaque_data, opaque_data, sizeof(frame->opaque_data));
1352c593315Sopenharmony_ci  } else {
1362c593315Sopenharmony_ci    memset(frame->opaque_data, 0, sizeof(frame->opaque_data));
1372c593315Sopenharmony_ci  }
1382c593315Sopenharmony_ci}
1392c593315Sopenharmony_ci
1402c593315Sopenharmony_civoid nghttp2_frame_ping_free(nghttp2_ping *frame) { (void)frame; }
1412c593315Sopenharmony_ci
1422c593315Sopenharmony_civoid nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
1432c593315Sopenharmony_ci                               uint32_t error_code, uint8_t *opaque_data,
1442c593315Sopenharmony_ci                               size_t opaque_data_len) {
1452c593315Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 8 + opaque_data_len, NGHTTP2_GOAWAY,
1462c593315Sopenharmony_ci                        NGHTTP2_FLAG_NONE, 0);
1472c593315Sopenharmony_ci  frame->last_stream_id = last_stream_id;
1482c593315Sopenharmony_ci  frame->error_code = error_code;
1492c593315Sopenharmony_ci  frame->opaque_data = opaque_data;
1502c593315Sopenharmony_ci  frame->opaque_data_len = opaque_data_len;
1512c593315Sopenharmony_ci  frame->reserved = 0;
1522c593315Sopenharmony_ci}
1532c593315Sopenharmony_ci
1542c593315Sopenharmony_civoid nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem) {
1552c593315Sopenharmony_ci  nghttp2_mem_free(mem, frame->opaque_data);
1562c593315Sopenharmony_ci}
1572c593315Sopenharmony_ci
1582c593315Sopenharmony_civoid nghttp2_frame_window_update_init(nghttp2_window_update *frame,
1592c593315Sopenharmony_ci                                      uint8_t flags, int32_t stream_id,
1602c593315Sopenharmony_ci                                      int32_t window_size_increment) {
1612c593315Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_WINDOW_UPDATE, flags, stream_id);
1622c593315Sopenharmony_ci  frame->window_size_increment = window_size_increment;
1632c593315Sopenharmony_ci  frame->reserved = 0;
1642c593315Sopenharmony_ci}
1652c593315Sopenharmony_ci
1662c593315Sopenharmony_civoid nghttp2_frame_window_update_free(nghttp2_window_update *frame) {
1672c593315Sopenharmony_ci  (void)frame;
1682c593315Sopenharmony_ci}
1692c593315Sopenharmony_ci
1702c593315Sopenharmony_cisize_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen) {
1712c593315Sopenharmony_ci  /* We have iframe->padlen == 0, but iframe->frame.hd.flags may have
1722c593315Sopenharmony_ci     NGHTTP2_FLAG_PADDED set.  This happens when receiving
1732c593315Sopenharmony_ci     CONTINUATION frame, since we don't reset flags after HEADERS was
1742c593315Sopenharmony_ci     received. */
1752c593315Sopenharmony_ci  if (padlen == 0) {
1762c593315Sopenharmony_ci    return 0;
1772c593315Sopenharmony_ci  }
1782c593315Sopenharmony_ci  return padlen - ((frame->hd.flags & NGHTTP2_FLAG_PADDED) > 0);
1792c593315Sopenharmony_ci}
1802c593315Sopenharmony_ci
1812c593315Sopenharmony_civoid nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
1822c593315Sopenharmony_ci                             int32_t stream_id) {
1832c593315Sopenharmony_ci  /* At this moment, the length of DATA frame is unknown */
1842c593315Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_DATA, flags, stream_id);
1852c593315Sopenharmony_ci  frame->padlen = 0;
1862c593315Sopenharmony_ci}
1872c593315Sopenharmony_ci
1882c593315Sopenharmony_civoid nghttp2_frame_data_free(nghttp2_data *frame) { (void)frame; }
1892c593315Sopenharmony_ci
1902c593315Sopenharmony_civoid nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
1912c593315Sopenharmony_ci                                  uint8_t flags, int32_t stream_id,
1922c593315Sopenharmony_ci                                  void *payload) {
1932c593315Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 0, type, flags, stream_id);
1942c593315Sopenharmony_ci  frame->payload = payload;
1952c593315Sopenharmony_ci}
1962c593315Sopenharmony_ci
1972c593315Sopenharmony_civoid nghttp2_frame_extension_free(nghttp2_extension *frame) { (void)frame; }
1982c593315Sopenharmony_ci
1992c593315Sopenharmony_civoid nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
2002c593315Sopenharmony_ci                               uint8_t *origin, size_t origin_len,
2012c593315Sopenharmony_ci                               uint8_t *field_value, size_t field_value_len) {
2022c593315Sopenharmony_ci  nghttp2_ext_altsvc *altsvc;
2032c593315Sopenharmony_ci
2042c593315Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 2 + origin_len + field_value_len,
2052c593315Sopenharmony_ci                        NGHTTP2_ALTSVC, NGHTTP2_FLAG_NONE, stream_id);
2062c593315Sopenharmony_ci
2072c593315Sopenharmony_ci  altsvc = frame->payload;
2082c593315Sopenharmony_ci  altsvc->origin = origin;
2092c593315Sopenharmony_ci  altsvc->origin_len = origin_len;
2102c593315Sopenharmony_ci  altsvc->field_value = field_value;
2112c593315Sopenharmony_ci  altsvc->field_value_len = field_value_len;
2122c593315Sopenharmony_ci}
2132c593315Sopenharmony_ci
2142c593315Sopenharmony_civoid nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem) {
2152c593315Sopenharmony_ci  nghttp2_ext_altsvc *altsvc;
2162c593315Sopenharmony_ci
2172c593315Sopenharmony_ci  altsvc = frame->payload;
2182c593315Sopenharmony_ci  if (altsvc == NULL) {
2192c593315Sopenharmony_ci    return;
2202c593315Sopenharmony_ci  }
2212c593315Sopenharmony_ci  /* We use the same buffer for altsvc->origin and
2222c593315Sopenharmony_ci     altsvc->field_value. */
2232c593315Sopenharmony_ci  nghttp2_mem_free(mem, altsvc->origin);
2242c593315Sopenharmony_ci}
2252c593315Sopenharmony_ci
2262c593315Sopenharmony_civoid nghttp2_frame_origin_init(nghttp2_extension *frame,
2272c593315Sopenharmony_ci                               nghttp2_origin_entry *ov, size_t nov) {
2282c593315Sopenharmony_ci  nghttp2_ext_origin *origin;
2292c593315Sopenharmony_ci  size_t payloadlen = 0;
2302c593315Sopenharmony_ci  size_t i;
2312c593315Sopenharmony_ci
2322c593315Sopenharmony_ci  for (i = 0; i < nov; ++i) {
2332c593315Sopenharmony_ci    payloadlen += 2 + ov[i].origin_len;
2342c593315Sopenharmony_ci  }
2352c593315Sopenharmony_ci
2362c593315Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, payloadlen, NGHTTP2_ORIGIN,
2372c593315Sopenharmony_ci                        NGHTTP2_FLAG_NONE, 0);
2382c593315Sopenharmony_ci
2392c593315Sopenharmony_ci  origin = frame->payload;
2402c593315Sopenharmony_ci  origin->ov = ov;
2412c593315Sopenharmony_ci  origin->nov = nov;
2422c593315Sopenharmony_ci}
2432c593315Sopenharmony_ci
2442c593315Sopenharmony_civoid nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem) {
2452c593315Sopenharmony_ci  nghttp2_ext_origin *origin;
2462c593315Sopenharmony_ci
2472c593315Sopenharmony_ci  origin = frame->payload;
2482c593315Sopenharmony_ci  if (origin == NULL) {
2492c593315Sopenharmony_ci    return;
2502c593315Sopenharmony_ci  }
2512c593315Sopenharmony_ci  /* We use the same buffer for all resources pointed by the field of
2522c593315Sopenharmony_ci     origin directly or indirectly. */
2532c593315Sopenharmony_ci  nghttp2_mem_free(mem, origin->ov);
2542c593315Sopenharmony_ci}
2552c593315Sopenharmony_ci
2562c593315Sopenharmony_civoid nghttp2_frame_priority_update_init(nghttp2_extension *frame,
2572c593315Sopenharmony_ci                                        int32_t stream_id, uint8_t *field_value,
2582c593315Sopenharmony_ci                                        size_t field_value_len) {
2592c593315Sopenharmony_ci  nghttp2_ext_priority_update *priority_update;
2602c593315Sopenharmony_ci
2612c593315Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 4 + field_value_len,
2622c593315Sopenharmony_ci                        NGHTTP2_PRIORITY_UPDATE, NGHTTP2_FLAG_NONE, 0);
2632c593315Sopenharmony_ci
2642c593315Sopenharmony_ci  priority_update = frame->payload;
2652c593315Sopenharmony_ci  priority_update->stream_id = stream_id;
2662c593315Sopenharmony_ci  priority_update->field_value = field_value;
2672c593315Sopenharmony_ci  priority_update->field_value_len = field_value_len;
2682c593315Sopenharmony_ci}
2692c593315Sopenharmony_ci
2702c593315Sopenharmony_civoid nghttp2_frame_priority_update_free(nghttp2_extension *frame,
2712c593315Sopenharmony_ci                                        nghttp2_mem *mem) {
2722c593315Sopenharmony_ci  nghttp2_ext_priority_update *priority_update;
2732c593315Sopenharmony_ci
2742c593315Sopenharmony_ci  priority_update = frame->payload;
2752c593315Sopenharmony_ci  if (priority_update == NULL) {
2762c593315Sopenharmony_ci    return;
2772c593315Sopenharmony_ci  }
2782c593315Sopenharmony_ci  nghttp2_mem_free(mem, priority_update->field_value);
2792c593315Sopenharmony_ci}
2802c593315Sopenharmony_ci
2812c593315Sopenharmony_cisize_t nghttp2_frame_priority_len(uint8_t flags) {
2822c593315Sopenharmony_ci  if (flags & NGHTTP2_FLAG_PRIORITY) {
2832c593315Sopenharmony_ci    return NGHTTP2_PRIORITY_SPECLEN;
2842c593315Sopenharmony_ci  }
2852c593315Sopenharmony_ci
2862c593315Sopenharmony_ci  return 0;
2872c593315Sopenharmony_ci}
2882c593315Sopenharmony_ci
2892c593315Sopenharmony_cisize_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame) {
2902c593315Sopenharmony_ci  return nghttp2_frame_priority_len(frame->hd.flags);
2912c593315Sopenharmony_ci}
2922c593315Sopenharmony_ci
2932c593315Sopenharmony_ci/*
2942c593315Sopenharmony_ci * Call this function after payload was serialized, but not before
2952c593315Sopenharmony_ci * changing buf->pos and serializing frame header.
2962c593315Sopenharmony_ci *
2972c593315Sopenharmony_ci * This function assumes bufs->cur points to the last buf chain of the
2982c593315Sopenharmony_ci * frame(s).
2992c593315Sopenharmony_ci *
3002c593315Sopenharmony_ci * This function serializes frame header for HEADERS/PUSH_PROMISE and
3012c593315Sopenharmony_ci * handles their successive CONTINUATION frames.
3022c593315Sopenharmony_ci *
3032c593315Sopenharmony_ci * We don't process any padding here.
3042c593315Sopenharmony_ci */
3052c593315Sopenharmony_cistatic int frame_pack_headers_shared(nghttp2_bufs *bufs,
3062c593315Sopenharmony_ci                                     nghttp2_frame_hd *frame_hd) {
3072c593315Sopenharmony_ci  nghttp2_buf *buf;
3082c593315Sopenharmony_ci  nghttp2_buf_chain *ci, *ce;
3092c593315Sopenharmony_ci  nghttp2_frame_hd hd;
3102c593315Sopenharmony_ci
3112c593315Sopenharmony_ci  buf = &bufs->head->buf;
3122c593315Sopenharmony_ci
3132c593315Sopenharmony_ci  hd = *frame_hd;
3142c593315Sopenharmony_ci  hd.length = nghttp2_buf_len(buf);
3152c593315Sopenharmony_ci
3162c593315Sopenharmony_ci  DEBUGF("send: HEADERS/PUSH_PROMISE, payloadlen=%zu\n", hd.length);
3172c593315Sopenharmony_ci
3182c593315Sopenharmony_ci  /* We have multiple frame buffers, which means one or more
3192c593315Sopenharmony_ci     CONTINUATION frame is involved. Remove END_HEADERS flag from the
3202c593315Sopenharmony_ci     first frame. */
3212c593315Sopenharmony_ci  if (bufs->head != bufs->cur) {
3222c593315Sopenharmony_ci    hd.flags = (uint8_t)(hd.flags & ~NGHTTP2_FLAG_END_HEADERS);
3232c593315Sopenharmony_ci  }
3242c593315Sopenharmony_ci
3252c593315Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
3262c593315Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &hd);
3272c593315Sopenharmony_ci
3282c593315Sopenharmony_ci  if (bufs->head != bufs->cur) {
3292c593315Sopenharmony_ci    /* 2nd and later frames are CONTINUATION frames. */
3302c593315Sopenharmony_ci    hd.type = NGHTTP2_CONTINUATION;
3312c593315Sopenharmony_ci    /* We don't have no flags except for last CONTINUATION */
3322c593315Sopenharmony_ci    hd.flags = NGHTTP2_FLAG_NONE;
3332c593315Sopenharmony_ci
3342c593315Sopenharmony_ci    ce = bufs->cur;
3352c593315Sopenharmony_ci
3362c593315Sopenharmony_ci    for (ci = bufs->head->next; ci != ce; ci = ci->next) {
3372c593315Sopenharmony_ci      buf = &ci->buf;
3382c593315Sopenharmony_ci
3392c593315Sopenharmony_ci      hd.length = nghttp2_buf_len(buf);
3402c593315Sopenharmony_ci
3412c593315Sopenharmony_ci      DEBUGF("send: int CONTINUATION, payloadlen=%zu\n", hd.length);
3422c593315Sopenharmony_ci
3432c593315Sopenharmony_ci      buf->pos -= NGHTTP2_FRAME_HDLEN;
3442c593315Sopenharmony_ci      nghttp2_frame_pack_frame_hd(buf->pos, &hd);
3452c593315Sopenharmony_ci    }
3462c593315Sopenharmony_ci
3472c593315Sopenharmony_ci    buf = &ci->buf;
3482c593315Sopenharmony_ci    hd.length = nghttp2_buf_len(buf);
3492c593315Sopenharmony_ci    /* Set END_HEADERS flag for last CONTINUATION */
3502c593315Sopenharmony_ci    hd.flags = NGHTTP2_FLAG_END_HEADERS;
3512c593315Sopenharmony_ci
3522c593315Sopenharmony_ci    DEBUGF("send: last CONTINUATION, payloadlen=%zu\n", hd.length);
3532c593315Sopenharmony_ci
3542c593315Sopenharmony_ci    buf->pos -= NGHTTP2_FRAME_HDLEN;
3552c593315Sopenharmony_ci    nghttp2_frame_pack_frame_hd(buf->pos, &hd);
3562c593315Sopenharmony_ci  }
3572c593315Sopenharmony_ci
3582c593315Sopenharmony_ci  return 0;
3592c593315Sopenharmony_ci}
3602c593315Sopenharmony_ci
3612c593315Sopenharmony_ciint nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
3622c593315Sopenharmony_ci                               nghttp2_hd_deflater *deflater) {
3632c593315Sopenharmony_ci  size_t nv_offset;
3642c593315Sopenharmony_ci  int rv;
3652c593315Sopenharmony_ci  nghttp2_buf *buf;
3662c593315Sopenharmony_ci
3672c593315Sopenharmony_ci  assert(bufs->head == bufs->cur);
3682c593315Sopenharmony_ci
3692c593315Sopenharmony_ci  nv_offset = nghttp2_frame_headers_payload_nv_offset(frame);
3702c593315Sopenharmony_ci
3712c593315Sopenharmony_ci  buf = &bufs->cur->buf;
3722c593315Sopenharmony_ci
3732c593315Sopenharmony_ci  buf->pos += nv_offset;
3742c593315Sopenharmony_ci  buf->last = buf->pos;
3752c593315Sopenharmony_ci
3762c593315Sopenharmony_ci  /* This call will adjust buf->last to the correct position */
3772c593315Sopenharmony_ci  rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen);
3782c593315Sopenharmony_ci
3792c593315Sopenharmony_ci  if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
3802c593315Sopenharmony_ci    rv = NGHTTP2_ERR_HEADER_COMP;
3812c593315Sopenharmony_ci  }
3822c593315Sopenharmony_ci
3832c593315Sopenharmony_ci  buf->pos -= nv_offset;
3842c593315Sopenharmony_ci
3852c593315Sopenharmony_ci  if (rv != 0) {
3862c593315Sopenharmony_ci    return rv;
3872c593315Sopenharmony_ci  }
3882c593315Sopenharmony_ci
3892c593315Sopenharmony_ci  if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
3902c593315Sopenharmony_ci    nghttp2_frame_pack_priority_spec(buf->pos, &frame->pri_spec);
3912c593315Sopenharmony_ci  }
3922c593315Sopenharmony_ci
3932c593315Sopenharmony_ci  frame->padlen = 0;
3942c593315Sopenharmony_ci  frame->hd.length = nghttp2_bufs_len(bufs);
3952c593315Sopenharmony_ci
3962c593315Sopenharmony_ci  return frame_pack_headers_shared(bufs, &frame->hd);
3972c593315Sopenharmony_ci}
3982c593315Sopenharmony_ci
3992c593315Sopenharmony_civoid nghttp2_frame_pack_priority_spec(uint8_t *buf,
4002c593315Sopenharmony_ci                                      const nghttp2_priority_spec *pri_spec) {
4012c593315Sopenharmony_ci  nghttp2_put_uint32be(buf, (uint32_t)pri_spec->stream_id);
4022c593315Sopenharmony_ci  if (pri_spec->exclusive) {
4032c593315Sopenharmony_ci    buf[0] |= 0x80;
4042c593315Sopenharmony_ci  }
4052c593315Sopenharmony_ci  buf[4] = (uint8_t)(pri_spec->weight - 1);
4062c593315Sopenharmony_ci}
4072c593315Sopenharmony_ci
4082c593315Sopenharmony_civoid nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
4092c593315Sopenharmony_ci                                        const uint8_t *payload) {
4102c593315Sopenharmony_ci  int32_t dep_stream_id;
4112c593315Sopenharmony_ci  uint8_t exclusive;
4122c593315Sopenharmony_ci  int32_t weight;
4132c593315Sopenharmony_ci
4142c593315Sopenharmony_ci  dep_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
4152c593315Sopenharmony_ci  exclusive = (payload[0] & 0x80) > 0;
4162c593315Sopenharmony_ci  weight = payload[4] + 1;
4172c593315Sopenharmony_ci
4182c593315Sopenharmony_ci  nghttp2_priority_spec_init(pri_spec, dep_stream_id, weight, exclusive);
4192c593315Sopenharmony_ci}
4202c593315Sopenharmony_ci
4212c593315Sopenharmony_civoid nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
4222c593315Sopenharmony_ci                                          const uint8_t *payload) {
4232c593315Sopenharmony_ci  if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
4242c593315Sopenharmony_ci    nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload);
4252c593315Sopenharmony_ci  } else {
4262c593315Sopenharmony_ci    nghttp2_priority_spec_default_init(&frame->pri_spec);
4272c593315Sopenharmony_ci  }
4282c593315Sopenharmony_ci
4292c593315Sopenharmony_ci  frame->nva = NULL;
4302c593315Sopenharmony_ci  frame->nvlen = 0;
4312c593315Sopenharmony_ci}
4322c593315Sopenharmony_ci
4332c593315Sopenharmony_civoid nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) {
4342c593315Sopenharmony_ci  nghttp2_buf *buf;
4352c593315Sopenharmony_ci
4362c593315Sopenharmony_ci  assert(bufs->head == bufs->cur);
4372c593315Sopenharmony_ci
4382c593315Sopenharmony_ci  buf = &bufs->head->buf;
4392c593315Sopenharmony_ci
4402c593315Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >= NGHTTP2_PRIORITY_SPECLEN);
4412c593315Sopenharmony_ci
4422c593315Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
4432c593315Sopenharmony_ci
4442c593315Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
4452c593315Sopenharmony_ci
4462c593315Sopenharmony_ci  nghttp2_frame_pack_priority_spec(buf->last, &frame->pri_spec);
4472c593315Sopenharmony_ci
4482c593315Sopenharmony_ci  buf->last += NGHTTP2_PRIORITY_SPECLEN;
4492c593315Sopenharmony_ci}
4502c593315Sopenharmony_ci
4512c593315Sopenharmony_civoid nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
4522c593315Sopenharmony_ci                                           const uint8_t *payload) {
4532c593315Sopenharmony_ci  nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload);
4542c593315Sopenharmony_ci}
4552c593315Sopenharmony_ci
4562c593315Sopenharmony_civoid nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
4572c593315Sopenharmony_ci                                   nghttp2_rst_stream *frame) {
4582c593315Sopenharmony_ci  nghttp2_buf *buf;
4592c593315Sopenharmony_ci
4602c593315Sopenharmony_ci  assert(bufs->head == bufs->cur);
4612c593315Sopenharmony_ci
4622c593315Sopenharmony_ci  buf = &bufs->head->buf;
4632c593315Sopenharmony_ci
4642c593315Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >= 4);
4652c593315Sopenharmony_ci
4662c593315Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
4672c593315Sopenharmony_ci
4682c593315Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
4692c593315Sopenharmony_ci
4702c593315Sopenharmony_ci  nghttp2_put_uint32be(buf->last, frame->error_code);
4712c593315Sopenharmony_ci  buf->last += 4;
4722c593315Sopenharmony_ci}
4732c593315Sopenharmony_ci
4742c593315Sopenharmony_civoid nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
4752c593315Sopenharmony_ci                                             const uint8_t *payload) {
4762c593315Sopenharmony_ci  frame->error_code = nghttp2_get_uint32(payload);
4772c593315Sopenharmony_ci}
4782c593315Sopenharmony_ci
4792c593315Sopenharmony_ciint nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame) {
4802c593315Sopenharmony_ci  nghttp2_buf *buf;
4812c593315Sopenharmony_ci
4822c593315Sopenharmony_ci  assert(bufs->head == bufs->cur);
4832c593315Sopenharmony_ci
4842c593315Sopenharmony_ci  buf = &bufs->head->buf;
4852c593315Sopenharmony_ci
4862c593315Sopenharmony_ci  if (nghttp2_buf_avail(buf) < frame->hd.length) {
4872c593315Sopenharmony_ci    return NGHTTP2_ERR_FRAME_SIZE_ERROR;
4882c593315Sopenharmony_ci  }
4892c593315Sopenharmony_ci
4902c593315Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
4912c593315Sopenharmony_ci
4922c593315Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
4932c593315Sopenharmony_ci
4942c593315Sopenharmony_ci  buf->last +=
4952c593315Sopenharmony_ci      nghttp2_frame_pack_settings_payload(buf->last, frame->iv, frame->niv);
4962c593315Sopenharmony_ci
4972c593315Sopenharmony_ci  return 0;
4982c593315Sopenharmony_ci}
4992c593315Sopenharmony_ci
5002c593315Sopenharmony_cisize_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
5012c593315Sopenharmony_ci                                           const nghttp2_settings_entry *iv,
5022c593315Sopenharmony_ci                                           size_t niv) {
5032c593315Sopenharmony_ci  size_t i;
5042c593315Sopenharmony_ci  for (i = 0; i < niv; ++i, buf += NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) {
5052c593315Sopenharmony_ci    nghttp2_put_uint16be(buf, (uint16_t)iv[i].settings_id);
5062c593315Sopenharmony_ci    nghttp2_put_uint32be(buf + 2, iv[i].value);
5072c593315Sopenharmony_ci  }
5082c593315Sopenharmony_ci  return NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH * niv;
5092c593315Sopenharmony_ci}
5102c593315Sopenharmony_ci
5112c593315Sopenharmony_civoid nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
5122c593315Sopenharmony_ci                                           nghttp2_settings_entry *iv,
5132c593315Sopenharmony_ci                                           size_t niv) {
5142c593315Sopenharmony_ci  frame->iv = iv;
5152c593315Sopenharmony_ci  frame->niv = niv;
5162c593315Sopenharmony_ci}
5172c593315Sopenharmony_ci
5182c593315Sopenharmony_civoid nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
5192c593315Sopenharmony_ci                                         const uint8_t *payload) {
5202c593315Sopenharmony_ci  iv->settings_id = nghttp2_get_uint16(&payload[0]);
5212c593315Sopenharmony_ci  iv->value = nghttp2_get_uint32(&payload[2]);
5222c593315Sopenharmony_ci}
5232c593315Sopenharmony_ci
5242c593315Sopenharmony_ciint nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
5252c593315Sopenharmony_ci                                           size_t *niv_ptr,
5262c593315Sopenharmony_ci                                           const uint8_t *payload,
5272c593315Sopenharmony_ci                                           size_t payloadlen,
5282c593315Sopenharmony_ci                                           nghttp2_mem *mem) {
5292c593315Sopenharmony_ci  size_t i;
5302c593315Sopenharmony_ci
5312c593315Sopenharmony_ci  *niv_ptr = payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH;
5322c593315Sopenharmony_ci
5332c593315Sopenharmony_ci  if (*niv_ptr == 0) {
5342c593315Sopenharmony_ci    *iv_ptr = NULL;
5352c593315Sopenharmony_ci
5362c593315Sopenharmony_ci    return 0;
5372c593315Sopenharmony_ci  }
5382c593315Sopenharmony_ci
5392c593315Sopenharmony_ci  *iv_ptr =
5402c593315Sopenharmony_ci      nghttp2_mem_malloc(mem, (*niv_ptr) * sizeof(nghttp2_settings_entry));
5412c593315Sopenharmony_ci
5422c593315Sopenharmony_ci  if (*iv_ptr == NULL) {
5432c593315Sopenharmony_ci    return NGHTTP2_ERR_NOMEM;
5442c593315Sopenharmony_ci  }
5452c593315Sopenharmony_ci
5462c593315Sopenharmony_ci  for (i = 0; i < *niv_ptr; ++i) {
5472c593315Sopenharmony_ci    size_t off = i * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH;
5482c593315Sopenharmony_ci    nghttp2_frame_unpack_settings_entry(&(*iv_ptr)[i], &payload[off]);
5492c593315Sopenharmony_ci  }
5502c593315Sopenharmony_ci
5512c593315Sopenharmony_ci  return 0;
5522c593315Sopenharmony_ci}
5532c593315Sopenharmony_ci
5542c593315Sopenharmony_ciint nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
5552c593315Sopenharmony_ci                                    nghttp2_push_promise *frame,
5562c593315Sopenharmony_ci                                    nghttp2_hd_deflater *deflater) {
5572c593315Sopenharmony_ci  size_t nv_offset = 4;
5582c593315Sopenharmony_ci  int rv;
5592c593315Sopenharmony_ci  nghttp2_buf *buf;
5602c593315Sopenharmony_ci
5612c593315Sopenharmony_ci  assert(bufs->head == bufs->cur);
5622c593315Sopenharmony_ci
5632c593315Sopenharmony_ci  buf = &bufs->cur->buf;
5642c593315Sopenharmony_ci
5652c593315Sopenharmony_ci  buf->pos += nv_offset;
5662c593315Sopenharmony_ci  buf->last = buf->pos;
5672c593315Sopenharmony_ci
5682c593315Sopenharmony_ci  /* This call will adjust buf->last to the correct position */
5692c593315Sopenharmony_ci  rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen);
5702c593315Sopenharmony_ci
5712c593315Sopenharmony_ci  if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
5722c593315Sopenharmony_ci    rv = NGHTTP2_ERR_HEADER_COMP;
5732c593315Sopenharmony_ci  }
5742c593315Sopenharmony_ci
5752c593315Sopenharmony_ci  buf->pos -= nv_offset;
5762c593315Sopenharmony_ci
5772c593315Sopenharmony_ci  if (rv != 0) {
5782c593315Sopenharmony_ci    return rv;
5792c593315Sopenharmony_ci  }
5802c593315Sopenharmony_ci
5812c593315Sopenharmony_ci  nghttp2_put_uint32be(buf->pos, (uint32_t)frame->promised_stream_id);
5822c593315Sopenharmony_ci
5832c593315Sopenharmony_ci  frame->padlen = 0;
5842c593315Sopenharmony_ci  frame->hd.length = nghttp2_bufs_len(bufs);
5852c593315Sopenharmony_ci
5862c593315Sopenharmony_ci  return frame_pack_headers_shared(bufs, &frame->hd);
5872c593315Sopenharmony_ci}
5882c593315Sopenharmony_ci
5892c593315Sopenharmony_civoid nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
5902c593315Sopenharmony_ci                                               const uint8_t *payload) {
5912c593315Sopenharmony_ci  frame->promised_stream_id =
5922c593315Sopenharmony_ci      nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
5932c593315Sopenharmony_ci  frame->nva = NULL;
5942c593315Sopenharmony_ci  frame->nvlen = 0;
5952c593315Sopenharmony_ci}
5962c593315Sopenharmony_ci
5972c593315Sopenharmony_civoid nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) {
5982c593315Sopenharmony_ci  nghttp2_buf *buf;
5992c593315Sopenharmony_ci
6002c593315Sopenharmony_ci  assert(bufs->head == bufs->cur);
6012c593315Sopenharmony_ci
6022c593315Sopenharmony_ci  buf = &bufs->head->buf;
6032c593315Sopenharmony_ci
6042c593315Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >= 8);
6052c593315Sopenharmony_ci
6062c593315Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
6072c593315Sopenharmony_ci
6082c593315Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
6092c593315Sopenharmony_ci
6102c593315Sopenharmony_ci  buf->last =
6112c593315Sopenharmony_ci      nghttp2_cpymem(buf->last, frame->opaque_data, sizeof(frame->opaque_data));
6122c593315Sopenharmony_ci}
6132c593315Sopenharmony_ci
6142c593315Sopenharmony_civoid nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
6152c593315Sopenharmony_ci                                       const uint8_t *payload) {
6162c593315Sopenharmony_ci  memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data));
6172c593315Sopenharmony_ci}
6182c593315Sopenharmony_ci
6192c593315Sopenharmony_ciint nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame) {
6202c593315Sopenharmony_ci  int rv;
6212c593315Sopenharmony_ci  nghttp2_buf *buf;
6222c593315Sopenharmony_ci
6232c593315Sopenharmony_ci  assert(bufs->head == bufs->cur);
6242c593315Sopenharmony_ci
6252c593315Sopenharmony_ci  buf = &bufs->head->buf;
6262c593315Sopenharmony_ci
6272c593315Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
6282c593315Sopenharmony_ci
6292c593315Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
6302c593315Sopenharmony_ci
6312c593315Sopenharmony_ci  nghttp2_put_uint32be(buf->last, (uint32_t)frame->last_stream_id);
6322c593315Sopenharmony_ci  buf->last += 4;
6332c593315Sopenharmony_ci
6342c593315Sopenharmony_ci  nghttp2_put_uint32be(buf->last, frame->error_code);
6352c593315Sopenharmony_ci  buf->last += 4;
6362c593315Sopenharmony_ci
6372c593315Sopenharmony_ci  rv = nghttp2_bufs_add(bufs, frame->opaque_data, frame->opaque_data_len);
6382c593315Sopenharmony_ci
6392c593315Sopenharmony_ci  if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
6402c593315Sopenharmony_ci    return NGHTTP2_ERR_FRAME_SIZE_ERROR;
6412c593315Sopenharmony_ci  }
6422c593315Sopenharmony_ci
6432c593315Sopenharmony_ci  if (rv != 0) {
6442c593315Sopenharmony_ci    return rv;
6452c593315Sopenharmony_ci  }
6462c593315Sopenharmony_ci
6472c593315Sopenharmony_ci  return 0;
6482c593315Sopenharmony_ci}
6492c593315Sopenharmony_ci
6502c593315Sopenharmony_civoid nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
6512c593315Sopenharmony_ci                                         const uint8_t *payload,
6522c593315Sopenharmony_ci                                         uint8_t *var_gift_payload,
6532c593315Sopenharmony_ci                                         size_t var_gift_payloadlen) {
6542c593315Sopenharmony_ci  frame->last_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
6552c593315Sopenharmony_ci  frame->error_code = nghttp2_get_uint32(payload + 4);
6562c593315Sopenharmony_ci
6572c593315Sopenharmony_ci  frame->opaque_data = var_gift_payload;
6582c593315Sopenharmony_ci  frame->opaque_data_len = var_gift_payloadlen;
6592c593315Sopenharmony_ci}
6602c593315Sopenharmony_ci
6612c593315Sopenharmony_ciint nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
6622c593315Sopenharmony_ci                                         const uint8_t *payload,
6632c593315Sopenharmony_ci                                         size_t payloadlen, nghttp2_mem *mem) {
6642c593315Sopenharmony_ci  uint8_t *var_gift_payload;
6652c593315Sopenharmony_ci  size_t var_gift_payloadlen;
6662c593315Sopenharmony_ci
6672c593315Sopenharmony_ci  if (payloadlen > 8) {
6682c593315Sopenharmony_ci    var_gift_payloadlen = payloadlen - 8;
6692c593315Sopenharmony_ci  } else {
6702c593315Sopenharmony_ci    var_gift_payloadlen = 0;
6712c593315Sopenharmony_ci  }
6722c593315Sopenharmony_ci
6732c593315Sopenharmony_ci  if (!var_gift_payloadlen) {
6742c593315Sopenharmony_ci    var_gift_payload = NULL;
6752c593315Sopenharmony_ci  } else {
6762c593315Sopenharmony_ci    var_gift_payload = nghttp2_mem_malloc(mem, var_gift_payloadlen);
6772c593315Sopenharmony_ci
6782c593315Sopenharmony_ci    if (var_gift_payload == NULL) {
6792c593315Sopenharmony_ci      return NGHTTP2_ERR_NOMEM;
6802c593315Sopenharmony_ci    }
6812c593315Sopenharmony_ci
6822c593315Sopenharmony_ci    memcpy(var_gift_payload, payload + 8, var_gift_payloadlen);
6832c593315Sopenharmony_ci  }
6842c593315Sopenharmony_ci
6852c593315Sopenharmony_ci  nghttp2_frame_unpack_goaway_payload(frame, payload, var_gift_payload,
6862c593315Sopenharmony_ci                                      var_gift_payloadlen);
6872c593315Sopenharmony_ci
6882c593315Sopenharmony_ci  return 0;
6892c593315Sopenharmony_ci}
6902c593315Sopenharmony_ci
6912c593315Sopenharmony_civoid nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
6922c593315Sopenharmony_ci                                      nghttp2_window_update *frame) {
6932c593315Sopenharmony_ci  nghttp2_buf *buf;
6942c593315Sopenharmony_ci
6952c593315Sopenharmony_ci  assert(bufs->head == bufs->cur);
6962c593315Sopenharmony_ci
6972c593315Sopenharmony_ci  buf = &bufs->head->buf;
6982c593315Sopenharmony_ci
6992c593315Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >= 4);
7002c593315Sopenharmony_ci
7012c593315Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
7022c593315Sopenharmony_ci
7032c593315Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
7042c593315Sopenharmony_ci
7052c593315Sopenharmony_ci  nghttp2_put_uint32be(buf->last, (uint32_t)frame->window_size_increment);
7062c593315Sopenharmony_ci  buf->last += 4;
7072c593315Sopenharmony_ci}
7082c593315Sopenharmony_ci
7092c593315Sopenharmony_civoid nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
7102c593315Sopenharmony_ci                                                const uint8_t *payload) {
7112c593315Sopenharmony_ci  frame->window_size_increment =
7122c593315Sopenharmony_ci      nghttp2_get_uint32(payload) & NGHTTP2_WINDOW_SIZE_INCREMENT_MASK;
7132c593315Sopenharmony_ci}
7142c593315Sopenharmony_ci
7152c593315Sopenharmony_civoid nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) {
7162c593315Sopenharmony_ci  int rv;
7172c593315Sopenharmony_ci  nghttp2_buf *buf;
7182c593315Sopenharmony_ci  nghttp2_ext_altsvc *altsvc;
7192c593315Sopenharmony_ci
7202c593315Sopenharmony_ci  /* This is required with --disable-assert. */
7212c593315Sopenharmony_ci  (void)rv;
7222c593315Sopenharmony_ci
7232c593315Sopenharmony_ci  altsvc = frame->payload;
7242c593315Sopenharmony_ci
7252c593315Sopenharmony_ci  buf = &bufs->head->buf;
7262c593315Sopenharmony_ci
7272c593315Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >=
7282c593315Sopenharmony_ci         2 + altsvc->origin_len + altsvc->field_value_len);
7292c593315Sopenharmony_ci
7302c593315Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
7312c593315Sopenharmony_ci
7322c593315Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
7332c593315Sopenharmony_ci
7342c593315Sopenharmony_ci  nghttp2_put_uint16be(buf->last, (uint16_t)altsvc->origin_len);
7352c593315Sopenharmony_ci  buf->last += 2;
7362c593315Sopenharmony_ci
7372c593315Sopenharmony_ci  rv = nghttp2_bufs_add(bufs, altsvc->origin, altsvc->origin_len);
7382c593315Sopenharmony_ci
7392c593315Sopenharmony_ci  assert(rv == 0);
7402c593315Sopenharmony_ci
7412c593315Sopenharmony_ci  rv = nghttp2_bufs_add(bufs, altsvc->field_value, altsvc->field_value_len);
7422c593315Sopenharmony_ci
7432c593315Sopenharmony_ci  assert(rv == 0);
7442c593315Sopenharmony_ci}
7452c593315Sopenharmony_ci
7462c593315Sopenharmony_civoid nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
7472c593315Sopenharmony_ci                                         size_t origin_len, uint8_t *payload,
7482c593315Sopenharmony_ci                                         size_t payloadlen) {
7492c593315Sopenharmony_ci  nghttp2_ext_altsvc *altsvc;
7502c593315Sopenharmony_ci  uint8_t *p;
7512c593315Sopenharmony_ci
7522c593315Sopenharmony_ci  altsvc = frame->payload;
7532c593315Sopenharmony_ci  p = payload;
7542c593315Sopenharmony_ci
7552c593315Sopenharmony_ci  altsvc->origin = p;
7562c593315Sopenharmony_ci
7572c593315Sopenharmony_ci  p += origin_len;
7582c593315Sopenharmony_ci
7592c593315Sopenharmony_ci  altsvc->origin_len = origin_len;
7602c593315Sopenharmony_ci
7612c593315Sopenharmony_ci  altsvc->field_value = p;
7622c593315Sopenharmony_ci  altsvc->field_value_len = (size_t)(payload + payloadlen - p);
7632c593315Sopenharmony_ci}
7642c593315Sopenharmony_ci
7652c593315Sopenharmony_ciint nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame,
7662c593315Sopenharmony_ci                                         const uint8_t *payload,
7672c593315Sopenharmony_ci                                         size_t payloadlen, nghttp2_mem *mem) {
7682c593315Sopenharmony_ci  uint8_t *buf;
7692c593315Sopenharmony_ci  size_t origin_len;
7702c593315Sopenharmony_ci
7712c593315Sopenharmony_ci  if (payloadlen < 2) {
7722c593315Sopenharmony_ci    return NGHTTP2_FRAME_SIZE_ERROR;
7732c593315Sopenharmony_ci  }
7742c593315Sopenharmony_ci
7752c593315Sopenharmony_ci  origin_len = nghttp2_get_uint16(payload);
7762c593315Sopenharmony_ci
7772c593315Sopenharmony_ci  buf = nghttp2_mem_malloc(mem, payloadlen - 2);
7782c593315Sopenharmony_ci  if (!buf) {
7792c593315Sopenharmony_ci    return NGHTTP2_ERR_NOMEM;
7802c593315Sopenharmony_ci  }
7812c593315Sopenharmony_ci
7822c593315Sopenharmony_ci  nghttp2_cpymem(buf, payload + 2, payloadlen - 2);
7832c593315Sopenharmony_ci
7842c593315Sopenharmony_ci  nghttp2_frame_unpack_altsvc_payload(frame, origin_len, buf, payloadlen - 2);
7852c593315Sopenharmony_ci
7862c593315Sopenharmony_ci  return 0;
7872c593315Sopenharmony_ci}
7882c593315Sopenharmony_ci
7892c593315Sopenharmony_ciint nghttp2_frame_pack_origin(nghttp2_bufs *bufs, nghttp2_extension *frame) {
7902c593315Sopenharmony_ci  nghttp2_buf *buf;
7912c593315Sopenharmony_ci  nghttp2_ext_origin *origin;
7922c593315Sopenharmony_ci  nghttp2_origin_entry *orig;
7932c593315Sopenharmony_ci  size_t i;
7942c593315Sopenharmony_ci
7952c593315Sopenharmony_ci  origin = frame->payload;
7962c593315Sopenharmony_ci
7972c593315Sopenharmony_ci  buf = &bufs->head->buf;
7982c593315Sopenharmony_ci
7992c593315Sopenharmony_ci  if (nghttp2_buf_avail(buf) < frame->hd.length) {
8002c593315Sopenharmony_ci    return NGHTTP2_ERR_FRAME_SIZE_ERROR;
8012c593315Sopenharmony_ci  }
8022c593315Sopenharmony_ci
8032c593315Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
8042c593315Sopenharmony_ci
8052c593315Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
8062c593315Sopenharmony_ci
8072c593315Sopenharmony_ci  for (i = 0; i < origin->nov; ++i) {
8082c593315Sopenharmony_ci    orig = &origin->ov[i];
8092c593315Sopenharmony_ci    nghttp2_put_uint16be(buf->last, (uint16_t)orig->origin_len);
8102c593315Sopenharmony_ci    buf->last += 2;
8112c593315Sopenharmony_ci    buf->last = nghttp2_cpymem(buf->last, orig->origin, orig->origin_len);
8122c593315Sopenharmony_ci  }
8132c593315Sopenharmony_ci
8142c593315Sopenharmony_ci  assert(nghttp2_buf_len(buf) == NGHTTP2_FRAME_HDLEN + frame->hd.length);
8152c593315Sopenharmony_ci
8162c593315Sopenharmony_ci  return 0;
8172c593315Sopenharmony_ci}
8182c593315Sopenharmony_ci
8192c593315Sopenharmony_ciint nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
8202c593315Sopenharmony_ci                                        const uint8_t *payload,
8212c593315Sopenharmony_ci                                        size_t payloadlen, nghttp2_mem *mem) {
8222c593315Sopenharmony_ci  nghttp2_ext_origin *origin;
8232c593315Sopenharmony_ci  const uint8_t *p, *end;
8242c593315Sopenharmony_ci  uint8_t *dst;
8252c593315Sopenharmony_ci  size_t originlen;
8262c593315Sopenharmony_ci  nghttp2_origin_entry *ov;
8272c593315Sopenharmony_ci  size_t nov = 0;
8282c593315Sopenharmony_ci  size_t len = 0;
8292c593315Sopenharmony_ci
8302c593315Sopenharmony_ci  origin = frame->payload;
8312c593315Sopenharmony_ci  p = end = payload;
8322c593315Sopenharmony_ci  if (payloadlen) {
8332c593315Sopenharmony_ci    end += payloadlen;
8342c593315Sopenharmony_ci  }
8352c593315Sopenharmony_ci
8362c593315Sopenharmony_ci  for (; p != end;) {
8372c593315Sopenharmony_ci    if (end - p < 2) {
8382c593315Sopenharmony_ci      return NGHTTP2_ERR_FRAME_SIZE_ERROR;
8392c593315Sopenharmony_ci    }
8402c593315Sopenharmony_ci    originlen = nghttp2_get_uint16(p);
8412c593315Sopenharmony_ci    p += 2;
8422c593315Sopenharmony_ci    if (originlen == 0) {
8432c593315Sopenharmony_ci      continue;
8442c593315Sopenharmony_ci    }
8452c593315Sopenharmony_ci    if (originlen > (size_t)(end - p)) {
8462c593315Sopenharmony_ci      return NGHTTP2_ERR_FRAME_SIZE_ERROR;
8472c593315Sopenharmony_ci    }
8482c593315Sopenharmony_ci    p += originlen;
8492c593315Sopenharmony_ci    /* 1 for terminal NULL */
8502c593315Sopenharmony_ci    len += originlen + 1;
8512c593315Sopenharmony_ci    ++nov;
8522c593315Sopenharmony_ci  }
8532c593315Sopenharmony_ci
8542c593315Sopenharmony_ci  if (nov == 0) {
8552c593315Sopenharmony_ci    origin->ov = NULL;
8562c593315Sopenharmony_ci    origin->nov = 0;
8572c593315Sopenharmony_ci
8582c593315Sopenharmony_ci    return 0;
8592c593315Sopenharmony_ci  }
8602c593315Sopenharmony_ci
8612c593315Sopenharmony_ci  len += nov * sizeof(nghttp2_origin_entry);
8622c593315Sopenharmony_ci
8632c593315Sopenharmony_ci  ov = nghttp2_mem_malloc(mem, len);
8642c593315Sopenharmony_ci  if (ov == NULL) {
8652c593315Sopenharmony_ci    return NGHTTP2_ERR_NOMEM;
8662c593315Sopenharmony_ci  }
8672c593315Sopenharmony_ci
8682c593315Sopenharmony_ci  origin->ov = ov;
8692c593315Sopenharmony_ci  origin->nov = nov;
8702c593315Sopenharmony_ci
8712c593315Sopenharmony_ci  dst = (uint8_t *)ov + nov * sizeof(nghttp2_origin_entry);
8722c593315Sopenharmony_ci  p = payload;
8732c593315Sopenharmony_ci
8742c593315Sopenharmony_ci  for (; p != end;) {
8752c593315Sopenharmony_ci    originlen = nghttp2_get_uint16(p);
8762c593315Sopenharmony_ci    p += 2;
8772c593315Sopenharmony_ci    if (originlen == 0) {
8782c593315Sopenharmony_ci      continue;
8792c593315Sopenharmony_ci    }
8802c593315Sopenharmony_ci    ov->origin = dst;
8812c593315Sopenharmony_ci    ov->origin_len = originlen;
8822c593315Sopenharmony_ci    dst = nghttp2_cpymem(dst, p, originlen);
8832c593315Sopenharmony_ci    *dst++ = '\0';
8842c593315Sopenharmony_ci    p += originlen;
8852c593315Sopenharmony_ci    ++ov;
8862c593315Sopenharmony_ci  }
8872c593315Sopenharmony_ci
8882c593315Sopenharmony_ci  return 0;
8892c593315Sopenharmony_ci}
8902c593315Sopenharmony_ci
8912c593315Sopenharmony_civoid nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
8922c593315Sopenharmony_ci                                        nghttp2_extension *frame) {
8932c593315Sopenharmony_ci  int rv;
8942c593315Sopenharmony_ci  nghttp2_buf *buf;
8952c593315Sopenharmony_ci  nghttp2_ext_priority_update *priority_update;
8962c593315Sopenharmony_ci
8972c593315Sopenharmony_ci  /* This is required with --disable-assert. */
8982c593315Sopenharmony_ci  (void)rv;
8992c593315Sopenharmony_ci
9002c593315Sopenharmony_ci  priority_update = frame->payload;
9012c593315Sopenharmony_ci
9022c593315Sopenharmony_ci  buf = &bufs->head->buf;
9032c593315Sopenharmony_ci
9042c593315Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >= 4 + priority_update->field_value_len);
9052c593315Sopenharmony_ci
9062c593315Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
9072c593315Sopenharmony_ci
9082c593315Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
9092c593315Sopenharmony_ci
9102c593315Sopenharmony_ci  nghttp2_put_uint32be(buf->last, (uint32_t)priority_update->stream_id);
9112c593315Sopenharmony_ci  buf->last += 4;
9122c593315Sopenharmony_ci
9132c593315Sopenharmony_ci  rv = nghttp2_bufs_add(bufs, priority_update->field_value,
9142c593315Sopenharmony_ci                        priority_update->field_value_len);
9152c593315Sopenharmony_ci
9162c593315Sopenharmony_ci  assert(rv == 0);
9172c593315Sopenharmony_ci}
9182c593315Sopenharmony_ci
9192c593315Sopenharmony_civoid nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
9202c593315Sopenharmony_ci                                                  uint8_t *payload,
9212c593315Sopenharmony_ci                                                  size_t payloadlen) {
9222c593315Sopenharmony_ci  nghttp2_ext_priority_update *priority_update;
9232c593315Sopenharmony_ci
9242c593315Sopenharmony_ci  assert(payloadlen >= 4);
9252c593315Sopenharmony_ci
9262c593315Sopenharmony_ci  priority_update = frame->payload;
9272c593315Sopenharmony_ci
9282c593315Sopenharmony_ci  priority_update->stream_id =
9292c593315Sopenharmony_ci      nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
9302c593315Sopenharmony_ci
9312c593315Sopenharmony_ci  if (payloadlen > 4) {
9322c593315Sopenharmony_ci    priority_update->field_value = payload + 4;
9332c593315Sopenharmony_ci    priority_update->field_value_len = payloadlen - 4;
9342c593315Sopenharmony_ci  } else {
9352c593315Sopenharmony_ci    priority_update->field_value = NULL;
9362c593315Sopenharmony_ci    priority_update->field_value_len = 0;
9372c593315Sopenharmony_ci  }
9382c593315Sopenharmony_ci}
9392c593315Sopenharmony_ci
9402c593315Sopenharmony_cinghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
9412c593315Sopenharmony_ci                                              size_t niv, nghttp2_mem *mem) {
9422c593315Sopenharmony_ci  nghttp2_settings_entry *iv_copy;
9432c593315Sopenharmony_ci  size_t len = niv * sizeof(nghttp2_settings_entry);
9442c593315Sopenharmony_ci
9452c593315Sopenharmony_ci  if (len == 0) {
9462c593315Sopenharmony_ci    return NULL;
9472c593315Sopenharmony_ci  }
9482c593315Sopenharmony_ci
9492c593315Sopenharmony_ci  iv_copy = nghttp2_mem_malloc(mem, len);
9502c593315Sopenharmony_ci
9512c593315Sopenharmony_ci  if (iv_copy == NULL) {
9522c593315Sopenharmony_ci    return NULL;
9532c593315Sopenharmony_ci  }
9542c593315Sopenharmony_ci
9552c593315Sopenharmony_ci  memcpy(iv_copy, iv, len);
9562c593315Sopenharmony_ci
9572c593315Sopenharmony_ci  return iv_copy;
9582c593315Sopenharmony_ci}
9592c593315Sopenharmony_ci
9602c593315Sopenharmony_ciint nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b) {
9612c593315Sopenharmony_ci  if (a->namelen != b->namelen || a->valuelen != b->valuelen) {
9622c593315Sopenharmony_ci    return 0;
9632c593315Sopenharmony_ci  }
9642c593315Sopenharmony_ci
9652c593315Sopenharmony_ci  if (a->name == NULL || b->name == NULL) {
9662c593315Sopenharmony_ci    assert(a->namelen == 0);
9672c593315Sopenharmony_ci    assert(b->namelen == 0);
9682c593315Sopenharmony_ci  } else if (memcmp(a->name, b->name, a->namelen) != 0) {
9692c593315Sopenharmony_ci    return 0;
9702c593315Sopenharmony_ci  }
9712c593315Sopenharmony_ci
9722c593315Sopenharmony_ci  if (a->value == NULL || b->value == NULL) {
9732c593315Sopenharmony_ci    assert(a->valuelen == 0);
9742c593315Sopenharmony_ci    assert(b->valuelen == 0);
9752c593315Sopenharmony_ci  } else if (memcmp(a->value, b->value, a->valuelen) != 0) {
9762c593315Sopenharmony_ci    return 0;
9772c593315Sopenharmony_ci  }
9782c593315Sopenharmony_ci
9792c593315Sopenharmony_ci  return 1;
9802c593315Sopenharmony_ci}
9812c593315Sopenharmony_ci
9822c593315Sopenharmony_civoid nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem) {
9832c593315Sopenharmony_ci  nghttp2_mem_free(mem, nva);
9842c593315Sopenharmony_ci}
9852c593315Sopenharmony_ci
9862c593315Sopenharmony_cistatic int bytes_compar(const uint8_t *a, size_t alen, const uint8_t *b,
9872c593315Sopenharmony_ci                        size_t blen) {
9882c593315Sopenharmony_ci  int rv;
9892c593315Sopenharmony_ci
9902c593315Sopenharmony_ci  if (alen == blen) {
9912c593315Sopenharmony_ci    return memcmp(a, b, alen);
9922c593315Sopenharmony_ci  }
9932c593315Sopenharmony_ci
9942c593315Sopenharmony_ci  if (alen < blen) {
9952c593315Sopenharmony_ci    rv = memcmp(a, b, alen);
9962c593315Sopenharmony_ci
9972c593315Sopenharmony_ci    if (rv == 0) {
9982c593315Sopenharmony_ci      return -1;
9992c593315Sopenharmony_ci    }
10002c593315Sopenharmony_ci
10012c593315Sopenharmony_ci    return rv;
10022c593315Sopenharmony_ci  }
10032c593315Sopenharmony_ci
10042c593315Sopenharmony_ci  rv = memcmp(a, b, blen);
10052c593315Sopenharmony_ci
10062c593315Sopenharmony_ci  if (rv == 0) {
10072c593315Sopenharmony_ci    return 1;
10082c593315Sopenharmony_ci  }
10092c593315Sopenharmony_ci
10102c593315Sopenharmony_ci  return rv;
10112c593315Sopenharmony_ci}
10122c593315Sopenharmony_ci
10132c593315Sopenharmony_ciint nghttp2_nv_compare_name(const nghttp2_nv *lhs, const nghttp2_nv *rhs) {
10142c593315Sopenharmony_ci  return bytes_compar(lhs->name, lhs->namelen, rhs->name, rhs->namelen);
10152c593315Sopenharmony_ci}
10162c593315Sopenharmony_ci
10172c593315Sopenharmony_cistatic int nv_compar(const void *lhs, const void *rhs) {
10182c593315Sopenharmony_ci  const nghttp2_nv *a = (const nghttp2_nv *)lhs;
10192c593315Sopenharmony_ci  const nghttp2_nv *b = (const nghttp2_nv *)rhs;
10202c593315Sopenharmony_ci  int rv;
10212c593315Sopenharmony_ci
10222c593315Sopenharmony_ci  rv = bytes_compar(a->name, a->namelen, b->name, b->namelen);
10232c593315Sopenharmony_ci
10242c593315Sopenharmony_ci  if (rv == 0) {
10252c593315Sopenharmony_ci    return bytes_compar(a->value, a->valuelen, b->value, b->valuelen);
10262c593315Sopenharmony_ci  }
10272c593315Sopenharmony_ci
10282c593315Sopenharmony_ci  return rv;
10292c593315Sopenharmony_ci}
10302c593315Sopenharmony_ci
10312c593315Sopenharmony_civoid nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen) {
10322c593315Sopenharmony_ci  qsort(nva, nvlen, sizeof(nghttp2_nv), nv_compar);
10332c593315Sopenharmony_ci}
10342c593315Sopenharmony_ci
10352c593315Sopenharmony_ciint nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
10362c593315Sopenharmony_ci                          size_t nvlen, nghttp2_mem *mem) {
10372c593315Sopenharmony_ci  size_t i;
10382c593315Sopenharmony_ci  uint8_t *data = NULL;
10392c593315Sopenharmony_ci  size_t buflen = 0;
10402c593315Sopenharmony_ci  nghttp2_nv *p;
10412c593315Sopenharmony_ci
10422c593315Sopenharmony_ci  if (nvlen == 0) {
10432c593315Sopenharmony_ci    *nva_ptr = NULL;
10442c593315Sopenharmony_ci
10452c593315Sopenharmony_ci    return 0;
10462c593315Sopenharmony_ci  }
10472c593315Sopenharmony_ci
10482c593315Sopenharmony_ci  for (i = 0; i < nvlen; ++i) {
10492c593315Sopenharmony_ci    /* + 1 for null-termination */
10502c593315Sopenharmony_ci    if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) == 0) {
10512c593315Sopenharmony_ci      buflen += nva[i].namelen + 1;
10522c593315Sopenharmony_ci    }
10532c593315Sopenharmony_ci    if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) == 0) {
10542c593315Sopenharmony_ci      buflen += nva[i].valuelen + 1;
10552c593315Sopenharmony_ci    }
10562c593315Sopenharmony_ci  }
10572c593315Sopenharmony_ci
10582c593315Sopenharmony_ci  buflen += sizeof(nghttp2_nv) * nvlen;
10592c593315Sopenharmony_ci
10602c593315Sopenharmony_ci  *nva_ptr = nghttp2_mem_malloc(mem, buflen);
10612c593315Sopenharmony_ci
10622c593315Sopenharmony_ci  if (*nva_ptr == NULL) {
10632c593315Sopenharmony_ci    return NGHTTP2_ERR_NOMEM;
10642c593315Sopenharmony_ci  }
10652c593315Sopenharmony_ci
10662c593315Sopenharmony_ci  p = *nva_ptr;
10672c593315Sopenharmony_ci  data = (uint8_t *)(*nva_ptr) + sizeof(nghttp2_nv) * nvlen;
10682c593315Sopenharmony_ci
10692c593315Sopenharmony_ci  for (i = 0; i < nvlen; ++i) {
10702c593315Sopenharmony_ci    p->flags = nva[i].flags;
10712c593315Sopenharmony_ci
10722c593315Sopenharmony_ci    if (nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) {
10732c593315Sopenharmony_ci      p->name = nva[i].name;
10742c593315Sopenharmony_ci      p->namelen = nva[i].namelen;
10752c593315Sopenharmony_ci    } else {
10762c593315Sopenharmony_ci      if (nva[i].namelen) {
10772c593315Sopenharmony_ci        memcpy(data, nva[i].name, nva[i].namelen);
10782c593315Sopenharmony_ci      }
10792c593315Sopenharmony_ci      p->name = data;
10802c593315Sopenharmony_ci      p->namelen = nva[i].namelen;
10812c593315Sopenharmony_ci      data[p->namelen] = '\0';
10822c593315Sopenharmony_ci      nghttp2_downcase(p->name, p->namelen);
10832c593315Sopenharmony_ci      data += nva[i].namelen + 1;
10842c593315Sopenharmony_ci    }
10852c593315Sopenharmony_ci
10862c593315Sopenharmony_ci    if (nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) {
10872c593315Sopenharmony_ci      p->value = nva[i].value;
10882c593315Sopenharmony_ci      p->valuelen = nva[i].valuelen;
10892c593315Sopenharmony_ci    } else {
10902c593315Sopenharmony_ci      if (nva[i].valuelen) {
10912c593315Sopenharmony_ci        memcpy(data, nva[i].value, nva[i].valuelen);
10922c593315Sopenharmony_ci      }
10932c593315Sopenharmony_ci      p->value = data;
10942c593315Sopenharmony_ci      p->valuelen = nva[i].valuelen;
10952c593315Sopenharmony_ci      data[p->valuelen] = '\0';
10962c593315Sopenharmony_ci      data += nva[i].valuelen + 1;
10972c593315Sopenharmony_ci    }
10982c593315Sopenharmony_ci
10992c593315Sopenharmony_ci    ++p;
11002c593315Sopenharmony_ci  }
11012c593315Sopenharmony_ci  return 0;
11022c593315Sopenharmony_ci}
11032c593315Sopenharmony_ci
11042c593315Sopenharmony_ciint nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) {
11052c593315Sopenharmony_ci  size_t i;
11062c593315Sopenharmony_ci  for (i = 0; i < niv; ++i) {
11072c593315Sopenharmony_ci    switch (iv[i].settings_id) {
11082c593315Sopenharmony_ci    case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE:
11092c593315Sopenharmony_ci      break;
11102c593315Sopenharmony_ci    case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:
11112c593315Sopenharmony_ci      break;
11122c593315Sopenharmony_ci    case NGHTTP2_SETTINGS_ENABLE_PUSH:
11132c593315Sopenharmony_ci      if (iv[i].value != 0 && iv[i].value != 1) {
11142c593315Sopenharmony_ci        return 0;
11152c593315Sopenharmony_ci      }
11162c593315Sopenharmony_ci      break;
11172c593315Sopenharmony_ci    case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
11182c593315Sopenharmony_ci      if (iv[i].value > (uint32_t)NGHTTP2_MAX_WINDOW_SIZE) {
11192c593315Sopenharmony_ci        return 0;
11202c593315Sopenharmony_ci      }
11212c593315Sopenharmony_ci      break;
11222c593315Sopenharmony_ci    case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
11232c593315Sopenharmony_ci      if (iv[i].value < NGHTTP2_MAX_FRAME_SIZE_MIN ||
11242c593315Sopenharmony_ci          iv[i].value > NGHTTP2_MAX_FRAME_SIZE_MAX) {
11252c593315Sopenharmony_ci        return 0;
11262c593315Sopenharmony_ci      }
11272c593315Sopenharmony_ci      break;
11282c593315Sopenharmony_ci    case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
11292c593315Sopenharmony_ci      break;
11302c593315Sopenharmony_ci    case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
11312c593315Sopenharmony_ci      if (iv[i].value != 0 && iv[i].value != 1) {
11322c593315Sopenharmony_ci        return 0;
11332c593315Sopenharmony_ci      }
11342c593315Sopenharmony_ci      break;
11352c593315Sopenharmony_ci    case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
11362c593315Sopenharmony_ci      if (iv[i].value != 0 && iv[i].value != 1) {
11372c593315Sopenharmony_ci        return 0;
11382c593315Sopenharmony_ci      }
11392c593315Sopenharmony_ci      break;
11402c593315Sopenharmony_ci    }
11412c593315Sopenharmony_ci  }
11422c593315Sopenharmony_ci  return 1;
11432c593315Sopenharmony_ci}
11442c593315Sopenharmony_ci
11452c593315Sopenharmony_cistatic void frame_set_pad(nghttp2_buf *buf, size_t padlen, int framehd_only) {
11462c593315Sopenharmony_ci  size_t trail_padlen;
11472c593315Sopenharmony_ci  size_t newlen;
11482c593315Sopenharmony_ci
11492c593315Sopenharmony_ci  DEBUGF("send: padlen=%zu, shift left 1 bytes\n", padlen);
11502c593315Sopenharmony_ci
11512c593315Sopenharmony_ci  memmove(buf->pos - 1, buf->pos, NGHTTP2_FRAME_HDLEN);
11522c593315Sopenharmony_ci
11532c593315Sopenharmony_ci  --buf->pos;
11542c593315Sopenharmony_ci
11552c593315Sopenharmony_ci  buf->pos[4] |= NGHTTP2_FLAG_PADDED;
11562c593315Sopenharmony_ci
11572c593315Sopenharmony_ci  newlen = (nghttp2_get_uint32(buf->pos) >> 8) + padlen;
11582c593315Sopenharmony_ci  nghttp2_put_uint32be(buf->pos, (uint32_t)((newlen << 8) + buf->pos[3]));
11592c593315Sopenharmony_ci
11602c593315Sopenharmony_ci  if (framehd_only) {
11612c593315Sopenharmony_ci    return;
11622c593315Sopenharmony_ci  }
11632c593315Sopenharmony_ci
11642c593315Sopenharmony_ci  trail_padlen = padlen - 1;
11652c593315Sopenharmony_ci  buf->pos[NGHTTP2_FRAME_HDLEN] = (uint8_t)trail_padlen;
11662c593315Sopenharmony_ci
11672c593315Sopenharmony_ci  /* zero out padding */
11682c593315Sopenharmony_ci  memset(buf->last, 0, trail_padlen);
11692c593315Sopenharmony_ci  /* extend buffers trail_padlen bytes, since we ate previous padlen -
11702c593315Sopenharmony_ci     trail_padlen byte(s) */
11712c593315Sopenharmony_ci  buf->last += trail_padlen;
11722c593315Sopenharmony_ci}
11732c593315Sopenharmony_ci
11742c593315Sopenharmony_civoid nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
11752c593315Sopenharmony_ci                           size_t padlen, int framehd_only) {
11762c593315Sopenharmony_ci  nghttp2_buf *buf;
11772c593315Sopenharmony_ci
11782c593315Sopenharmony_ci  if (padlen == 0) {
11792c593315Sopenharmony_ci    DEBUGF("send: padlen = 0, nothing to do\n");
11802c593315Sopenharmony_ci
11812c593315Sopenharmony_ci    return;
11822c593315Sopenharmony_ci  }
11832c593315Sopenharmony_ci
11842c593315Sopenharmony_ci  /*
11852c593315Sopenharmony_ci   * We have arranged bufs like this:
11862c593315Sopenharmony_ci   *
11872c593315Sopenharmony_ci   *  0                   1                   2                   3
11882c593315Sopenharmony_ci   *  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
11892c593315Sopenharmony_ci   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
11902c593315Sopenharmony_ci   * | |Frame header     | Frame payload...                          :
11912c593315Sopenharmony_ci   * +-+-----------------+-------------------------------------------+
11922c593315Sopenharmony_ci   * | |Frame header     | Frame payload...                          :
11932c593315Sopenharmony_ci   * +-+-----------------+-------------------------------------------+
11942c593315Sopenharmony_ci   * | |Frame header     | Frame payload...                          :
11952c593315Sopenharmony_ci   * +-+-----------------+-------------------------------------------+
11962c593315Sopenharmony_ci   *
11972c593315Sopenharmony_ci   * We arranged padding so that it is included in the first frame
11982c593315Sopenharmony_ci   * completely.  For padded frame, we are going to adjust buf->pos of
11992c593315Sopenharmony_ci   * frame which includes padding and serialize (memmove) frame header
12002c593315Sopenharmony_ci   * in the correct position.  Also extends buf->last to include
12012c593315Sopenharmony_ci   * padding.
12022c593315Sopenharmony_ci   */
12032c593315Sopenharmony_ci
12042c593315Sopenharmony_ci  buf = &bufs->head->buf;
12052c593315Sopenharmony_ci
12062c593315Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >= padlen - 1);
12072c593315Sopenharmony_ci
12082c593315Sopenharmony_ci  frame_set_pad(buf, padlen, framehd_only);
12092c593315Sopenharmony_ci
12102c593315Sopenharmony_ci  hd->length += padlen;
12112c593315Sopenharmony_ci  hd->flags |= NGHTTP2_FLAG_PADDED;
12122c593315Sopenharmony_ci
12132c593315Sopenharmony_ci  DEBUGF("send: final payloadlen=%zu, padlen=%zu\n", hd->length, padlen);
12142c593315Sopenharmony_ci}
1215