11cb0ef41Sopenharmony_ci/*
21cb0ef41Sopenharmony_ci * nghttp2 - HTTP/2 C Library
31cb0ef41Sopenharmony_ci *
41cb0ef41Sopenharmony_ci * Copyright (c) 2013 Tatsuhiro Tsujikawa
51cb0ef41Sopenharmony_ci *
61cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
71cb0ef41Sopenharmony_ci * a copy of this software and associated documentation files (the
81cb0ef41Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
91cb0ef41Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
101cb0ef41Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
111cb0ef41Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
121cb0ef41Sopenharmony_ci * the following conditions:
131cb0ef41Sopenharmony_ci *
141cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice shall be
151cb0ef41Sopenharmony_ci * included in all copies or substantial portions of the Software.
161cb0ef41Sopenharmony_ci *
171cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
181cb0ef41Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
191cb0ef41Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
201cb0ef41Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
211cb0ef41Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
221cb0ef41Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
231cb0ef41Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
241cb0ef41Sopenharmony_ci */
251cb0ef41Sopenharmony_ci#include "nghttp2_frame.h"
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci#include <string.h>
281cb0ef41Sopenharmony_ci#include <assert.h>
291cb0ef41Sopenharmony_ci#include <stdio.h>
301cb0ef41Sopenharmony_ci#include <errno.h>
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci#include "nghttp2_helper.h"
331cb0ef41Sopenharmony_ci#include "nghttp2_net.h"
341cb0ef41Sopenharmony_ci#include "nghttp2_priority_spec.h"
351cb0ef41Sopenharmony_ci#include "nghttp2_debug.h"
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_civoid nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd) {
381cb0ef41Sopenharmony_ci  nghttp2_put_uint32be(&buf[0], (uint32_t)(hd->length << 8));
391cb0ef41Sopenharmony_ci  buf[3] = hd->type;
401cb0ef41Sopenharmony_ci  buf[4] = hd->flags;
411cb0ef41Sopenharmony_ci  nghttp2_put_uint32be(&buf[5], (uint32_t)hd->stream_id);
421cb0ef41Sopenharmony_ci  /* ignore hd->reserved for now */
431cb0ef41Sopenharmony_ci}
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_civoid nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf) {
461cb0ef41Sopenharmony_ci  hd->length = nghttp2_get_uint32(&buf[0]) >> 8;
471cb0ef41Sopenharmony_ci  hd->type = buf[3];
481cb0ef41Sopenharmony_ci  hd->flags = buf[4];
491cb0ef41Sopenharmony_ci  hd->stream_id = nghttp2_get_uint32(&buf[5]) & NGHTTP2_STREAM_ID_MASK;
501cb0ef41Sopenharmony_ci  hd->reserved = 0;
511cb0ef41Sopenharmony_ci}
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_civoid nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type,
541cb0ef41Sopenharmony_ci                           uint8_t flags, int32_t stream_id) {
551cb0ef41Sopenharmony_ci  hd->length = length;
561cb0ef41Sopenharmony_ci  hd->type = type;
571cb0ef41Sopenharmony_ci  hd->flags = flags;
581cb0ef41Sopenharmony_ci  hd->stream_id = stream_id;
591cb0ef41Sopenharmony_ci  hd->reserved = 0;
601cb0ef41Sopenharmony_ci}
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_civoid nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags,
631cb0ef41Sopenharmony_ci                                int32_t stream_id, nghttp2_headers_category cat,
641cb0ef41Sopenharmony_ci                                const nghttp2_priority_spec *pri_spec,
651cb0ef41Sopenharmony_ci                                nghttp2_nv *nva, size_t nvlen) {
661cb0ef41Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_HEADERS, flags, stream_id);
671cb0ef41Sopenharmony_ci  frame->padlen = 0;
681cb0ef41Sopenharmony_ci  frame->nva = nva;
691cb0ef41Sopenharmony_ci  frame->nvlen = nvlen;
701cb0ef41Sopenharmony_ci  frame->cat = cat;
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  if (pri_spec) {
731cb0ef41Sopenharmony_ci    frame->pri_spec = *pri_spec;
741cb0ef41Sopenharmony_ci  } else {
751cb0ef41Sopenharmony_ci    nghttp2_priority_spec_default_init(&frame->pri_spec);
761cb0ef41Sopenharmony_ci  }
771cb0ef41Sopenharmony_ci}
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_civoid nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem) {
801cb0ef41Sopenharmony_ci  nghttp2_nv_array_del(frame->nva, mem);
811cb0ef41Sopenharmony_ci}
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_civoid nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
841cb0ef41Sopenharmony_ci                                 const nghttp2_priority_spec *pri_spec) {
851cb0ef41Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, NGHTTP2_PRIORITY_SPECLEN, NGHTTP2_PRIORITY,
861cb0ef41Sopenharmony_ci                        NGHTTP2_FLAG_NONE, stream_id);
871cb0ef41Sopenharmony_ci  frame->pri_spec = *pri_spec;
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_civoid nghttp2_frame_priority_free(nghttp2_priority *frame) { (void)frame; }
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_civoid nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
931cb0ef41Sopenharmony_ci                                   uint32_t error_code) {
941cb0ef41Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE,
951cb0ef41Sopenharmony_ci                        stream_id);
961cb0ef41Sopenharmony_ci  frame->error_code = error_code;
971cb0ef41Sopenharmony_ci}
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_civoid nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame) { (void)frame; }
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_civoid nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
1021cb0ef41Sopenharmony_ci                                 nghttp2_settings_entry *iv, size_t niv) {
1031cb0ef41Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH,
1041cb0ef41Sopenharmony_ci                        NGHTTP2_SETTINGS, flags, 0);
1051cb0ef41Sopenharmony_ci  frame->niv = niv;
1061cb0ef41Sopenharmony_ci  frame->iv = iv;
1071cb0ef41Sopenharmony_ci}
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_civoid nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem) {
1101cb0ef41Sopenharmony_ci  nghttp2_mem_free(mem, frame->iv);
1111cb0ef41Sopenharmony_ci}
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_civoid nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags,
1141cb0ef41Sopenharmony_ci                                     int32_t stream_id,
1151cb0ef41Sopenharmony_ci                                     int32_t promised_stream_id,
1161cb0ef41Sopenharmony_ci                                     nghttp2_nv *nva, size_t nvlen) {
1171cb0ef41Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_PUSH_PROMISE, flags, stream_id);
1181cb0ef41Sopenharmony_ci  frame->padlen = 0;
1191cb0ef41Sopenharmony_ci  frame->nva = nva;
1201cb0ef41Sopenharmony_ci  frame->nvlen = nvlen;
1211cb0ef41Sopenharmony_ci  frame->promised_stream_id = promised_stream_id;
1221cb0ef41Sopenharmony_ci  frame->reserved = 0;
1231cb0ef41Sopenharmony_ci}
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_civoid nghttp2_frame_push_promise_free(nghttp2_push_promise *frame,
1261cb0ef41Sopenharmony_ci                                     nghttp2_mem *mem) {
1271cb0ef41Sopenharmony_ci  nghttp2_nv_array_del(frame->nva, mem);
1281cb0ef41Sopenharmony_ci}
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_civoid nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags,
1311cb0ef41Sopenharmony_ci                             const uint8_t *opaque_data) {
1321cb0ef41Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 8, NGHTTP2_PING, flags, 0);
1331cb0ef41Sopenharmony_ci  if (opaque_data) {
1341cb0ef41Sopenharmony_ci    memcpy(frame->opaque_data, opaque_data, sizeof(frame->opaque_data));
1351cb0ef41Sopenharmony_ci  } else {
1361cb0ef41Sopenharmony_ci    memset(frame->opaque_data, 0, sizeof(frame->opaque_data));
1371cb0ef41Sopenharmony_ci  }
1381cb0ef41Sopenharmony_ci}
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_civoid nghttp2_frame_ping_free(nghttp2_ping *frame) { (void)frame; }
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_civoid nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
1431cb0ef41Sopenharmony_ci                               uint32_t error_code, uint8_t *opaque_data,
1441cb0ef41Sopenharmony_ci                               size_t opaque_data_len) {
1451cb0ef41Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 8 + opaque_data_len, NGHTTP2_GOAWAY,
1461cb0ef41Sopenharmony_ci                        NGHTTP2_FLAG_NONE, 0);
1471cb0ef41Sopenharmony_ci  frame->last_stream_id = last_stream_id;
1481cb0ef41Sopenharmony_ci  frame->error_code = error_code;
1491cb0ef41Sopenharmony_ci  frame->opaque_data = opaque_data;
1501cb0ef41Sopenharmony_ci  frame->opaque_data_len = opaque_data_len;
1511cb0ef41Sopenharmony_ci  frame->reserved = 0;
1521cb0ef41Sopenharmony_ci}
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_civoid nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem) {
1551cb0ef41Sopenharmony_ci  nghttp2_mem_free(mem, frame->opaque_data);
1561cb0ef41Sopenharmony_ci}
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_civoid nghttp2_frame_window_update_init(nghttp2_window_update *frame,
1591cb0ef41Sopenharmony_ci                                      uint8_t flags, int32_t stream_id,
1601cb0ef41Sopenharmony_ci                                      int32_t window_size_increment) {
1611cb0ef41Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_WINDOW_UPDATE, flags, stream_id);
1621cb0ef41Sopenharmony_ci  frame->window_size_increment = window_size_increment;
1631cb0ef41Sopenharmony_ci  frame->reserved = 0;
1641cb0ef41Sopenharmony_ci}
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_civoid nghttp2_frame_window_update_free(nghttp2_window_update *frame) {
1671cb0ef41Sopenharmony_ci  (void)frame;
1681cb0ef41Sopenharmony_ci}
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_cisize_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen) {
1711cb0ef41Sopenharmony_ci  /* We have iframe->padlen == 0, but iframe->frame.hd.flags may have
1721cb0ef41Sopenharmony_ci     NGHTTP2_FLAG_PADDED set.  This happens when receiving
1731cb0ef41Sopenharmony_ci     CONTINUATION frame, since we don't reset flags after HEADERS was
1741cb0ef41Sopenharmony_ci     received. */
1751cb0ef41Sopenharmony_ci  if (padlen == 0) {
1761cb0ef41Sopenharmony_ci    return 0;
1771cb0ef41Sopenharmony_ci  }
1781cb0ef41Sopenharmony_ci  return padlen - ((frame->hd.flags & NGHTTP2_FLAG_PADDED) > 0);
1791cb0ef41Sopenharmony_ci}
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_civoid nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
1821cb0ef41Sopenharmony_ci                             int32_t stream_id) {
1831cb0ef41Sopenharmony_ci  /* At this moment, the length of DATA frame is unknown */
1841cb0ef41Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_DATA, flags, stream_id);
1851cb0ef41Sopenharmony_ci  frame->padlen = 0;
1861cb0ef41Sopenharmony_ci}
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_civoid nghttp2_frame_data_free(nghttp2_data *frame) { (void)frame; }
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_civoid nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
1911cb0ef41Sopenharmony_ci                                  uint8_t flags, int32_t stream_id,
1921cb0ef41Sopenharmony_ci                                  void *payload) {
1931cb0ef41Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 0, type, flags, stream_id);
1941cb0ef41Sopenharmony_ci  frame->payload = payload;
1951cb0ef41Sopenharmony_ci}
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_civoid nghttp2_frame_extension_free(nghttp2_extension *frame) { (void)frame; }
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_civoid nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
2001cb0ef41Sopenharmony_ci                               uint8_t *origin, size_t origin_len,
2011cb0ef41Sopenharmony_ci                               uint8_t *field_value, size_t field_value_len) {
2021cb0ef41Sopenharmony_ci  nghttp2_ext_altsvc *altsvc;
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 2 + origin_len + field_value_len,
2051cb0ef41Sopenharmony_ci                        NGHTTP2_ALTSVC, NGHTTP2_FLAG_NONE, stream_id);
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_ci  altsvc = frame->payload;
2081cb0ef41Sopenharmony_ci  altsvc->origin = origin;
2091cb0ef41Sopenharmony_ci  altsvc->origin_len = origin_len;
2101cb0ef41Sopenharmony_ci  altsvc->field_value = field_value;
2111cb0ef41Sopenharmony_ci  altsvc->field_value_len = field_value_len;
2121cb0ef41Sopenharmony_ci}
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_civoid nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem) {
2151cb0ef41Sopenharmony_ci  nghttp2_ext_altsvc *altsvc;
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_ci  altsvc = frame->payload;
2181cb0ef41Sopenharmony_ci  if (altsvc == NULL) {
2191cb0ef41Sopenharmony_ci    return;
2201cb0ef41Sopenharmony_ci  }
2211cb0ef41Sopenharmony_ci  /* We use the same buffer for altsvc->origin and
2221cb0ef41Sopenharmony_ci     altsvc->field_value. */
2231cb0ef41Sopenharmony_ci  nghttp2_mem_free(mem, altsvc->origin);
2241cb0ef41Sopenharmony_ci}
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_civoid nghttp2_frame_origin_init(nghttp2_extension *frame,
2271cb0ef41Sopenharmony_ci                               nghttp2_origin_entry *ov, size_t nov) {
2281cb0ef41Sopenharmony_ci  nghttp2_ext_origin *origin;
2291cb0ef41Sopenharmony_ci  size_t payloadlen = 0;
2301cb0ef41Sopenharmony_ci  size_t i;
2311cb0ef41Sopenharmony_ci
2321cb0ef41Sopenharmony_ci  for (i = 0; i < nov; ++i) {
2331cb0ef41Sopenharmony_ci    payloadlen += 2 + ov[i].origin_len;
2341cb0ef41Sopenharmony_ci  }
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, payloadlen, NGHTTP2_ORIGIN,
2371cb0ef41Sopenharmony_ci                        NGHTTP2_FLAG_NONE, 0);
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci  origin = frame->payload;
2401cb0ef41Sopenharmony_ci  origin->ov = ov;
2411cb0ef41Sopenharmony_ci  origin->nov = nov;
2421cb0ef41Sopenharmony_ci}
2431cb0ef41Sopenharmony_ci
2441cb0ef41Sopenharmony_civoid nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem) {
2451cb0ef41Sopenharmony_ci  nghttp2_ext_origin *origin;
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci  origin = frame->payload;
2481cb0ef41Sopenharmony_ci  if (origin == NULL) {
2491cb0ef41Sopenharmony_ci    return;
2501cb0ef41Sopenharmony_ci  }
2511cb0ef41Sopenharmony_ci  /* We use the same buffer for all resources pointed by the field of
2521cb0ef41Sopenharmony_ci     origin directly or indirectly. */
2531cb0ef41Sopenharmony_ci  nghttp2_mem_free(mem, origin->ov);
2541cb0ef41Sopenharmony_ci}
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_civoid nghttp2_frame_priority_update_init(nghttp2_extension *frame,
2571cb0ef41Sopenharmony_ci                                        int32_t stream_id, uint8_t *field_value,
2581cb0ef41Sopenharmony_ci                                        size_t field_value_len) {
2591cb0ef41Sopenharmony_ci  nghttp2_ext_priority_update *priority_update;
2601cb0ef41Sopenharmony_ci
2611cb0ef41Sopenharmony_ci  nghttp2_frame_hd_init(&frame->hd, 4 + field_value_len,
2621cb0ef41Sopenharmony_ci                        NGHTTP2_PRIORITY_UPDATE, NGHTTP2_FLAG_NONE, 0);
2631cb0ef41Sopenharmony_ci
2641cb0ef41Sopenharmony_ci  priority_update = frame->payload;
2651cb0ef41Sopenharmony_ci  priority_update->stream_id = stream_id;
2661cb0ef41Sopenharmony_ci  priority_update->field_value = field_value;
2671cb0ef41Sopenharmony_ci  priority_update->field_value_len = field_value_len;
2681cb0ef41Sopenharmony_ci}
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_civoid nghttp2_frame_priority_update_free(nghttp2_extension *frame,
2711cb0ef41Sopenharmony_ci                                        nghttp2_mem *mem) {
2721cb0ef41Sopenharmony_ci  nghttp2_ext_priority_update *priority_update;
2731cb0ef41Sopenharmony_ci
2741cb0ef41Sopenharmony_ci  priority_update = frame->payload;
2751cb0ef41Sopenharmony_ci  if (priority_update == NULL) {
2761cb0ef41Sopenharmony_ci    return;
2771cb0ef41Sopenharmony_ci  }
2781cb0ef41Sopenharmony_ci  nghttp2_mem_free(mem, priority_update->field_value);
2791cb0ef41Sopenharmony_ci}
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_cisize_t nghttp2_frame_priority_len(uint8_t flags) {
2821cb0ef41Sopenharmony_ci  if (flags & NGHTTP2_FLAG_PRIORITY) {
2831cb0ef41Sopenharmony_ci    return NGHTTP2_PRIORITY_SPECLEN;
2841cb0ef41Sopenharmony_ci  }
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ci  return 0;
2871cb0ef41Sopenharmony_ci}
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_cisize_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame) {
2901cb0ef41Sopenharmony_ci  return nghttp2_frame_priority_len(frame->hd.flags);
2911cb0ef41Sopenharmony_ci}
2921cb0ef41Sopenharmony_ci
2931cb0ef41Sopenharmony_ci/*
2941cb0ef41Sopenharmony_ci * Call this function after payload was serialized, but not before
2951cb0ef41Sopenharmony_ci * changing buf->pos and serializing frame header.
2961cb0ef41Sopenharmony_ci *
2971cb0ef41Sopenharmony_ci * This function assumes bufs->cur points to the last buf chain of the
2981cb0ef41Sopenharmony_ci * frame(s).
2991cb0ef41Sopenharmony_ci *
3001cb0ef41Sopenharmony_ci * This function serializes frame header for HEADERS/PUSH_PROMISE and
3011cb0ef41Sopenharmony_ci * handles their successive CONTINUATION frames.
3021cb0ef41Sopenharmony_ci *
3031cb0ef41Sopenharmony_ci * We don't process any padding here.
3041cb0ef41Sopenharmony_ci */
3051cb0ef41Sopenharmony_cistatic int frame_pack_headers_shared(nghttp2_bufs *bufs,
3061cb0ef41Sopenharmony_ci                                     nghttp2_frame_hd *frame_hd) {
3071cb0ef41Sopenharmony_ci  nghttp2_buf *buf;
3081cb0ef41Sopenharmony_ci  nghttp2_buf_chain *ci, *ce;
3091cb0ef41Sopenharmony_ci  nghttp2_frame_hd hd;
3101cb0ef41Sopenharmony_ci
3111cb0ef41Sopenharmony_ci  buf = &bufs->head->buf;
3121cb0ef41Sopenharmony_ci
3131cb0ef41Sopenharmony_ci  hd = *frame_hd;
3141cb0ef41Sopenharmony_ci  hd.length = nghttp2_buf_len(buf);
3151cb0ef41Sopenharmony_ci
3161cb0ef41Sopenharmony_ci  DEBUGF("send: HEADERS/PUSH_PROMISE, payloadlen=%zu\n", hd.length);
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_ci  /* We have multiple frame buffers, which means one or more
3191cb0ef41Sopenharmony_ci     CONTINUATION frame is involved. Remove END_HEADERS flag from the
3201cb0ef41Sopenharmony_ci     first frame. */
3211cb0ef41Sopenharmony_ci  if (bufs->head != bufs->cur) {
3221cb0ef41Sopenharmony_ci    hd.flags = (uint8_t)(hd.flags & ~NGHTTP2_FLAG_END_HEADERS);
3231cb0ef41Sopenharmony_ci  }
3241cb0ef41Sopenharmony_ci
3251cb0ef41Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
3261cb0ef41Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &hd);
3271cb0ef41Sopenharmony_ci
3281cb0ef41Sopenharmony_ci  if (bufs->head != bufs->cur) {
3291cb0ef41Sopenharmony_ci    /* 2nd and later frames are CONTINUATION frames. */
3301cb0ef41Sopenharmony_ci    hd.type = NGHTTP2_CONTINUATION;
3311cb0ef41Sopenharmony_ci    /* We don't have no flags except for last CONTINUATION */
3321cb0ef41Sopenharmony_ci    hd.flags = NGHTTP2_FLAG_NONE;
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ci    ce = bufs->cur;
3351cb0ef41Sopenharmony_ci
3361cb0ef41Sopenharmony_ci    for (ci = bufs->head->next; ci != ce; ci = ci->next) {
3371cb0ef41Sopenharmony_ci      buf = &ci->buf;
3381cb0ef41Sopenharmony_ci
3391cb0ef41Sopenharmony_ci      hd.length = nghttp2_buf_len(buf);
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ci      DEBUGF("send: int CONTINUATION, payloadlen=%zu\n", hd.length);
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_ci      buf->pos -= NGHTTP2_FRAME_HDLEN;
3441cb0ef41Sopenharmony_ci      nghttp2_frame_pack_frame_hd(buf->pos, &hd);
3451cb0ef41Sopenharmony_ci    }
3461cb0ef41Sopenharmony_ci
3471cb0ef41Sopenharmony_ci    buf = &ci->buf;
3481cb0ef41Sopenharmony_ci    hd.length = nghttp2_buf_len(buf);
3491cb0ef41Sopenharmony_ci    /* Set END_HEADERS flag for last CONTINUATION */
3501cb0ef41Sopenharmony_ci    hd.flags = NGHTTP2_FLAG_END_HEADERS;
3511cb0ef41Sopenharmony_ci
3521cb0ef41Sopenharmony_ci    DEBUGF("send: last CONTINUATION, payloadlen=%zu\n", hd.length);
3531cb0ef41Sopenharmony_ci
3541cb0ef41Sopenharmony_ci    buf->pos -= NGHTTP2_FRAME_HDLEN;
3551cb0ef41Sopenharmony_ci    nghttp2_frame_pack_frame_hd(buf->pos, &hd);
3561cb0ef41Sopenharmony_ci  }
3571cb0ef41Sopenharmony_ci
3581cb0ef41Sopenharmony_ci  return 0;
3591cb0ef41Sopenharmony_ci}
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_ciint nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
3621cb0ef41Sopenharmony_ci                               nghttp2_hd_deflater *deflater) {
3631cb0ef41Sopenharmony_ci  size_t nv_offset;
3641cb0ef41Sopenharmony_ci  int rv;
3651cb0ef41Sopenharmony_ci  nghttp2_buf *buf;
3661cb0ef41Sopenharmony_ci
3671cb0ef41Sopenharmony_ci  assert(bufs->head == bufs->cur);
3681cb0ef41Sopenharmony_ci
3691cb0ef41Sopenharmony_ci  nv_offset = nghttp2_frame_headers_payload_nv_offset(frame);
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_ci  buf = &bufs->cur->buf;
3721cb0ef41Sopenharmony_ci
3731cb0ef41Sopenharmony_ci  buf->pos += nv_offset;
3741cb0ef41Sopenharmony_ci  buf->last = buf->pos;
3751cb0ef41Sopenharmony_ci
3761cb0ef41Sopenharmony_ci  /* This call will adjust buf->last to the correct position */
3771cb0ef41Sopenharmony_ci  rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen);
3781cb0ef41Sopenharmony_ci
3791cb0ef41Sopenharmony_ci  if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
3801cb0ef41Sopenharmony_ci    rv = NGHTTP2_ERR_HEADER_COMP;
3811cb0ef41Sopenharmony_ci  }
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_ci  buf->pos -= nv_offset;
3841cb0ef41Sopenharmony_ci
3851cb0ef41Sopenharmony_ci  if (rv != 0) {
3861cb0ef41Sopenharmony_ci    return rv;
3871cb0ef41Sopenharmony_ci  }
3881cb0ef41Sopenharmony_ci
3891cb0ef41Sopenharmony_ci  if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
3901cb0ef41Sopenharmony_ci    nghttp2_frame_pack_priority_spec(buf->pos, &frame->pri_spec);
3911cb0ef41Sopenharmony_ci  }
3921cb0ef41Sopenharmony_ci
3931cb0ef41Sopenharmony_ci  frame->padlen = 0;
3941cb0ef41Sopenharmony_ci  frame->hd.length = nghttp2_bufs_len(bufs);
3951cb0ef41Sopenharmony_ci
3961cb0ef41Sopenharmony_ci  return frame_pack_headers_shared(bufs, &frame->hd);
3971cb0ef41Sopenharmony_ci}
3981cb0ef41Sopenharmony_ci
3991cb0ef41Sopenharmony_civoid nghttp2_frame_pack_priority_spec(uint8_t *buf,
4001cb0ef41Sopenharmony_ci                                      const nghttp2_priority_spec *pri_spec) {
4011cb0ef41Sopenharmony_ci  nghttp2_put_uint32be(buf, (uint32_t)pri_spec->stream_id);
4021cb0ef41Sopenharmony_ci  if (pri_spec->exclusive) {
4031cb0ef41Sopenharmony_ci    buf[0] |= 0x80;
4041cb0ef41Sopenharmony_ci  }
4051cb0ef41Sopenharmony_ci  buf[4] = (uint8_t)(pri_spec->weight - 1);
4061cb0ef41Sopenharmony_ci}
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_civoid nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
4091cb0ef41Sopenharmony_ci                                        const uint8_t *payload) {
4101cb0ef41Sopenharmony_ci  int32_t dep_stream_id;
4111cb0ef41Sopenharmony_ci  uint8_t exclusive;
4121cb0ef41Sopenharmony_ci  int32_t weight;
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ci  dep_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
4151cb0ef41Sopenharmony_ci  exclusive = (payload[0] & 0x80) > 0;
4161cb0ef41Sopenharmony_ci  weight = payload[4] + 1;
4171cb0ef41Sopenharmony_ci
4181cb0ef41Sopenharmony_ci  nghttp2_priority_spec_init(pri_spec, dep_stream_id, weight, exclusive);
4191cb0ef41Sopenharmony_ci}
4201cb0ef41Sopenharmony_ci
4211cb0ef41Sopenharmony_civoid nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
4221cb0ef41Sopenharmony_ci                                          const uint8_t *payload) {
4231cb0ef41Sopenharmony_ci  if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
4241cb0ef41Sopenharmony_ci    nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload);
4251cb0ef41Sopenharmony_ci  } else {
4261cb0ef41Sopenharmony_ci    nghttp2_priority_spec_default_init(&frame->pri_spec);
4271cb0ef41Sopenharmony_ci  }
4281cb0ef41Sopenharmony_ci
4291cb0ef41Sopenharmony_ci  frame->nva = NULL;
4301cb0ef41Sopenharmony_ci  frame->nvlen = 0;
4311cb0ef41Sopenharmony_ci}
4321cb0ef41Sopenharmony_ci
4331cb0ef41Sopenharmony_civoid nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) {
4341cb0ef41Sopenharmony_ci  nghttp2_buf *buf;
4351cb0ef41Sopenharmony_ci
4361cb0ef41Sopenharmony_ci  assert(bufs->head == bufs->cur);
4371cb0ef41Sopenharmony_ci
4381cb0ef41Sopenharmony_ci  buf = &bufs->head->buf;
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >= NGHTTP2_PRIORITY_SPECLEN);
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
4431cb0ef41Sopenharmony_ci
4441cb0ef41Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
4451cb0ef41Sopenharmony_ci
4461cb0ef41Sopenharmony_ci  nghttp2_frame_pack_priority_spec(buf->last, &frame->pri_spec);
4471cb0ef41Sopenharmony_ci
4481cb0ef41Sopenharmony_ci  buf->last += NGHTTP2_PRIORITY_SPECLEN;
4491cb0ef41Sopenharmony_ci}
4501cb0ef41Sopenharmony_ci
4511cb0ef41Sopenharmony_civoid nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
4521cb0ef41Sopenharmony_ci                                           const uint8_t *payload) {
4531cb0ef41Sopenharmony_ci  nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload);
4541cb0ef41Sopenharmony_ci}
4551cb0ef41Sopenharmony_ci
4561cb0ef41Sopenharmony_civoid nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
4571cb0ef41Sopenharmony_ci                                   nghttp2_rst_stream *frame) {
4581cb0ef41Sopenharmony_ci  nghttp2_buf *buf;
4591cb0ef41Sopenharmony_ci
4601cb0ef41Sopenharmony_ci  assert(bufs->head == bufs->cur);
4611cb0ef41Sopenharmony_ci
4621cb0ef41Sopenharmony_ci  buf = &bufs->head->buf;
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >= 4);
4651cb0ef41Sopenharmony_ci
4661cb0ef41Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
4671cb0ef41Sopenharmony_ci
4681cb0ef41Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
4691cb0ef41Sopenharmony_ci
4701cb0ef41Sopenharmony_ci  nghttp2_put_uint32be(buf->last, frame->error_code);
4711cb0ef41Sopenharmony_ci  buf->last += 4;
4721cb0ef41Sopenharmony_ci}
4731cb0ef41Sopenharmony_ci
4741cb0ef41Sopenharmony_civoid nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
4751cb0ef41Sopenharmony_ci                                             const uint8_t *payload) {
4761cb0ef41Sopenharmony_ci  frame->error_code = nghttp2_get_uint32(payload);
4771cb0ef41Sopenharmony_ci}
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ciint nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame) {
4801cb0ef41Sopenharmony_ci  nghttp2_buf *buf;
4811cb0ef41Sopenharmony_ci
4821cb0ef41Sopenharmony_ci  assert(bufs->head == bufs->cur);
4831cb0ef41Sopenharmony_ci
4841cb0ef41Sopenharmony_ci  buf = &bufs->head->buf;
4851cb0ef41Sopenharmony_ci
4861cb0ef41Sopenharmony_ci  if (nghttp2_buf_avail(buf) < frame->hd.length) {
4871cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_FRAME_SIZE_ERROR;
4881cb0ef41Sopenharmony_ci  }
4891cb0ef41Sopenharmony_ci
4901cb0ef41Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
4911cb0ef41Sopenharmony_ci
4921cb0ef41Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
4931cb0ef41Sopenharmony_ci
4941cb0ef41Sopenharmony_ci  buf->last +=
4951cb0ef41Sopenharmony_ci      nghttp2_frame_pack_settings_payload(buf->last, frame->iv, frame->niv);
4961cb0ef41Sopenharmony_ci
4971cb0ef41Sopenharmony_ci  return 0;
4981cb0ef41Sopenharmony_ci}
4991cb0ef41Sopenharmony_ci
5001cb0ef41Sopenharmony_cisize_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
5011cb0ef41Sopenharmony_ci                                           const nghttp2_settings_entry *iv,
5021cb0ef41Sopenharmony_ci                                           size_t niv) {
5031cb0ef41Sopenharmony_ci  size_t i;
5041cb0ef41Sopenharmony_ci  for (i = 0; i < niv; ++i, buf += NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) {
5051cb0ef41Sopenharmony_ci    nghttp2_put_uint16be(buf, (uint16_t)iv[i].settings_id);
5061cb0ef41Sopenharmony_ci    nghttp2_put_uint32be(buf + 2, iv[i].value);
5071cb0ef41Sopenharmony_ci  }
5081cb0ef41Sopenharmony_ci  return NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH * niv;
5091cb0ef41Sopenharmony_ci}
5101cb0ef41Sopenharmony_ci
5111cb0ef41Sopenharmony_civoid nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
5121cb0ef41Sopenharmony_ci                                           nghttp2_settings_entry *iv,
5131cb0ef41Sopenharmony_ci                                           size_t niv) {
5141cb0ef41Sopenharmony_ci  frame->iv = iv;
5151cb0ef41Sopenharmony_ci  frame->niv = niv;
5161cb0ef41Sopenharmony_ci}
5171cb0ef41Sopenharmony_ci
5181cb0ef41Sopenharmony_civoid nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
5191cb0ef41Sopenharmony_ci                                         const uint8_t *payload) {
5201cb0ef41Sopenharmony_ci  iv->settings_id = nghttp2_get_uint16(&payload[0]);
5211cb0ef41Sopenharmony_ci  iv->value = nghttp2_get_uint32(&payload[2]);
5221cb0ef41Sopenharmony_ci}
5231cb0ef41Sopenharmony_ci
5241cb0ef41Sopenharmony_ciint nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
5251cb0ef41Sopenharmony_ci                                           size_t *niv_ptr,
5261cb0ef41Sopenharmony_ci                                           const uint8_t *payload,
5271cb0ef41Sopenharmony_ci                                           size_t payloadlen,
5281cb0ef41Sopenharmony_ci                                           nghttp2_mem *mem) {
5291cb0ef41Sopenharmony_ci  size_t i;
5301cb0ef41Sopenharmony_ci
5311cb0ef41Sopenharmony_ci  *niv_ptr = payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH;
5321cb0ef41Sopenharmony_ci
5331cb0ef41Sopenharmony_ci  if (*niv_ptr == 0) {
5341cb0ef41Sopenharmony_ci    *iv_ptr = NULL;
5351cb0ef41Sopenharmony_ci
5361cb0ef41Sopenharmony_ci    return 0;
5371cb0ef41Sopenharmony_ci  }
5381cb0ef41Sopenharmony_ci
5391cb0ef41Sopenharmony_ci  *iv_ptr =
5401cb0ef41Sopenharmony_ci      nghttp2_mem_malloc(mem, (*niv_ptr) * sizeof(nghttp2_settings_entry));
5411cb0ef41Sopenharmony_ci
5421cb0ef41Sopenharmony_ci  if (*iv_ptr == NULL) {
5431cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_NOMEM;
5441cb0ef41Sopenharmony_ci  }
5451cb0ef41Sopenharmony_ci
5461cb0ef41Sopenharmony_ci  for (i = 0; i < *niv_ptr; ++i) {
5471cb0ef41Sopenharmony_ci    size_t off = i * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH;
5481cb0ef41Sopenharmony_ci    nghttp2_frame_unpack_settings_entry(&(*iv_ptr)[i], &payload[off]);
5491cb0ef41Sopenharmony_ci  }
5501cb0ef41Sopenharmony_ci
5511cb0ef41Sopenharmony_ci  return 0;
5521cb0ef41Sopenharmony_ci}
5531cb0ef41Sopenharmony_ci
5541cb0ef41Sopenharmony_ciint nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
5551cb0ef41Sopenharmony_ci                                    nghttp2_push_promise *frame,
5561cb0ef41Sopenharmony_ci                                    nghttp2_hd_deflater *deflater) {
5571cb0ef41Sopenharmony_ci  size_t nv_offset = 4;
5581cb0ef41Sopenharmony_ci  int rv;
5591cb0ef41Sopenharmony_ci  nghttp2_buf *buf;
5601cb0ef41Sopenharmony_ci
5611cb0ef41Sopenharmony_ci  assert(bufs->head == bufs->cur);
5621cb0ef41Sopenharmony_ci
5631cb0ef41Sopenharmony_ci  buf = &bufs->cur->buf;
5641cb0ef41Sopenharmony_ci
5651cb0ef41Sopenharmony_ci  buf->pos += nv_offset;
5661cb0ef41Sopenharmony_ci  buf->last = buf->pos;
5671cb0ef41Sopenharmony_ci
5681cb0ef41Sopenharmony_ci  /* This call will adjust buf->last to the correct position */
5691cb0ef41Sopenharmony_ci  rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen);
5701cb0ef41Sopenharmony_ci
5711cb0ef41Sopenharmony_ci  if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
5721cb0ef41Sopenharmony_ci    rv = NGHTTP2_ERR_HEADER_COMP;
5731cb0ef41Sopenharmony_ci  }
5741cb0ef41Sopenharmony_ci
5751cb0ef41Sopenharmony_ci  buf->pos -= nv_offset;
5761cb0ef41Sopenharmony_ci
5771cb0ef41Sopenharmony_ci  if (rv != 0) {
5781cb0ef41Sopenharmony_ci    return rv;
5791cb0ef41Sopenharmony_ci  }
5801cb0ef41Sopenharmony_ci
5811cb0ef41Sopenharmony_ci  nghttp2_put_uint32be(buf->pos, (uint32_t)frame->promised_stream_id);
5821cb0ef41Sopenharmony_ci
5831cb0ef41Sopenharmony_ci  frame->padlen = 0;
5841cb0ef41Sopenharmony_ci  frame->hd.length = nghttp2_bufs_len(bufs);
5851cb0ef41Sopenharmony_ci
5861cb0ef41Sopenharmony_ci  return frame_pack_headers_shared(bufs, &frame->hd);
5871cb0ef41Sopenharmony_ci}
5881cb0ef41Sopenharmony_ci
5891cb0ef41Sopenharmony_civoid nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
5901cb0ef41Sopenharmony_ci                                               const uint8_t *payload) {
5911cb0ef41Sopenharmony_ci  frame->promised_stream_id =
5921cb0ef41Sopenharmony_ci      nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
5931cb0ef41Sopenharmony_ci  frame->nva = NULL;
5941cb0ef41Sopenharmony_ci  frame->nvlen = 0;
5951cb0ef41Sopenharmony_ci}
5961cb0ef41Sopenharmony_ci
5971cb0ef41Sopenharmony_civoid nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) {
5981cb0ef41Sopenharmony_ci  nghttp2_buf *buf;
5991cb0ef41Sopenharmony_ci
6001cb0ef41Sopenharmony_ci  assert(bufs->head == bufs->cur);
6011cb0ef41Sopenharmony_ci
6021cb0ef41Sopenharmony_ci  buf = &bufs->head->buf;
6031cb0ef41Sopenharmony_ci
6041cb0ef41Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >= 8);
6051cb0ef41Sopenharmony_ci
6061cb0ef41Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
6071cb0ef41Sopenharmony_ci
6081cb0ef41Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
6091cb0ef41Sopenharmony_ci
6101cb0ef41Sopenharmony_ci  buf->last =
6111cb0ef41Sopenharmony_ci      nghttp2_cpymem(buf->last, frame->opaque_data, sizeof(frame->opaque_data));
6121cb0ef41Sopenharmony_ci}
6131cb0ef41Sopenharmony_ci
6141cb0ef41Sopenharmony_civoid nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
6151cb0ef41Sopenharmony_ci                                       const uint8_t *payload) {
6161cb0ef41Sopenharmony_ci  memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data));
6171cb0ef41Sopenharmony_ci}
6181cb0ef41Sopenharmony_ci
6191cb0ef41Sopenharmony_ciint nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame) {
6201cb0ef41Sopenharmony_ci  int rv;
6211cb0ef41Sopenharmony_ci  nghttp2_buf *buf;
6221cb0ef41Sopenharmony_ci
6231cb0ef41Sopenharmony_ci  assert(bufs->head == bufs->cur);
6241cb0ef41Sopenharmony_ci
6251cb0ef41Sopenharmony_ci  buf = &bufs->head->buf;
6261cb0ef41Sopenharmony_ci
6271cb0ef41Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
6281cb0ef41Sopenharmony_ci
6291cb0ef41Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
6301cb0ef41Sopenharmony_ci
6311cb0ef41Sopenharmony_ci  nghttp2_put_uint32be(buf->last, (uint32_t)frame->last_stream_id);
6321cb0ef41Sopenharmony_ci  buf->last += 4;
6331cb0ef41Sopenharmony_ci
6341cb0ef41Sopenharmony_ci  nghttp2_put_uint32be(buf->last, frame->error_code);
6351cb0ef41Sopenharmony_ci  buf->last += 4;
6361cb0ef41Sopenharmony_ci
6371cb0ef41Sopenharmony_ci  rv = nghttp2_bufs_add(bufs, frame->opaque_data, frame->opaque_data_len);
6381cb0ef41Sopenharmony_ci
6391cb0ef41Sopenharmony_ci  if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
6401cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_FRAME_SIZE_ERROR;
6411cb0ef41Sopenharmony_ci  }
6421cb0ef41Sopenharmony_ci
6431cb0ef41Sopenharmony_ci  if (rv != 0) {
6441cb0ef41Sopenharmony_ci    return rv;
6451cb0ef41Sopenharmony_ci  }
6461cb0ef41Sopenharmony_ci
6471cb0ef41Sopenharmony_ci  return 0;
6481cb0ef41Sopenharmony_ci}
6491cb0ef41Sopenharmony_ci
6501cb0ef41Sopenharmony_civoid nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
6511cb0ef41Sopenharmony_ci                                         const uint8_t *payload,
6521cb0ef41Sopenharmony_ci                                         uint8_t *var_gift_payload,
6531cb0ef41Sopenharmony_ci                                         size_t var_gift_payloadlen) {
6541cb0ef41Sopenharmony_ci  frame->last_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
6551cb0ef41Sopenharmony_ci  frame->error_code = nghttp2_get_uint32(payload + 4);
6561cb0ef41Sopenharmony_ci
6571cb0ef41Sopenharmony_ci  frame->opaque_data = var_gift_payload;
6581cb0ef41Sopenharmony_ci  frame->opaque_data_len = var_gift_payloadlen;
6591cb0ef41Sopenharmony_ci}
6601cb0ef41Sopenharmony_ci
6611cb0ef41Sopenharmony_ciint nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
6621cb0ef41Sopenharmony_ci                                         const uint8_t *payload,
6631cb0ef41Sopenharmony_ci                                         size_t payloadlen, nghttp2_mem *mem) {
6641cb0ef41Sopenharmony_ci  uint8_t *var_gift_payload;
6651cb0ef41Sopenharmony_ci  size_t var_gift_payloadlen;
6661cb0ef41Sopenharmony_ci
6671cb0ef41Sopenharmony_ci  if (payloadlen > 8) {
6681cb0ef41Sopenharmony_ci    var_gift_payloadlen = payloadlen - 8;
6691cb0ef41Sopenharmony_ci  } else {
6701cb0ef41Sopenharmony_ci    var_gift_payloadlen = 0;
6711cb0ef41Sopenharmony_ci  }
6721cb0ef41Sopenharmony_ci
6731cb0ef41Sopenharmony_ci  if (!var_gift_payloadlen) {
6741cb0ef41Sopenharmony_ci    var_gift_payload = NULL;
6751cb0ef41Sopenharmony_ci  } else {
6761cb0ef41Sopenharmony_ci    var_gift_payload = nghttp2_mem_malloc(mem, var_gift_payloadlen);
6771cb0ef41Sopenharmony_ci
6781cb0ef41Sopenharmony_ci    if (var_gift_payload == NULL) {
6791cb0ef41Sopenharmony_ci      return NGHTTP2_ERR_NOMEM;
6801cb0ef41Sopenharmony_ci    }
6811cb0ef41Sopenharmony_ci
6821cb0ef41Sopenharmony_ci    memcpy(var_gift_payload, payload + 8, var_gift_payloadlen);
6831cb0ef41Sopenharmony_ci  }
6841cb0ef41Sopenharmony_ci
6851cb0ef41Sopenharmony_ci  nghttp2_frame_unpack_goaway_payload(frame, payload, var_gift_payload,
6861cb0ef41Sopenharmony_ci                                      var_gift_payloadlen);
6871cb0ef41Sopenharmony_ci
6881cb0ef41Sopenharmony_ci  return 0;
6891cb0ef41Sopenharmony_ci}
6901cb0ef41Sopenharmony_ci
6911cb0ef41Sopenharmony_civoid nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
6921cb0ef41Sopenharmony_ci                                      nghttp2_window_update *frame) {
6931cb0ef41Sopenharmony_ci  nghttp2_buf *buf;
6941cb0ef41Sopenharmony_ci
6951cb0ef41Sopenharmony_ci  assert(bufs->head == bufs->cur);
6961cb0ef41Sopenharmony_ci
6971cb0ef41Sopenharmony_ci  buf = &bufs->head->buf;
6981cb0ef41Sopenharmony_ci
6991cb0ef41Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >= 4);
7001cb0ef41Sopenharmony_ci
7011cb0ef41Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
7021cb0ef41Sopenharmony_ci
7031cb0ef41Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
7041cb0ef41Sopenharmony_ci
7051cb0ef41Sopenharmony_ci  nghttp2_put_uint32be(buf->last, (uint32_t)frame->window_size_increment);
7061cb0ef41Sopenharmony_ci  buf->last += 4;
7071cb0ef41Sopenharmony_ci}
7081cb0ef41Sopenharmony_ci
7091cb0ef41Sopenharmony_civoid nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
7101cb0ef41Sopenharmony_ci                                                const uint8_t *payload) {
7111cb0ef41Sopenharmony_ci  frame->window_size_increment =
7121cb0ef41Sopenharmony_ci      nghttp2_get_uint32(payload) & NGHTTP2_WINDOW_SIZE_INCREMENT_MASK;
7131cb0ef41Sopenharmony_ci}
7141cb0ef41Sopenharmony_ci
7151cb0ef41Sopenharmony_civoid nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) {
7161cb0ef41Sopenharmony_ci  int rv;
7171cb0ef41Sopenharmony_ci  nghttp2_buf *buf;
7181cb0ef41Sopenharmony_ci  nghttp2_ext_altsvc *altsvc;
7191cb0ef41Sopenharmony_ci
7201cb0ef41Sopenharmony_ci  /* This is required with --disable-assert. */
7211cb0ef41Sopenharmony_ci  (void)rv;
7221cb0ef41Sopenharmony_ci
7231cb0ef41Sopenharmony_ci  altsvc = frame->payload;
7241cb0ef41Sopenharmony_ci
7251cb0ef41Sopenharmony_ci  buf = &bufs->head->buf;
7261cb0ef41Sopenharmony_ci
7271cb0ef41Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >=
7281cb0ef41Sopenharmony_ci         2 + altsvc->origin_len + altsvc->field_value_len);
7291cb0ef41Sopenharmony_ci
7301cb0ef41Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
7311cb0ef41Sopenharmony_ci
7321cb0ef41Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
7331cb0ef41Sopenharmony_ci
7341cb0ef41Sopenharmony_ci  nghttp2_put_uint16be(buf->last, (uint16_t)altsvc->origin_len);
7351cb0ef41Sopenharmony_ci  buf->last += 2;
7361cb0ef41Sopenharmony_ci
7371cb0ef41Sopenharmony_ci  rv = nghttp2_bufs_add(bufs, altsvc->origin, altsvc->origin_len);
7381cb0ef41Sopenharmony_ci
7391cb0ef41Sopenharmony_ci  assert(rv == 0);
7401cb0ef41Sopenharmony_ci
7411cb0ef41Sopenharmony_ci  rv = nghttp2_bufs_add(bufs, altsvc->field_value, altsvc->field_value_len);
7421cb0ef41Sopenharmony_ci
7431cb0ef41Sopenharmony_ci  assert(rv == 0);
7441cb0ef41Sopenharmony_ci}
7451cb0ef41Sopenharmony_ci
7461cb0ef41Sopenharmony_civoid nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
7471cb0ef41Sopenharmony_ci                                         size_t origin_len, uint8_t *payload,
7481cb0ef41Sopenharmony_ci                                         size_t payloadlen) {
7491cb0ef41Sopenharmony_ci  nghttp2_ext_altsvc *altsvc;
7501cb0ef41Sopenharmony_ci  uint8_t *p;
7511cb0ef41Sopenharmony_ci
7521cb0ef41Sopenharmony_ci  altsvc = frame->payload;
7531cb0ef41Sopenharmony_ci  p = payload;
7541cb0ef41Sopenharmony_ci
7551cb0ef41Sopenharmony_ci  altsvc->origin = p;
7561cb0ef41Sopenharmony_ci
7571cb0ef41Sopenharmony_ci  p += origin_len;
7581cb0ef41Sopenharmony_ci
7591cb0ef41Sopenharmony_ci  altsvc->origin_len = origin_len;
7601cb0ef41Sopenharmony_ci
7611cb0ef41Sopenharmony_ci  altsvc->field_value = p;
7621cb0ef41Sopenharmony_ci  altsvc->field_value_len = (size_t)(payload + payloadlen - p);
7631cb0ef41Sopenharmony_ci}
7641cb0ef41Sopenharmony_ci
7651cb0ef41Sopenharmony_ciint nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame,
7661cb0ef41Sopenharmony_ci                                         const uint8_t *payload,
7671cb0ef41Sopenharmony_ci                                         size_t payloadlen, nghttp2_mem *mem) {
7681cb0ef41Sopenharmony_ci  uint8_t *buf;
7691cb0ef41Sopenharmony_ci  size_t origin_len;
7701cb0ef41Sopenharmony_ci
7711cb0ef41Sopenharmony_ci  if (payloadlen < 2) {
7721cb0ef41Sopenharmony_ci    return NGHTTP2_FRAME_SIZE_ERROR;
7731cb0ef41Sopenharmony_ci  }
7741cb0ef41Sopenharmony_ci
7751cb0ef41Sopenharmony_ci  origin_len = nghttp2_get_uint16(payload);
7761cb0ef41Sopenharmony_ci
7771cb0ef41Sopenharmony_ci  buf = nghttp2_mem_malloc(mem, payloadlen - 2);
7781cb0ef41Sopenharmony_ci  if (!buf) {
7791cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_NOMEM;
7801cb0ef41Sopenharmony_ci  }
7811cb0ef41Sopenharmony_ci
7821cb0ef41Sopenharmony_ci  nghttp2_cpymem(buf, payload + 2, payloadlen - 2);
7831cb0ef41Sopenharmony_ci
7841cb0ef41Sopenharmony_ci  nghttp2_frame_unpack_altsvc_payload(frame, origin_len, buf, payloadlen - 2);
7851cb0ef41Sopenharmony_ci
7861cb0ef41Sopenharmony_ci  return 0;
7871cb0ef41Sopenharmony_ci}
7881cb0ef41Sopenharmony_ci
7891cb0ef41Sopenharmony_ciint nghttp2_frame_pack_origin(nghttp2_bufs *bufs, nghttp2_extension *frame) {
7901cb0ef41Sopenharmony_ci  nghttp2_buf *buf;
7911cb0ef41Sopenharmony_ci  nghttp2_ext_origin *origin;
7921cb0ef41Sopenharmony_ci  nghttp2_origin_entry *orig;
7931cb0ef41Sopenharmony_ci  size_t i;
7941cb0ef41Sopenharmony_ci
7951cb0ef41Sopenharmony_ci  origin = frame->payload;
7961cb0ef41Sopenharmony_ci
7971cb0ef41Sopenharmony_ci  buf = &bufs->head->buf;
7981cb0ef41Sopenharmony_ci
7991cb0ef41Sopenharmony_ci  if (nghttp2_buf_avail(buf) < frame->hd.length) {
8001cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_FRAME_SIZE_ERROR;
8011cb0ef41Sopenharmony_ci  }
8021cb0ef41Sopenharmony_ci
8031cb0ef41Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
8041cb0ef41Sopenharmony_ci
8051cb0ef41Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
8061cb0ef41Sopenharmony_ci
8071cb0ef41Sopenharmony_ci  for (i = 0; i < origin->nov; ++i) {
8081cb0ef41Sopenharmony_ci    orig = &origin->ov[i];
8091cb0ef41Sopenharmony_ci    nghttp2_put_uint16be(buf->last, (uint16_t)orig->origin_len);
8101cb0ef41Sopenharmony_ci    buf->last += 2;
8111cb0ef41Sopenharmony_ci    buf->last = nghttp2_cpymem(buf->last, orig->origin, orig->origin_len);
8121cb0ef41Sopenharmony_ci  }
8131cb0ef41Sopenharmony_ci
8141cb0ef41Sopenharmony_ci  assert(nghttp2_buf_len(buf) == NGHTTP2_FRAME_HDLEN + frame->hd.length);
8151cb0ef41Sopenharmony_ci
8161cb0ef41Sopenharmony_ci  return 0;
8171cb0ef41Sopenharmony_ci}
8181cb0ef41Sopenharmony_ci
8191cb0ef41Sopenharmony_ciint nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
8201cb0ef41Sopenharmony_ci                                        const uint8_t *payload,
8211cb0ef41Sopenharmony_ci                                        size_t payloadlen, nghttp2_mem *mem) {
8221cb0ef41Sopenharmony_ci  nghttp2_ext_origin *origin;
8231cb0ef41Sopenharmony_ci  const uint8_t *p, *end;
8241cb0ef41Sopenharmony_ci  uint8_t *dst;
8251cb0ef41Sopenharmony_ci  size_t originlen;
8261cb0ef41Sopenharmony_ci  nghttp2_origin_entry *ov;
8271cb0ef41Sopenharmony_ci  size_t nov = 0;
8281cb0ef41Sopenharmony_ci  size_t len = 0;
8291cb0ef41Sopenharmony_ci
8301cb0ef41Sopenharmony_ci  origin = frame->payload;
8311cb0ef41Sopenharmony_ci  p = end = payload;
8321cb0ef41Sopenharmony_ci  if (payloadlen) {
8331cb0ef41Sopenharmony_ci    end += payloadlen;
8341cb0ef41Sopenharmony_ci  }
8351cb0ef41Sopenharmony_ci
8361cb0ef41Sopenharmony_ci  for (; p != end;) {
8371cb0ef41Sopenharmony_ci    if (end - p < 2) {
8381cb0ef41Sopenharmony_ci      return NGHTTP2_ERR_FRAME_SIZE_ERROR;
8391cb0ef41Sopenharmony_ci    }
8401cb0ef41Sopenharmony_ci    originlen = nghttp2_get_uint16(p);
8411cb0ef41Sopenharmony_ci    p += 2;
8421cb0ef41Sopenharmony_ci    if (originlen == 0) {
8431cb0ef41Sopenharmony_ci      continue;
8441cb0ef41Sopenharmony_ci    }
8451cb0ef41Sopenharmony_ci    if (originlen > (size_t)(end - p)) {
8461cb0ef41Sopenharmony_ci      return NGHTTP2_ERR_FRAME_SIZE_ERROR;
8471cb0ef41Sopenharmony_ci    }
8481cb0ef41Sopenharmony_ci    p += originlen;
8491cb0ef41Sopenharmony_ci    /* 1 for terminal NULL */
8501cb0ef41Sopenharmony_ci    len += originlen + 1;
8511cb0ef41Sopenharmony_ci    ++nov;
8521cb0ef41Sopenharmony_ci  }
8531cb0ef41Sopenharmony_ci
8541cb0ef41Sopenharmony_ci  if (nov == 0) {
8551cb0ef41Sopenharmony_ci    origin->ov = NULL;
8561cb0ef41Sopenharmony_ci    origin->nov = 0;
8571cb0ef41Sopenharmony_ci
8581cb0ef41Sopenharmony_ci    return 0;
8591cb0ef41Sopenharmony_ci  }
8601cb0ef41Sopenharmony_ci
8611cb0ef41Sopenharmony_ci  len += nov * sizeof(nghttp2_origin_entry);
8621cb0ef41Sopenharmony_ci
8631cb0ef41Sopenharmony_ci  ov = nghttp2_mem_malloc(mem, len);
8641cb0ef41Sopenharmony_ci  if (ov == NULL) {
8651cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_NOMEM;
8661cb0ef41Sopenharmony_ci  }
8671cb0ef41Sopenharmony_ci
8681cb0ef41Sopenharmony_ci  origin->ov = ov;
8691cb0ef41Sopenharmony_ci  origin->nov = nov;
8701cb0ef41Sopenharmony_ci
8711cb0ef41Sopenharmony_ci  dst = (uint8_t *)ov + nov * sizeof(nghttp2_origin_entry);
8721cb0ef41Sopenharmony_ci  p = payload;
8731cb0ef41Sopenharmony_ci
8741cb0ef41Sopenharmony_ci  for (; p != end;) {
8751cb0ef41Sopenharmony_ci    originlen = nghttp2_get_uint16(p);
8761cb0ef41Sopenharmony_ci    p += 2;
8771cb0ef41Sopenharmony_ci    if (originlen == 0) {
8781cb0ef41Sopenharmony_ci      continue;
8791cb0ef41Sopenharmony_ci    }
8801cb0ef41Sopenharmony_ci    ov->origin = dst;
8811cb0ef41Sopenharmony_ci    ov->origin_len = originlen;
8821cb0ef41Sopenharmony_ci    dst = nghttp2_cpymem(dst, p, originlen);
8831cb0ef41Sopenharmony_ci    *dst++ = '\0';
8841cb0ef41Sopenharmony_ci    p += originlen;
8851cb0ef41Sopenharmony_ci    ++ov;
8861cb0ef41Sopenharmony_ci  }
8871cb0ef41Sopenharmony_ci
8881cb0ef41Sopenharmony_ci  return 0;
8891cb0ef41Sopenharmony_ci}
8901cb0ef41Sopenharmony_ci
8911cb0ef41Sopenharmony_civoid nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
8921cb0ef41Sopenharmony_ci                                        nghttp2_extension *frame) {
8931cb0ef41Sopenharmony_ci  int rv;
8941cb0ef41Sopenharmony_ci  nghttp2_buf *buf;
8951cb0ef41Sopenharmony_ci  nghttp2_ext_priority_update *priority_update;
8961cb0ef41Sopenharmony_ci
8971cb0ef41Sopenharmony_ci  /* This is required with --disable-assert. */
8981cb0ef41Sopenharmony_ci  (void)rv;
8991cb0ef41Sopenharmony_ci
9001cb0ef41Sopenharmony_ci  priority_update = frame->payload;
9011cb0ef41Sopenharmony_ci
9021cb0ef41Sopenharmony_ci  buf = &bufs->head->buf;
9031cb0ef41Sopenharmony_ci
9041cb0ef41Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >= 4 + priority_update->field_value_len);
9051cb0ef41Sopenharmony_ci
9061cb0ef41Sopenharmony_ci  buf->pos -= NGHTTP2_FRAME_HDLEN;
9071cb0ef41Sopenharmony_ci
9081cb0ef41Sopenharmony_ci  nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
9091cb0ef41Sopenharmony_ci
9101cb0ef41Sopenharmony_ci  nghttp2_put_uint32be(buf->last, (uint32_t)priority_update->stream_id);
9111cb0ef41Sopenharmony_ci  buf->last += 4;
9121cb0ef41Sopenharmony_ci
9131cb0ef41Sopenharmony_ci  rv = nghttp2_bufs_add(bufs, priority_update->field_value,
9141cb0ef41Sopenharmony_ci                        priority_update->field_value_len);
9151cb0ef41Sopenharmony_ci
9161cb0ef41Sopenharmony_ci  assert(rv == 0);
9171cb0ef41Sopenharmony_ci}
9181cb0ef41Sopenharmony_ci
9191cb0ef41Sopenharmony_civoid nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
9201cb0ef41Sopenharmony_ci                                                  uint8_t *payload,
9211cb0ef41Sopenharmony_ci                                                  size_t payloadlen) {
9221cb0ef41Sopenharmony_ci  nghttp2_ext_priority_update *priority_update;
9231cb0ef41Sopenharmony_ci
9241cb0ef41Sopenharmony_ci  assert(payloadlen >= 4);
9251cb0ef41Sopenharmony_ci
9261cb0ef41Sopenharmony_ci  priority_update = frame->payload;
9271cb0ef41Sopenharmony_ci
9281cb0ef41Sopenharmony_ci  priority_update->stream_id =
9291cb0ef41Sopenharmony_ci      nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
9301cb0ef41Sopenharmony_ci
9311cb0ef41Sopenharmony_ci  if (payloadlen > 4) {
9321cb0ef41Sopenharmony_ci    priority_update->field_value = payload + 4;
9331cb0ef41Sopenharmony_ci    priority_update->field_value_len = payloadlen - 4;
9341cb0ef41Sopenharmony_ci  } else {
9351cb0ef41Sopenharmony_ci    priority_update->field_value = NULL;
9361cb0ef41Sopenharmony_ci    priority_update->field_value_len = 0;
9371cb0ef41Sopenharmony_ci  }
9381cb0ef41Sopenharmony_ci}
9391cb0ef41Sopenharmony_ci
9401cb0ef41Sopenharmony_cinghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
9411cb0ef41Sopenharmony_ci                                              size_t niv, nghttp2_mem *mem) {
9421cb0ef41Sopenharmony_ci  nghttp2_settings_entry *iv_copy;
9431cb0ef41Sopenharmony_ci  size_t len = niv * sizeof(nghttp2_settings_entry);
9441cb0ef41Sopenharmony_ci
9451cb0ef41Sopenharmony_ci  if (len == 0) {
9461cb0ef41Sopenharmony_ci    return NULL;
9471cb0ef41Sopenharmony_ci  }
9481cb0ef41Sopenharmony_ci
9491cb0ef41Sopenharmony_ci  iv_copy = nghttp2_mem_malloc(mem, len);
9501cb0ef41Sopenharmony_ci
9511cb0ef41Sopenharmony_ci  if (iv_copy == NULL) {
9521cb0ef41Sopenharmony_ci    return NULL;
9531cb0ef41Sopenharmony_ci  }
9541cb0ef41Sopenharmony_ci
9551cb0ef41Sopenharmony_ci  memcpy(iv_copy, iv, len);
9561cb0ef41Sopenharmony_ci
9571cb0ef41Sopenharmony_ci  return iv_copy;
9581cb0ef41Sopenharmony_ci}
9591cb0ef41Sopenharmony_ci
9601cb0ef41Sopenharmony_ciint nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b) {
9611cb0ef41Sopenharmony_ci  if (a->namelen != b->namelen || a->valuelen != b->valuelen) {
9621cb0ef41Sopenharmony_ci    return 0;
9631cb0ef41Sopenharmony_ci  }
9641cb0ef41Sopenharmony_ci
9651cb0ef41Sopenharmony_ci  if (a->name == NULL || b->name == NULL) {
9661cb0ef41Sopenharmony_ci    assert(a->namelen == 0);
9671cb0ef41Sopenharmony_ci    assert(b->namelen == 0);
9681cb0ef41Sopenharmony_ci  } else if (memcmp(a->name, b->name, a->namelen) != 0) {
9691cb0ef41Sopenharmony_ci    return 0;
9701cb0ef41Sopenharmony_ci  }
9711cb0ef41Sopenharmony_ci
9721cb0ef41Sopenharmony_ci  if (a->value == NULL || b->value == NULL) {
9731cb0ef41Sopenharmony_ci    assert(a->valuelen == 0);
9741cb0ef41Sopenharmony_ci    assert(b->valuelen == 0);
9751cb0ef41Sopenharmony_ci  } else if (memcmp(a->value, b->value, a->valuelen) != 0) {
9761cb0ef41Sopenharmony_ci    return 0;
9771cb0ef41Sopenharmony_ci  }
9781cb0ef41Sopenharmony_ci
9791cb0ef41Sopenharmony_ci  return 1;
9801cb0ef41Sopenharmony_ci}
9811cb0ef41Sopenharmony_ci
9821cb0ef41Sopenharmony_civoid nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem) {
9831cb0ef41Sopenharmony_ci  nghttp2_mem_free(mem, nva);
9841cb0ef41Sopenharmony_ci}
9851cb0ef41Sopenharmony_ci
9861cb0ef41Sopenharmony_cistatic int bytes_compar(const uint8_t *a, size_t alen, const uint8_t *b,
9871cb0ef41Sopenharmony_ci                        size_t blen) {
9881cb0ef41Sopenharmony_ci  int rv;
9891cb0ef41Sopenharmony_ci
9901cb0ef41Sopenharmony_ci  if (alen == blen) {
9911cb0ef41Sopenharmony_ci    return memcmp(a, b, alen);
9921cb0ef41Sopenharmony_ci  }
9931cb0ef41Sopenharmony_ci
9941cb0ef41Sopenharmony_ci  if (alen < blen) {
9951cb0ef41Sopenharmony_ci    rv = memcmp(a, b, alen);
9961cb0ef41Sopenharmony_ci
9971cb0ef41Sopenharmony_ci    if (rv == 0) {
9981cb0ef41Sopenharmony_ci      return -1;
9991cb0ef41Sopenharmony_ci    }
10001cb0ef41Sopenharmony_ci
10011cb0ef41Sopenharmony_ci    return rv;
10021cb0ef41Sopenharmony_ci  }
10031cb0ef41Sopenharmony_ci
10041cb0ef41Sopenharmony_ci  rv = memcmp(a, b, blen);
10051cb0ef41Sopenharmony_ci
10061cb0ef41Sopenharmony_ci  if (rv == 0) {
10071cb0ef41Sopenharmony_ci    return 1;
10081cb0ef41Sopenharmony_ci  }
10091cb0ef41Sopenharmony_ci
10101cb0ef41Sopenharmony_ci  return rv;
10111cb0ef41Sopenharmony_ci}
10121cb0ef41Sopenharmony_ci
10131cb0ef41Sopenharmony_ciint nghttp2_nv_compare_name(const nghttp2_nv *lhs, const nghttp2_nv *rhs) {
10141cb0ef41Sopenharmony_ci  return bytes_compar(lhs->name, lhs->namelen, rhs->name, rhs->namelen);
10151cb0ef41Sopenharmony_ci}
10161cb0ef41Sopenharmony_ci
10171cb0ef41Sopenharmony_cistatic int nv_compar(const void *lhs, const void *rhs) {
10181cb0ef41Sopenharmony_ci  const nghttp2_nv *a = (const nghttp2_nv *)lhs;
10191cb0ef41Sopenharmony_ci  const nghttp2_nv *b = (const nghttp2_nv *)rhs;
10201cb0ef41Sopenharmony_ci  int rv;
10211cb0ef41Sopenharmony_ci
10221cb0ef41Sopenharmony_ci  rv = bytes_compar(a->name, a->namelen, b->name, b->namelen);
10231cb0ef41Sopenharmony_ci
10241cb0ef41Sopenharmony_ci  if (rv == 0) {
10251cb0ef41Sopenharmony_ci    return bytes_compar(a->value, a->valuelen, b->value, b->valuelen);
10261cb0ef41Sopenharmony_ci  }
10271cb0ef41Sopenharmony_ci
10281cb0ef41Sopenharmony_ci  return rv;
10291cb0ef41Sopenharmony_ci}
10301cb0ef41Sopenharmony_ci
10311cb0ef41Sopenharmony_civoid nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen) {
10321cb0ef41Sopenharmony_ci  qsort(nva, nvlen, sizeof(nghttp2_nv), nv_compar);
10331cb0ef41Sopenharmony_ci}
10341cb0ef41Sopenharmony_ci
10351cb0ef41Sopenharmony_ciint nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
10361cb0ef41Sopenharmony_ci                          size_t nvlen, nghttp2_mem *mem) {
10371cb0ef41Sopenharmony_ci  size_t i;
10381cb0ef41Sopenharmony_ci  uint8_t *data = NULL;
10391cb0ef41Sopenharmony_ci  size_t buflen = 0;
10401cb0ef41Sopenharmony_ci  nghttp2_nv *p;
10411cb0ef41Sopenharmony_ci
10421cb0ef41Sopenharmony_ci  if (nvlen == 0) {
10431cb0ef41Sopenharmony_ci    *nva_ptr = NULL;
10441cb0ef41Sopenharmony_ci
10451cb0ef41Sopenharmony_ci    return 0;
10461cb0ef41Sopenharmony_ci  }
10471cb0ef41Sopenharmony_ci
10481cb0ef41Sopenharmony_ci  for (i = 0; i < nvlen; ++i) {
10491cb0ef41Sopenharmony_ci    /* + 1 for null-termination */
10501cb0ef41Sopenharmony_ci    if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) == 0) {
10511cb0ef41Sopenharmony_ci      buflen += nva[i].namelen + 1;
10521cb0ef41Sopenharmony_ci    }
10531cb0ef41Sopenharmony_ci    if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) == 0) {
10541cb0ef41Sopenharmony_ci      buflen += nva[i].valuelen + 1;
10551cb0ef41Sopenharmony_ci    }
10561cb0ef41Sopenharmony_ci  }
10571cb0ef41Sopenharmony_ci
10581cb0ef41Sopenharmony_ci  buflen += sizeof(nghttp2_nv) * nvlen;
10591cb0ef41Sopenharmony_ci
10601cb0ef41Sopenharmony_ci  *nva_ptr = nghttp2_mem_malloc(mem, buflen);
10611cb0ef41Sopenharmony_ci
10621cb0ef41Sopenharmony_ci  if (*nva_ptr == NULL) {
10631cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_NOMEM;
10641cb0ef41Sopenharmony_ci  }
10651cb0ef41Sopenharmony_ci
10661cb0ef41Sopenharmony_ci  p = *nva_ptr;
10671cb0ef41Sopenharmony_ci  data = (uint8_t *)(*nva_ptr) + sizeof(nghttp2_nv) * nvlen;
10681cb0ef41Sopenharmony_ci
10691cb0ef41Sopenharmony_ci  for (i = 0; i < nvlen; ++i) {
10701cb0ef41Sopenharmony_ci    p->flags = nva[i].flags;
10711cb0ef41Sopenharmony_ci
10721cb0ef41Sopenharmony_ci    if (nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) {
10731cb0ef41Sopenharmony_ci      p->name = nva[i].name;
10741cb0ef41Sopenharmony_ci      p->namelen = nva[i].namelen;
10751cb0ef41Sopenharmony_ci    } else {
10761cb0ef41Sopenharmony_ci      if (nva[i].namelen) {
10771cb0ef41Sopenharmony_ci        memcpy(data, nva[i].name, nva[i].namelen);
10781cb0ef41Sopenharmony_ci      }
10791cb0ef41Sopenharmony_ci      p->name = data;
10801cb0ef41Sopenharmony_ci      p->namelen = nva[i].namelen;
10811cb0ef41Sopenharmony_ci      data[p->namelen] = '\0';
10821cb0ef41Sopenharmony_ci      nghttp2_downcase(p->name, p->namelen);
10831cb0ef41Sopenharmony_ci      data += nva[i].namelen + 1;
10841cb0ef41Sopenharmony_ci    }
10851cb0ef41Sopenharmony_ci
10861cb0ef41Sopenharmony_ci    if (nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) {
10871cb0ef41Sopenharmony_ci      p->value = nva[i].value;
10881cb0ef41Sopenharmony_ci      p->valuelen = nva[i].valuelen;
10891cb0ef41Sopenharmony_ci    } else {
10901cb0ef41Sopenharmony_ci      if (nva[i].valuelen) {
10911cb0ef41Sopenharmony_ci        memcpy(data, nva[i].value, nva[i].valuelen);
10921cb0ef41Sopenharmony_ci      }
10931cb0ef41Sopenharmony_ci      p->value = data;
10941cb0ef41Sopenharmony_ci      p->valuelen = nva[i].valuelen;
10951cb0ef41Sopenharmony_ci      data[p->valuelen] = '\0';
10961cb0ef41Sopenharmony_ci      data += nva[i].valuelen + 1;
10971cb0ef41Sopenharmony_ci    }
10981cb0ef41Sopenharmony_ci
10991cb0ef41Sopenharmony_ci    ++p;
11001cb0ef41Sopenharmony_ci  }
11011cb0ef41Sopenharmony_ci  return 0;
11021cb0ef41Sopenharmony_ci}
11031cb0ef41Sopenharmony_ci
11041cb0ef41Sopenharmony_ciint nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) {
11051cb0ef41Sopenharmony_ci  size_t i;
11061cb0ef41Sopenharmony_ci  for (i = 0; i < niv; ++i) {
11071cb0ef41Sopenharmony_ci    switch (iv[i].settings_id) {
11081cb0ef41Sopenharmony_ci    case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE:
11091cb0ef41Sopenharmony_ci      break;
11101cb0ef41Sopenharmony_ci    case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:
11111cb0ef41Sopenharmony_ci      break;
11121cb0ef41Sopenharmony_ci    case NGHTTP2_SETTINGS_ENABLE_PUSH:
11131cb0ef41Sopenharmony_ci      if (iv[i].value != 0 && iv[i].value != 1) {
11141cb0ef41Sopenharmony_ci        return 0;
11151cb0ef41Sopenharmony_ci      }
11161cb0ef41Sopenharmony_ci      break;
11171cb0ef41Sopenharmony_ci    case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
11181cb0ef41Sopenharmony_ci      if (iv[i].value > (uint32_t)NGHTTP2_MAX_WINDOW_SIZE) {
11191cb0ef41Sopenharmony_ci        return 0;
11201cb0ef41Sopenharmony_ci      }
11211cb0ef41Sopenharmony_ci      break;
11221cb0ef41Sopenharmony_ci    case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
11231cb0ef41Sopenharmony_ci      if (iv[i].value < NGHTTP2_MAX_FRAME_SIZE_MIN ||
11241cb0ef41Sopenharmony_ci          iv[i].value > NGHTTP2_MAX_FRAME_SIZE_MAX) {
11251cb0ef41Sopenharmony_ci        return 0;
11261cb0ef41Sopenharmony_ci      }
11271cb0ef41Sopenharmony_ci      break;
11281cb0ef41Sopenharmony_ci    case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
11291cb0ef41Sopenharmony_ci      break;
11301cb0ef41Sopenharmony_ci    case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
11311cb0ef41Sopenharmony_ci      if (iv[i].value != 0 && iv[i].value != 1) {
11321cb0ef41Sopenharmony_ci        return 0;
11331cb0ef41Sopenharmony_ci      }
11341cb0ef41Sopenharmony_ci      break;
11351cb0ef41Sopenharmony_ci    case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
11361cb0ef41Sopenharmony_ci      if (iv[i].value != 0 && iv[i].value != 1) {
11371cb0ef41Sopenharmony_ci        return 0;
11381cb0ef41Sopenharmony_ci      }
11391cb0ef41Sopenharmony_ci      break;
11401cb0ef41Sopenharmony_ci    }
11411cb0ef41Sopenharmony_ci  }
11421cb0ef41Sopenharmony_ci  return 1;
11431cb0ef41Sopenharmony_ci}
11441cb0ef41Sopenharmony_ci
11451cb0ef41Sopenharmony_cistatic void frame_set_pad(nghttp2_buf *buf, size_t padlen, int framehd_only) {
11461cb0ef41Sopenharmony_ci  size_t trail_padlen;
11471cb0ef41Sopenharmony_ci  size_t newlen;
11481cb0ef41Sopenharmony_ci
11491cb0ef41Sopenharmony_ci  DEBUGF("send: padlen=%zu, shift left 1 bytes\n", padlen);
11501cb0ef41Sopenharmony_ci
11511cb0ef41Sopenharmony_ci  memmove(buf->pos - 1, buf->pos, NGHTTP2_FRAME_HDLEN);
11521cb0ef41Sopenharmony_ci
11531cb0ef41Sopenharmony_ci  --buf->pos;
11541cb0ef41Sopenharmony_ci
11551cb0ef41Sopenharmony_ci  buf->pos[4] |= NGHTTP2_FLAG_PADDED;
11561cb0ef41Sopenharmony_ci
11571cb0ef41Sopenharmony_ci  newlen = (nghttp2_get_uint32(buf->pos) >> 8) + padlen;
11581cb0ef41Sopenharmony_ci  nghttp2_put_uint32be(buf->pos, (uint32_t)((newlen << 8) + buf->pos[3]));
11591cb0ef41Sopenharmony_ci
11601cb0ef41Sopenharmony_ci  if (framehd_only) {
11611cb0ef41Sopenharmony_ci    return;
11621cb0ef41Sopenharmony_ci  }
11631cb0ef41Sopenharmony_ci
11641cb0ef41Sopenharmony_ci  trail_padlen = padlen - 1;
11651cb0ef41Sopenharmony_ci  buf->pos[NGHTTP2_FRAME_HDLEN] = (uint8_t)trail_padlen;
11661cb0ef41Sopenharmony_ci
11671cb0ef41Sopenharmony_ci  /* zero out padding */
11681cb0ef41Sopenharmony_ci  memset(buf->last, 0, trail_padlen);
11691cb0ef41Sopenharmony_ci  /* extend buffers trail_padlen bytes, since we ate previous padlen -
11701cb0ef41Sopenharmony_ci     trail_padlen byte(s) */
11711cb0ef41Sopenharmony_ci  buf->last += trail_padlen;
11721cb0ef41Sopenharmony_ci}
11731cb0ef41Sopenharmony_ci
11741cb0ef41Sopenharmony_civoid nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
11751cb0ef41Sopenharmony_ci                           size_t padlen, int framehd_only) {
11761cb0ef41Sopenharmony_ci  nghttp2_buf *buf;
11771cb0ef41Sopenharmony_ci
11781cb0ef41Sopenharmony_ci  if (padlen == 0) {
11791cb0ef41Sopenharmony_ci    DEBUGF("send: padlen = 0, nothing to do\n");
11801cb0ef41Sopenharmony_ci
11811cb0ef41Sopenharmony_ci    return;
11821cb0ef41Sopenharmony_ci  }
11831cb0ef41Sopenharmony_ci
11841cb0ef41Sopenharmony_ci  /*
11851cb0ef41Sopenharmony_ci   * We have arranged bufs like this:
11861cb0ef41Sopenharmony_ci   *
11871cb0ef41Sopenharmony_ci   *  0                   1                   2                   3
11881cb0ef41Sopenharmony_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
11891cb0ef41Sopenharmony_ci   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
11901cb0ef41Sopenharmony_ci   * | |Frame header     | Frame payload...                          :
11911cb0ef41Sopenharmony_ci   * +-+-----------------+-------------------------------------------+
11921cb0ef41Sopenharmony_ci   * | |Frame header     | Frame payload...                          :
11931cb0ef41Sopenharmony_ci   * +-+-----------------+-------------------------------------------+
11941cb0ef41Sopenharmony_ci   * | |Frame header     | Frame payload...                          :
11951cb0ef41Sopenharmony_ci   * +-+-----------------+-------------------------------------------+
11961cb0ef41Sopenharmony_ci   *
11971cb0ef41Sopenharmony_ci   * We arranged padding so that it is included in the first frame
11981cb0ef41Sopenharmony_ci   * completely.  For padded frame, we are going to adjust buf->pos of
11991cb0ef41Sopenharmony_ci   * frame which includes padding and serialize (memmove) frame header
12001cb0ef41Sopenharmony_ci   * in the correct position.  Also extends buf->last to include
12011cb0ef41Sopenharmony_ci   * padding.
12021cb0ef41Sopenharmony_ci   */
12031cb0ef41Sopenharmony_ci
12041cb0ef41Sopenharmony_ci  buf = &bufs->head->buf;
12051cb0ef41Sopenharmony_ci
12061cb0ef41Sopenharmony_ci  assert(nghttp2_buf_avail(buf) >= padlen - 1);
12071cb0ef41Sopenharmony_ci
12081cb0ef41Sopenharmony_ci  frame_set_pad(buf, padlen, framehd_only);
12091cb0ef41Sopenharmony_ci
12101cb0ef41Sopenharmony_ci  hd->length += padlen;
12111cb0ef41Sopenharmony_ci  hd->flags |= NGHTTP2_FLAG_PADDED;
12121cb0ef41Sopenharmony_ci
12131cb0ef41Sopenharmony_ci  DEBUGF("send: final payloadlen=%zu, padlen=%zu\n", hd->length, padlen);
12141cb0ef41Sopenharmony_ci}
1215