11cb0ef41Sopenharmony_ci/*
21cb0ef41Sopenharmony_ci * nghttp2 - HTTP/2 C Library
31cb0ef41Sopenharmony_ci *
41cb0ef41Sopenharmony_ci * Copyright (c) 2012, 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_submit.h"
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci#include <string.h>
281cb0ef41Sopenharmony_ci#include <assert.h>
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci#include "nghttp2_session.h"
311cb0ef41Sopenharmony_ci#include "nghttp2_frame.h"
321cb0ef41Sopenharmony_ci#include "nghttp2_helper.h"
331cb0ef41Sopenharmony_ci#include "nghttp2_priority_spec.h"
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci/*
361cb0ef41Sopenharmony_ci * Detects the dependency error, that is stream attempted to depend on
371cb0ef41Sopenharmony_ci * itself.  If |stream_id| is -1, we use session->next_stream_id as
381cb0ef41Sopenharmony_ci * stream ID.
391cb0ef41Sopenharmony_ci *
401cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following
411cb0ef41Sopenharmony_ci * error codes:
421cb0ef41Sopenharmony_ci *
431cb0ef41Sopenharmony_ci * NGHTTP2_ERR_INVALID_ARGUMENT
441cb0ef41Sopenharmony_ci *   Stream attempted to depend on itself.
451cb0ef41Sopenharmony_ci */
461cb0ef41Sopenharmony_cistatic int detect_self_dependency(nghttp2_session *session, int32_t stream_id,
471cb0ef41Sopenharmony_ci                                  const nghttp2_priority_spec *pri_spec) {
481cb0ef41Sopenharmony_ci  assert(pri_spec);
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci  if (stream_id == -1) {
511cb0ef41Sopenharmony_ci    if ((int32_t)session->next_stream_id == pri_spec->stream_id) {
521cb0ef41Sopenharmony_ci      return NGHTTP2_ERR_INVALID_ARGUMENT;
531cb0ef41Sopenharmony_ci    }
541cb0ef41Sopenharmony_ci    return 0;
551cb0ef41Sopenharmony_ci  }
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci  if (stream_id == pri_spec->stream_id) {
581cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
591cb0ef41Sopenharmony_ci  }
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  return 0;
621cb0ef41Sopenharmony_ci}
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci/* This function takes ownership of |nva_copy|. Regardless of the
651cb0ef41Sopenharmony_ci   return value, the caller must not free |nva_copy| after this
661cb0ef41Sopenharmony_ci   function returns. */
671cb0ef41Sopenharmony_cistatic int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
681cb0ef41Sopenharmony_ci                                     int32_t stream_id,
691cb0ef41Sopenharmony_ci                                     const nghttp2_priority_spec *pri_spec,
701cb0ef41Sopenharmony_ci                                     nghttp2_nv *nva_copy, size_t nvlen,
711cb0ef41Sopenharmony_ci                                     const nghttp2_data_provider *data_prd,
721cb0ef41Sopenharmony_ci                                     void *stream_user_data) {
731cb0ef41Sopenharmony_ci  int rv;
741cb0ef41Sopenharmony_ci  uint8_t flags_copy;
751cb0ef41Sopenharmony_ci  nghttp2_outbound_item *item = NULL;
761cb0ef41Sopenharmony_ci  nghttp2_frame *frame = NULL;
771cb0ef41Sopenharmony_ci  nghttp2_headers_category hcat;
781cb0ef41Sopenharmony_ci  nghttp2_mem *mem;
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci  mem = &session->mem;
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci  item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
831cb0ef41Sopenharmony_ci  if (item == NULL) {
841cb0ef41Sopenharmony_ci    rv = NGHTTP2_ERR_NOMEM;
851cb0ef41Sopenharmony_ci    goto fail;
861cb0ef41Sopenharmony_ci  }
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci  nghttp2_outbound_item_init(item);
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci  if (data_prd != NULL && data_prd->read_callback != NULL) {
911cb0ef41Sopenharmony_ci    item->aux_data.headers.data_prd = *data_prd;
921cb0ef41Sopenharmony_ci  }
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci  item->aux_data.headers.stream_user_data = stream_user_data;
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci  flags_copy =
971cb0ef41Sopenharmony_ci      (uint8_t)((flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) |
981cb0ef41Sopenharmony_ci                NGHTTP2_FLAG_END_HEADERS);
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci  if (stream_id == -1) {
1011cb0ef41Sopenharmony_ci    if (session->next_stream_id > INT32_MAX) {
1021cb0ef41Sopenharmony_ci      rv = NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE;
1031cb0ef41Sopenharmony_ci      goto fail;
1041cb0ef41Sopenharmony_ci    }
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci    stream_id = (int32_t)session->next_stream_id;
1071cb0ef41Sopenharmony_ci    session->next_stream_id += 2;
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci    hcat = NGHTTP2_HCAT_REQUEST;
1101cb0ef41Sopenharmony_ci  } else {
1111cb0ef41Sopenharmony_ci    /* More specific categorization will be done later. */
1121cb0ef41Sopenharmony_ci    hcat = NGHTTP2_HCAT_HEADERS;
1131cb0ef41Sopenharmony_ci  }
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci  frame = &item->frame;
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, hcat,
1181cb0ef41Sopenharmony_ci                             pri_spec, nva_copy, nvlen);
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci  rv = nghttp2_session_add_item(session, item);
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci  if (rv != 0) {
1231cb0ef41Sopenharmony_ci    nghttp2_frame_headers_free(&frame->headers, mem);
1241cb0ef41Sopenharmony_ci    goto fail2;
1251cb0ef41Sopenharmony_ci  }
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci  if (hcat == NGHTTP2_HCAT_REQUEST) {
1281cb0ef41Sopenharmony_ci    return stream_id;
1291cb0ef41Sopenharmony_ci  }
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci  return 0;
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_cifail:
1341cb0ef41Sopenharmony_ci  /* nghttp2_frame_headers_init() takes ownership of nva_copy. */
1351cb0ef41Sopenharmony_ci  nghttp2_nv_array_del(nva_copy, mem);
1361cb0ef41Sopenharmony_cifail2:
1371cb0ef41Sopenharmony_ci  nghttp2_mem_free(mem, item);
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci  return rv;
1401cb0ef41Sopenharmony_ci}
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_cistatic int32_t submit_headers_shared_nva(nghttp2_session *session,
1431cb0ef41Sopenharmony_ci                                         uint8_t flags, int32_t stream_id,
1441cb0ef41Sopenharmony_ci                                         const nghttp2_priority_spec *pri_spec,
1451cb0ef41Sopenharmony_ci                                         const nghttp2_nv *nva, size_t nvlen,
1461cb0ef41Sopenharmony_ci                                         const nghttp2_data_provider *data_prd,
1471cb0ef41Sopenharmony_ci                                         void *stream_user_data) {
1481cb0ef41Sopenharmony_ci  int rv;
1491cb0ef41Sopenharmony_ci  nghttp2_nv *nva_copy;
1501cb0ef41Sopenharmony_ci  nghttp2_priority_spec copy_pri_spec;
1511cb0ef41Sopenharmony_ci  nghttp2_mem *mem;
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  mem = &session->mem;
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci  if (pri_spec) {
1561cb0ef41Sopenharmony_ci    copy_pri_spec = *pri_spec;
1571cb0ef41Sopenharmony_ci    nghttp2_priority_spec_normalize_weight(&copy_pri_spec);
1581cb0ef41Sopenharmony_ci  } else {
1591cb0ef41Sopenharmony_ci    nghttp2_priority_spec_default_init(&copy_pri_spec);
1601cb0ef41Sopenharmony_ci  }
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci  rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem);
1631cb0ef41Sopenharmony_ci  if (rv < 0) {
1641cb0ef41Sopenharmony_ci    return rv;
1651cb0ef41Sopenharmony_ci  }
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci  return submit_headers_shared(session, flags, stream_id, &copy_pri_spec,
1681cb0ef41Sopenharmony_ci                               nva_copy, nvlen, data_prd, stream_user_data);
1691cb0ef41Sopenharmony_ci}
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ciint nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id,
1721cb0ef41Sopenharmony_ci                           const nghttp2_nv *nva, size_t nvlen) {
1731cb0ef41Sopenharmony_ci  if (stream_id <= 0) {
1741cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
1751cb0ef41Sopenharmony_ci  }
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci  return (int)submit_headers_shared_nva(session, NGHTTP2_FLAG_END_STREAM,
1781cb0ef41Sopenharmony_ci                                        stream_id, NULL, nva, nvlen, NULL,
1791cb0ef41Sopenharmony_ci                                        NULL);
1801cb0ef41Sopenharmony_ci}
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ciint32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
1831cb0ef41Sopenharmony_ci                               int32_t stream_id,
1841cb0ef41Sopenharmony_ci                               const nghttp2_priority_spec *pri_spec,
1851cb0ef41Sopenharmony_ci                               const nghttp2_nv *nva, size_t nvlen,
1861cb0ef41Sopenharmony_ci                               void *stream_user_data) {
1871cb0ef41Sopenharmony_ci  int rv;
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci  if (stream_id == -1) {
1901cb0ef41Sopenharmony_ci    if (session->server) {
1911cb0ef41Sopenharmony_ci      return NGHTTP2_ERR_PROTO;
1921cb0ef41Sopenharmony_ci    }
1931cb0ef41Sopenharmony_ci  } else if (stream_id <= 0) {
1941cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
1951cb0ef41Sopenharmony_ci  }
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci  flags &= NGHTTP2_FLAG_END_STREAM;
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_ci  if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
2001cb0ef41Sopenharmony_ci      session->remote_settings.no_rfc7540_priorities != 1) {
2011cb0ef41Sopenharmony_ci    rv = detect_self_dependency(session, stream_id, pri_spec);
2021cb0ef41Sopenharmony_ci    if (rv != 0) {
2031cb0ef41Sopenharmony_ci      return rv;
2041cb0ef41Sopenharmony_ci    }
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci    flags |= NGHTTP2_FLAG_PRIORITY;
2071cb0ef41Sopenharmony_ci  } else {
2081cb0ef41Sopenharmony_ci    pri_spec = NULL;
2091cb0ef41Sopenharmony_ci  }
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci  return submit_headers_shared_nva(session, flags, stream_id, pri_spec, nva,
2121cb0ef41Sopenharmony_ci                                   nvlen, NULL, stream_user_data);
2131cb0ef41Sopenharmony_ci}
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ciint nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
2161cb0ef41Sopenharmony_ci                        const uint8_t *opaque_data) {
2171cb0ef41Sopenharmony_ci  flags &= NGHTTP2_FLAG_ACK;
2181cb0ef41Sopenharmony_ci  return nghttp2_session_add_ping(session, flags, opaque_data);
2191cb0ef41Sopenharmony_ci}
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ciint nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
2221cb0ef41Sopenharmony_ci                            int32_t stream_id,
2231cb0ef41Sopenharmony_ci                            const nghttp2_priority_spec *pri_spec) {
2241cb0ef41Sopenharmony_ci  int rv;
2251cb0ef41Sopenharmony_ci  nghttp2_outbound_item *item;
2261cb0ef41Sopenharmony_ci  nghttp2_frame *frame;
2271cb0ef41Sopenharmony_ci  nghttp2_priority_spec copy_pri_spec;
2281cb0ef41Sopenharmony_ci  nghttp2_mem *mem;
2291cb0ef41Sopenharmony_ci  (void)flags;
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ci  mem = &session->mem;
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci  if (session->remote_settings.no_rfc7540_priorities == 1) {
2341cb0ef41Sopenharmony_ci    return 0;
2351cb0ef41Sopenharmony_ci  }
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci  if (stream_id == 0 || pri_spec == NULL) {
2381cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
2391cb0ef41Sopenharmony_ci  }
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci  if (stream_id == pri_spec->stream_id) {
2421cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
2431cb0ef41Sopenharmony_ci  }
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci  copy_pri_spec = *pri_spec;
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci  nghttp2_priority_spec_normalize_weight(&copy_pri_spec);
2481cb0ef41Sopenharmony_ci
2491cb0ef41Sopenharmony_ci  item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci  if (item == NULL) {
2521cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_NOMEM;
2531cb0ef41Sopenharmony_ci  }
2541cb0ef41Sopenharmony_ci
2551cb0ef41Sopenharmony_ci  nghttp2_outbound_item_init(item);
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci  frame = &item->frame;
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_ci  nghttp2_frame_priority_init(&frame->priority, stream_id, &copy_pri_spec);
2601cb0ef41Sopenharmony_ci
2611cb0ef41Sopenharmony_ci  rv = nghttp2_session_add_item(session, item);
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci  if (rv != 0) {
2641cb0ef41Sopenharmony_ci    nghttp2_frame_priority_free(&frame->priority);
2651cb0ef41Sopenharmony_ci    nghttp2_mem_free(mem, item);
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci    return rv;
2681cb0ef41Sopenharmony_ci  }
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci  return 0;
2711cb0ef41Sopenharmony_ci}
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ciint nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
2741cb0ef41Sopenharmony_ci                              int32_t stream_id, uint32_t error_code) {
2751cb0ef41Sopenharmony_ci  (void)flags;
2761cb0ef41Sopenharmony_ci
2771cb0ef41Sopenharmony_ci  if (stream_id == 0) {
2781cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
2791cb0ef41Sopenharmony_ci  }
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_ci  return nghttp2_session_add_rst_stream(session, stream_id, error_code);
2821cb0ef41Sopenharmony_ci}
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ciint nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags,
2851cb0ef41Sopenharmony_ci                          int32_t last_stream_id, uint32_t error_code,
2861cb0ef41Sopenharmony_ci                          const uint8_t *opaque_data, size_t opaque_data_len) {
2871cb0ef41Sopenharmony_ci  (void)flags;
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ci  if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) {
2901cb0ef41Sopenharmony_ci    return 0;
2911cb0ef41Sopenharmony_ci  }
2921cb0ef41Sopenharmony_ci  return nghttp2_session_add_goaway(session, last_stream_id, error_code,
2931cb0ef41Sopenharmony_ci                                    opaque_data, opaque_data_len,
2941cb0ef41Sopenharmony_ci                                    NGHTTP2_GOAWAY_AUX_NONE);
2951cb0ef41Sopenharmony_ci}
2961cb0ef41Sopenharmony_ci
2971cb0ef41Sopenharmony_ciint nghttp2_submit_shutdown_notice(nghttp2_session *session) {
2981cb0ef41Sopenharmony_ci  if (!session->server) {
2991cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_STATE;
3001cb0ef41Sopenharmony_ci  }
3011cb0ef41Sopenharmony_ci  if (session->goaway_flags) {
3021cb0ef41Sopenharmony_ci    return 0;
3031cb0ef41Sopenharmony_ci  }
3041cb0ef41Sopenharmony_ci  return nghttp2_session_add_goaway(session, (1u << 31) - 1, NGHTTP2_NO_ERROR,
3051cb0ef41Sopenharmony_ci                                    NULL, 0,
3061cb0ef41Sopenharmony_ci                                    NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE);
3071cb0ef41Sopenharmony_ci}
3081cb0ef41Sopenharmony_ci
3091cb0ef41Sopenharmony_ciint nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
3101cb0ef41Sopenharmony_ci                            const nghttp2_settings_entry *iv, size_t niv) {
3111cb0ef41Sopenharmony_ci  (void)flags;
3121cb0ef41Sopenharmony_ci  return nghttp2_session_add_settings(session, NGHTTP2_FLAG_NONE, iv, niv);
3131cb0ef41Sopenharmony_ci}
3141cb0ef41Sopenharmony_ci
3151cb0ef41Sopenharmony_ciint32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
3161cb0ef41Sopenharmony_ci                                    int32_t stream_id, const nghttp2_nv *nva,
3171cb0ef41Sopenharmony_ci                                    size_t nvlen,
3181cb0ef41Sopenharmony_ci                                    void *promised_stream_user_data) {
3191cb0ef41Sopenharmony_ci  nghttp2_outbound_item *item;
3201cb0ef41Sopenharmony_ci  nghttp2_frame *frame;
3211cb0ef41Sopenharmony_ci  nghttp2_nv *nva_copy;
3221cb0ef41Sopenharmony_ci  uint8_t flags_copy;
3231cb0ef41Sopenharmony_ci  int32_t promised_stream_id;
3241cb0ef41Sopenharmony_ci  int rv;
3251cb0ef41Sopenharmony_ci  nghttp2_mem *mem;
3261cb0ef41Sopenharmony_ci  (void)flags;
3271cb0ef41Sopenharmony_ci
3281cb0ef41Sopenharmony_ci  mem = &session->mem;
3291cb0ef41Sopenharmony_ci
3301cb0ef41Sopenharmony_ci  if (stream_id <= 0 || nghttp2_session_is_my_stream_id(session, stream_id)) {
3311cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
3321cb0ef41Sopenharmony_ci  }
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ci  if (!session->server) {
3351cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_PROTO;
3361cb0ef41Sopenharmony_ci  }
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_ci  /* All 32bit signed stream IDs are spent. */
3391cb0ef41Sopenharmony_ci  if (session->next_stream_id > INT32_MAX) {
3401cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE;
3411cb0ef41Sopenharmony_ci  }
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_ci  item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
3441cb0ef41Sopenharmony_ci  if (item == NULL) {
3451cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_NOMEM;
3461cb0ef41Sopenharmony_ci  }
3471cb0ef41Sopenharmony_ci
3481cb0ef41Sopenharmony_ci  nghttp2_outbound_item_init(item);
3491cb0ef41Sopenharmony_ci
3501cb0ef41Sopenharmony_ci  item->aux_data.headers.stream_user_data = promised_stream_user_data;
3511cb0ef41Sopenharmony_ci
3521cb0ef41Sopenharmony_ci  frame = &item->frame;
3531cb0ef41Sopenharmony_ci
3541cb0ef41Sopenharmony_ci  rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem);
3551cb0ef41Sopenharmony_ci  if (rv < 0) {
3561cb0ef41Sopenharmony_ci    nghttp2_mem_free(mem, item);
3571cb0ef41Sopenharmony_ci    return rv;
3581cb0ef41Sopenharmony_ci  }
3591cb0ef41Sopenharmony_ci
3601cb0ef41Sopenharmony_ci  flags_copy = NGHTTP2_FLAG_END_HEADERS;
3611cb0ef41Sopenharmony_ci
3621cb0ef41Sopenharmony_ci  promised_stream_id = (int32_t)session->next_stream_id;
3631cb0ef41Sopenharmony_ci  session->next_stream_id += 2;
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_ci  nghttp2_frame_push_promise_init(&frame->push_promise, flags_copy, stream_id,
3661cb0ef41Sopenharmony_ci                                  promised_stream_id, nva_copy, nvlen);
3671cb0ef41Sopenharmony_ci
3681cb0ef41Sopenharmony_ci  rv = nghttp2_session_add_item(session, item);
3691cb0ef41Sopenharmony_ci
3701cb0ef41Sopenharmony_ci  if (rv != 0) {
3711cb0ef41Sopenharmony_ci    nghttp2_frame_push_promise_free(&frame->push_promise, mem);
3721cb0ef41Sopenharmony_ci    nghttp2_mem_free(mem, item);
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ci    return rv;
3751cb0ef41Sopenharmony_ci  }
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_ci  return promised_stream_id;
3781cb0ef41Sopenharmony_ci}
3791cb0ef41Sopenharmony_ci
3801cb0ef41Sopenharmony_ciint nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
3811cb0ef41Sopenharmony_ci                                 int32_t stream_id,
3821cb0ef41Sopenharmony_ci                                 int32_t window_size_increment) {
3831cb0ef41Sopenharmony_ci  int rv;
3841cb0ef41Sopenharmony_ci  nghttp2_stream *stream = 0;
3851cb0ef41Sopenharmony_ci  (void)flags;
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_ci  if (window_size_increment == 0) {
3881cb0ef41Sopenharmony_ci    return 0;
3891cb0ef41Sopenharmony_ci  }
3901cb0ef41Sopenharmony_ci  if (stream_id == 0) {
3911cb0ef41Sopenharmony_ci    rv = nghttp2_adjust_local_window_size(
3921cb0ef41Sopenharmony_ci        &session->local_window_size, &session->recv_window_size,
3931cb0ef41Sopenharmony_ci        &session->recv_reduction, &window_size_increment);
3941cb0ef41Sopenharmony_ci    if (rv != 0) {
3951cb0ef41Sopenharmony_ci      return rv;
3961cb0ef41Sopenharmony_ci    }
3971cb0ef41Sopenharmony_ci  } else {
3981cb0ef41Sopenharmony_ci    stream = nghttp2_session_get_stream(session, stream_id);
3991cb0ef41Sopenharmony_ci    if (!stream) {
4001cb0ef41Sopenharmony_ci      return 0;
4011cb0ef41Sopenharmony_ci    }
4021cb0ef41Sopenharmony_ci
4031cb0ef41Sopenharmony_ci    rv = nghttp2_adjust_local_window_size(
4041cb0ef41Sopenharmony_ci        &stream->local_window_size, &stream->recv_window_size,
4051cb0ef41Sopenharmony_ci        &stream->recv_reduction, &window_size_increment);
4061cb0ef41Sopenharmony_ci    if (rv != 0) {
4071cb0ef41Sopenharmony_ci      return rv;
4081cb0ef41Sopenharmony_ci    }
4091cb0ef41Sopenharmony_ci  }
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci  if (window_size_increment > 0) {
4121cb0ef41Sopenharmony_ci    if (stream_id == 0) {
4131cb0ef41Sopenharmony_ci      session->consumed_size =
4141cb0ef41Sopenharmony_ci          nghttp2_max(0, session->consumed_size - window_size_increment);
4151cb0ef41Sopenharmony_ci    } else {
4161cb0ef41Sopenharmony_ci      stream->consumed_size =
4171cb0ef41Sopenharmony_ci          nghttp2_max(0, stream->consumed_size - window_size_increment);
4181cb0ef41Sopenharmony_ci    }
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ci    return nghttp2_session_add_window_update(session, 0, stream_id,
4211cb0ef41Sopenharmony_ci                                             window_size_increment);
4221cb0ef41Sopenharmony_ci  }
4231cb0ef41Sopenharmony_ci  return 0;
4241cb0ef41Sopenharmony_ci}
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ciint nghttp2_session_set_local_window_size(nghttp2_session *session,
4271cb0ef41Sopenharmony_ci                                          uint8_t flags, int32_t stream_id,
4281cb0ef41Sopenharmony_ci                                          int32_t window_size) {
4291cb0ef41Sopenharmony_ci  int32_t window_size_increment;
4301cb0ef41Sopenharmony_ci  nghttp2_stream *stream;
4311cb0ef41Sopenharmony_ci  int rv;
4321cb0ef41Sopenharmony_ci  (void)flags;
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_ci  if (window_size < 0) {
4351cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
4361cb0ef41Sopenharmony_ci  }
4371cb0ef41Sopenharmony_ci
4381cb0ef41Sopenharmony_ci  if (stream_id == 0) {
4391cb0ef41Sopenharmony_ci    window_size_increment = window_size - session->local_window_size;
4401cb0ef41Sopenharmony_ci
4411cb0ef41Sopenharmony_ci    if (window_size_increment == 0) {
4421cb0ef41Sopenharmony_ci      return 0;
4431cb0ef41Sopenharmony_ci    }
4441cb0ef41Sopenharmony_ci
4451cb0ef41Sopenharmony_ci    if (window_size_increment < 0) {
4461cb0ef41Sopenharmony_ci      return nghttp2_adjust_local_window_size(
4471cb0ef41Sopenharmony_ci          &session->local_window_size, &session->recv_window_size,
4481cb0ef41Sopenharmony_ci          &session->recv_reduction, &window_size_increment);
4491cb0ef41Sopenharmony_ci    }
4501cb0ef41Sopenharmony_ci
4511cb0ef41Sopenharmony_ci    rv = nghttp2_increase_local_window_size(
4521cb0ef41Sopenharmony_ci        &session->local_window_size, &session->recv_window_size,
4531cb0ef41Sopenharmony_ci        &session->recv_reduction, &window_size_increment);
4541cb0ef41Sopenharmony_ci
4551cb0ef41Sopenharmony_ci    if (rv != 0) {
4561cb0ef41Sopenharmony_ci      return rv;
4571cb0ef41Sopenharmony_ci    }
4581cb0ef41Sopenharmony_ci
4591cb0ef41Sopenharmony_ci    if (window_size_increment > 0) {
4601cb0ef41Sopenharmony_ci      return nghttp2_session_add_window_update(session, 0, stream_id,
4611cb0ef41Sopenharmony_ci                                               window_size_increment);
4621cb0ef41Sopenharmony_ci    }
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_ci    return nghttp2_session_update_recv_connection_window_size(session, 0);
4651cb0ef41Sopenharmony_ci  } else {
4661cb0ef41Sopenharmony_ci    stream = nghttp2_session_get_stream(session, stream_id);
4671cb0ef41Sopenharmony_ci
4681cb0ef41Sopenharmony_ci    if (stream == NULL) {
4691cb0ef41Sopenharmony_ci      return 0;
4701cb0ef41Sopenharmony_ci    }
4711cb0ef41Sopenharmony_ci
4721cb0ef41Sopenharmony_ci    window_size_increment = window_size - stream->local_window_size;
4731cb0ef41Sopenharmony_ci
4741cb0ef41Sopenharmony_ci    if (window_size_increment == 0) {
4751cb0ef41Sopenharmony_ci      return 0;
4761cb0ef41Sopenharmony_ci    }
4771cb0ef41Sopenharmony_ci
4781cb0ef41Sopenharmony_ci    if (window_size_increment < 0) {
4791cb0ef41Sopenharmony_ci      return nghttp2_adjust_local_window_size(
4801cb0ef41Sopenharmony_ci          &stream->local_window_size, &stream->recv_window_size,
4811cb0ef41Sopenharmony_ci          &stream->recv_reduction, &window_size_increment);
4821cb0ef41Sopenharmony_ci    }
4831cb0ef41Sopenharmony_ci
4841cb0ef41Sopenharmony_ci    rv = nghttp2_increase_local_window_size(
4851cb0ef41Sopenharmony_ci        &stream->local_window_size, &stream->recv_window_size,
4861cb0ef41Sopenharmony_ci        &stream->recv_reduction, &window_size_increment);
4871cb0ef41Sopenharmony_ci
4881cb0ef41Sopenharmony_ci    if (rv != 0) {
4891cb0ef41Sopenharmony_ci      return rv;
4901cb0ef41Sopenharmony_ci    }
4911cb0ef41Sopenharmony_ci
4921cb0ef41Sopenharmony_ci    if (window_size_increment > 0) {
4931cb0ef41Sopenharmony_ci      return nghttp2_session_add_window_update(session, 0, stream_id,
4941cb0ef41Sopenharmony_ci                                               window_size_increment);
4951cb0ef41Sopenharmony_ci    }
4961cb0ef41Sopenharmony_ci
4971cb0ef41Sopenharmony_ci    return nghttp2_session_update_recv_stream_window_size(session, stream, 0,
4981cb0ef41Sopenharmony_ci                                                          1);
4991cb0ef41Sopenharmony_ci  }
5001cb0ef41Sopenharmony_ci}
5011cb0ef41Sopenharmony_ci
5021cb0ef41Sopenharmony_ciint nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
5031cb0ef41Sopenharmony_ci                          int32_t stream_id, const uint8_t *origin,
5041cb0ef41Sopenharmony_ci                          size_t origin_len, const uint8_t *field_value,
5051cb0ef41Sopenharmony_ci                          size_t field_value_len) {
5061cb0ef41Sopenharmony_ci  nghttp2_mem *mem;
5071cb0ef41Sopenharmony_ci  uint8_t *buf, *p;
5081cb0ef41Sopenharmony_ci  uint8_t *origin_copy;
5091cb0ef41Sopenharmony_ci  uint8_t *field_value_copy;
5101cb0ef41Sopenharmony_ci  nghttp2_outbound_item *item;
5111cb0ef41Sopenharmony_ci  nghttp2_frame *frame;
5121cb0ef41Sopenharmony_ci  nghttp2_ext_altsvc *altsvc;
5131cb0ef41Sopenharmony_ci  int rv;
5141cb0ef41Sopenharmony_ci  (void)flags;
5151cb0ef41Sopenharmony_ci
5161cb0ef41Sopenharmony_ci  mem = &session->mem;
5171cb0ef41Sopenharmony_ci
5181cb0ef41Sopenharmony_ci  if (!session->server) {
5191cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_STATE;
5201cb0ef41Sopenharmony_ci  }
5211cb0ef41Sopenharmony_ci
5221cb0ef41Sopenharmony_ci  if (2 + origin_len + field_value_len > NGHTTP2_MAX_PAYLOADLEN) {
5231cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
5241cb0ef41Sopenharmony_ci  }
5251cb0ef41Sopenharmony_ci
5261cb0ef41Sopenharmony_ci  if (stream_id == 0) {
5271cb0ef41Sopenharmony_ci    if (origin_len == 0) {
5281cb0ef41Sopenharmony_ci      return NGHTTP2_ERR_INVALID_ARGUMENT;
5291cb0ef41Sopenharmony_ci    }
5301cb0ef41Sopenharmony_ci  } else if (origin_len != 0) {
5311cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
5321cb0ef41Sopenharmony_ci  }
5331cb0ef41Sopenharmony_ci
5341cb0ef41Sopenharmony_ci  buf = nghttp2_mem_malloc(mem, origin_len + field_value_len + 2);
5351cb0ef41Sopenharmony_ci  if (buf == NULL) {
5361cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_NOMEM;
5371cb0ef41Sopenharmony_ci  }
5381cb0ef41Sopenharmony_ci
5391cb0ef41Sopenharmony_ci  p = buf;
5401cb0ef41Sopenharmony_ci
5411cb0ef41Sopenharmony_ci  origin_copy = p;
5421cb0ef41Sopenharmony_ci  if (origin_len) {
5431cb0ef41Sopenharmony_ci    p = nghttp2_cpymem(p, origin, origin_len);
5441cb0ef41Sopenharmony_ci  }
5451cb0ef41Sopenharmony_ci  *p++ = '\0';
5461cb0ef41Sopenharmony_ci
5471cb0ef41Sopenharmony_ci  field_value_copy = p;
5481cb0ef41Sopenharmony_ci  if (field_value_len) {
5491cb0ef41Sopenharmony_ci    p = nghttp2_cpymem(p, field_value, field_value_len);
5501cb0ef41Sopenharmony_ci  }
5511cb0ef41Sopenharmony_ci  *p++ = '\0';
5521cb0ef41Sopenharmony_ci
5531cb0ef41Sopenharmony_ci  item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
5541cb0ef41Sopenharmony_ci  if (item == NULL) {
5551cb0ef41Sopenharmony_ci    rv = NGHTTP2_ERR_NOMEM;
5561cb0ef41Sopenharmony_ci    goto fail_item_malloc;
5571cb0ef41Sopenharmony_ci  }
5581cb0ef41Sopenharmony_ci
5591cb0ef41Sopenharmony_ci  nghttp2_outbound_item_init(item);
5601cb0ef41Sopenharmony_ci
5611cb0ef41Sopenharmony_ci  item->aux_data.ext.builtin = 1;
5621cb0ef41Sopenharmony_ci
5631cb0ef41Sopenharmony_ci  altsvc = &item->ext_frame_payload.altsvc;
5641cb0ef41Sopenharmony_ci
5651cb0ef41Sopenharmony_ci  frame = &item->frame;
5661cb0ef41Sopenharmony_ci  frame->ext.payload = altsvc;
5671cb0ef41Sopenharmony_ci
5681cb0ef41Sopenharmony_ci  nghttp2_frame_altsvc_init(&frame->ext, stream_id, origin_copy, origin_len,
5691cb0ef41Sopenharmony_ci                            field_value_copy, field_value_len);
5701cb0ef41Sopenharmony_ci
5711cb0ef41Sopenharmony_ci  rv = nghttp2_session_add_item(session, item);
5721cb0ef41Sopenharmony_ci  if (rv != 0) {
5731cb0ef41Sopenharmony_ci    nghttp2_frame_altsvc_free(&frame->ext, mem);
5741cb0ef41Sopenharmony_ci    nghttp2_mem_free(mem, item);
5751cb0ef41Sopenharmony_ci
5761cb0ef41Sopenharmony_ci    return rv;
5771cb0ef41Sopenharmony_ci  }
5781cb0ef41Sopenharmony_ci
5791cb0ef41Sopenharmony_ci  return 0;
5801cb0ef41Sopenharmony_ci
5811cb0ef41Sopenharmony_cifail_item_malloc:
5821cb0ef41Sopenharmony_ci  free(buf);
5831cb0ef41Sopenharmony_ci
5841cb0ef41Sopenharmony_ci  return rv;
5851cb0ef41Sopenharmony_ci}
5861cb0ef41Sopenharmony_ci
5871cb0ef41Sopenharmony_ciint nghttp2_submit_origin(nghttp2_session *session, uint8_t flags,
5881cb0ef41Sopenharmony_ci                          const nghttp2_origin_entry *ov, size_t nov) {
5891cb0ef41Sopenharmony_ci  nghttp2_mem *mem;
5901cb0ef41Sopenharmony_ci  uint8_t *p;
5911cb0ef41Sopenharmony_ci  nghttp2_outbound_item *item;
5921cb0ef41Sopenharmony_ci  nghttp2_frame *frame;
5931cb0ef41Sopenharmony_ci  nghttp2_ext_origin *origin;
5941cb0ef41Sopenharmony_ci  nghttp2_origin_entry *ov_copy;
5951cb0ef41Sopenharmony_ci  size_t len = 0;
5961cb0ef41Sopenharmony_ci  size_t i;
5971cb0ef41Sopenharmony_ci  int rv;
5981cb0ef41Sopenharmony_ci  (void)flags;
5991cb0ef41Sopenharmony_ci
6001cb0ef41Sopenharmony_ci  mem = &session->mem;
6011cb0ef41Sopenharmony_ci
6021cb0ef41Sopenharmony_ci  if (!session->server) {
6031cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_STATE;
6041cb0ef41Sopenharmony_ci  }
6051cb0ef41Sopenharmony_ci
6061cb0ef41Sopenharmony_ci  if (nov) {
6071cb0ef41Sopenharmony_ci    for (i = 0; i < nov; ++i) {
6081cb0ef41Sopenharmony_ci      len += ov[i].origin_len;
6091cb0ef41Sopenharmony_ci    }
6101cb0ef41Sopenharmony_ci
6111cb0ef41Sopenharmony_ci    if (2 * nov + len > NGHTTP2_MAX_PAYLOADLEN) {
6121cb0ef41Sopenharmony_ci      return NGHTTP2_ERR_INVALID_ARGUMENT;
6131cb0ef41Sopenharmony_ci    }
6141cb0ef41Sopenharmony_ci
6151cb0ef41Sopenharmony_ci    /* The last nov is added for terminal NULL character. */
6161cb0ef41Sopenharmony_ci    ov_copy =
6171cb0ef41Sopenharmony_ci        nghttp2_mem_malloc(mem, nov * sizeof(nghttp2_origin_entry) + len + nov);
6181cb0ef41Sopenharmony_ci    if (ov_copy == NULL) {
6191cb0ef41Sopenharmony_ci      return NGHTTP2_ERR_NOMEM;
6201cb0ef41Sopenharmony_ci    }
6211cb0ef41Sopenharmony_ci
6221cb0ef41Sopenharmony_ci    p = (uint8_t *)ov_copy + nov * sizeof(nghttp2_origin_entry);
6231cb0ef41Sopenharmony_ci
6241cb0ef41Sopenharmony_ci    for (i = 0; i < nov; ++i) {
6251cb0ef41Sopenharmony_ci      ov_copy[i].origin = p;
6261cb0ef41Sopenharmony_ci      ov_copy[i].origin_len = ov[i].origin_len;
6271cb0ef41Sopenharmony_ci      p = nghttp2_cpymem(p, ov[i].origin, ov[i].origin_len);
6281cb0ef41Sopenharmony_ci      *p++ = '\0';
6291cb0ef41Sopenharmony_ci    }
6301cb0ef41Sopenharmony_ci
6311cb0ef41Sopenharmony_ci    assert((size_t)(p - (uint8_t *)ov_copy) ==
6321cb0ef41Sopenharmony_ci           nov * sizeof(nghttp2_origin_entry) + len + nov);
6331cb0ef41Sopenharmony_ci  } else {
6341cb0ef41Sopenharmony_ci    ov_copy = NULL;
6351cb0ef41Sopenharmony_ci  }
6361cb0ef41Sopenharmony_ci
6371cb0ef41Sopenharmony_ci  item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
6381cb0ef41Sopenharmony_ci  if (item == NULL) {
6391cb0ef41Sopenharmony_ci    rv = NGHTTP2_ERR_NOMEM;
6401cb0ef41Sopenharmony_ci    goto fail_item_malloc;
6411cb0ef41Sopenharmony_ci  }
6421cb0ef41Sopenharmony_ci
6431cb0ef41Sopenharmony_ci  nghttp2_outbound_item_init(item);
6441cb0ef41Sopenharmony_ci
6451cb0ef41Sopenharmony_ci  item->aux_data.ext.builtin = 1;
6461cb0ef41Sopenharmony_ci
6471cb0ef41Sopenharmony_ci  origin = &item->ext_frame_payload.origin;
6481cb0ef41Sopenharmony_ci
6491cb0ef41Sopenharmony_ci  frame = &item->frame;
6501cb0ef41Sopenharmony_ci  frame->ext.payload = origin;
6511cb0ef41Sopenharmony_ci
6521cb0ef41Sopenharmony_ci  nghttp2_frame_origin_init(&frame->ext, ov_copy, nov);
6531cb0ef41Sopenharmony_ci
6541cb0ef41Sopenharmony_ci  rv = nghttp2_session_add_item(session, item);
6551cb0ef41Sopenharmony_ci  if (rv != 0) {
6561cb0ef41Sopenharmony_ci    nghttp2_frame_origin_free(&frame->ext, mem);
6571cb0ef41Sopenharmony_ci    nghttp2_mem_free(mem, item);
6581cb0ef41Sopenharmony_ci
6591cb0ef41Sopenharmony_ci    return rv;
6601cb0ef41Sopenharmony_ci  }
6611cb0ef41Sopenharmony_ci
6621cb0ef41Sopenharmony_ci  return 0;
6631cb0ef41Sopenharmony_ci
6641cb0ef41Sopenharmony_cifail_item_malloc:
6651cb0ef41Sopenharmony_ci  free(ov_copy);
6661cb0ef41Sopenharmony_ci
6671cb0ef41Sopenharmony_ci  return rv;
6681cb0ef41Sopenharmony_ci}
6691cb0ef41Sopenharmony_ci
6701cb0ef41Sopenharmony_ciint nghttp2_submit_priority_update(nghttp2_session *session, uint8_t flags,
6711cb0ef41Sopenharmony_ci                                   int32_t stream_id,
6721cb0ef41Sopenharmony_ci                                   const uint8_t *field_value,
6731cb0ef41Sopenharmony_ci                                   size_t field_value_len) {
6741cb0ef41Sopenharmony_ci  nghttp2_mem *mem;
6751cb0ef41Sopenharmony_ci  uint8_t *buf, *p;
6761cb0ef41Sopenharmony_ci  nghttp2_outbound_item *item;
6771cb0ef41Sopenharmony_ci  nghttp2_frame *frame;
6781cb0ef41Sopenharmony_ci  nghttp2_ext_priority_update *priority_update;
6791cb0ef41Sopenharmony_ci  int rv;
6801cb0ef41Sopenharmony_ci  (void)flags;
6811cb0ef41Sopenharmony_ci
6821cb0ef41Sopenharmony_ci  mem = &session->mem;
6831cb0ef41Sopenharmony_ci
6841cb0ef41Sopenharmony_ci  if (session->server) {
6851cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_STATE;
6861cb0ef41Sopenharmony_ci  }
6871cb0ef41Sopenharmony_ci
6881cb0ef41Sopenharmony_ci  if (session->remote_settings.no_rfc7540_priorities == 0) {
6891cb0ef41Sopenharmony_ci    return 0;
6901cb0ef41Sopenharmony_ci  }
6911cb0ef41Sopenharmony_ci
6921cb0ef41Sopenharmony_ci  if (stream_id == 0 || 4 + field_value_len > NGHTTP2_MAX_PAYLOADLEN) {
6931cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
6941cb0ef41Sopenharmony_ci  }
6951cb0ef41Sopenharmony_ci
6961cb0ef41Sopenharmony_ci  if (field_value_len) {
6971cb0ef41Sopenharmony_ci    buf = nghttp2_mem_malloc(mem, field_value_len + 1);
6981cb0ef41Sopenharmony_ci    if (buf == NULL) {
6991cb0ef41Sopenharmony_ci      return NGHTTP2_ERR_NOMEM;
7001cb0ef41Sopenharmony_ci    }
7011cb0ef41Sopenharmony_ci
7021cb0ef41Sopenharmony_ci    p = nghttp2_cpymem(buf, field_value, field_value_len);
7031cb0ef41Sopenharmony_ci    *p = '\0';
7041cb0ef41Sopenharmony_ci  } else {
7051cb0ef41Sopenharmony_ci    buf = NULL;
7061cb0ef41Sopenharmony_ci  }
7071cb0ef41Sopenharmony_ci
7081cb0ef41Sopenharmony_ci  item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
7091cb0ef41Sopenharmony_ci  if (item == NULL) {
7101cb0ef41Sopenharmony_ci    rv = NGHTTP2_ERR_NOMEM;
7111cb0ef41Sopenharmony_ci    goto fail_item_malloc;
7121cb0ef41Sopenharmony_ci  }
7131cb0ef41Sopenharmony_ci
7141cb0ef41Sopenharmony_ci  nghttp2_outbound_item_init(item);
7151cb0ef41Sopenharmony_ci
7161cb0ef41Sopenharmony_ci  item->aux_data.ext.builtin = 1;
7171cb0ef41Sopenharmony_ci
7181cb0ef41Sopenharmony_ci  priority_update = &item->ext_frame_payload.priority_update;
7191cb0ef41Sopenharmony_ci
7201cb0ef41Sopenharmony_ci  frame = &item->frame;
7211cb0ef41Sopenharmony_ci  frame->ext.payload = priority_update;
7221cb0ef41Sopenharmony_ci
7231cb0ef41Sopenharmony_ci  nghttp2_frame_priority_update_init(&frame->ext, stream_id, buf,
7241cb0ef41Sopenharmony_ci                                     field_value_len);
7251cb0ef41Sopenharmony_ci
7261cb0ef41Sopenharmony_ci  rv = nghttp2_session_add_item(session, item);
7271cb0ef41Sopenharmony_ci  if (rv != 0) {
7281cb0ef41Sopenharmony_ci    nghttp2_frame_priority_update_free(&frame->ext, mem);
7291cb0ef41Sopenharmony_ci    nghttp2_mem_free(mem, item);
7301cb0ef41Sopenharmony_ci
7311cb0ef41Sopenharmony_ci    return rv;
7321cb0ef41Sopenharmony_ci  }
7331cb0ef41Sopenharmony_ci
7341cb0ef41Sopenharmony_ci  return 0;
7351cb0ef41Sopenharmony_ci
7361cb0ef41Sopenharmony_cifail_item_malloc:
7371cb0ef41Sopenharmony_ci  free(buf);
7381cb0ef41Sopenharmony_ci
7391cb0ef41Sopenharmony_ci  return rv;
7401cb0ef41Sopenharmony_ci}
7411cb0ef41Sopenharmony_ci
7421cb0ef41Sopenharmony_cistatic uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
7431cb0ef41Sopenharmony_ci                                 const nghttp2_data_provider *data_prd) {
7441cb0ef41Sopenharmony_ci  uint8_t flags = NGHTTP2_FLAG_NONE;
7451cb0ef41Sopenharmony_ci  if (data_prd == NULL || data_prd->read_callback == NULL) {
7461cb0ef41Sopenharmony_ci    flags |= NGHTTP2_FLAG_END_STREAM;
7471cb0ef41Sopenharmony_ci  }
7481cb0ef41Sopenharmony_ci
7491cb0ef41Sopenharmony_ci  if (pri_spec) {
7501cb0ef41Sopenharmony_ci    flags |= NGHTTP2_FLAG_PRIORITY;
7511cb0ef41Sopenharmony_ci  }
7521cb0ef41Sopenharmony_ci
7531cb0ef41Sopenharmony_ci  return flags;
7541cb0ef41Sopenharmony_ci}
7551cb0ef41Sopenharmony_ci
7561cb0ef41Sopenharmony_ciint32_t nghttp2_submit_request(nghttp2_session *session,
7571cb0ef41Sopenharmony_ci                               const nghttp2_priority_spec *pri_spec,
7581cb0ef41Sopenharmony_ci                               const nghttp2_nv *nva, size_t nvlen,
7591cb0ef41Sopenharmony_ci                               const nghttp2_data_provider *data_prd,
7601cb0ef41Sopenharmony_ci                               void *stream_user_data) {
7611cb0ef41Sopenharmony_ci  uint8_t flags;
7621cb0ef41Sopenharmony_ci  int rv;
7631cb0ef41Sopenharmony_ci
7641cb0ef41Sopenharmony_ci  if (session->server) {
7651cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_PROTO;
7661cb0ef41Sopenharmony_ci  }
7671cb0ef41Sopenharmony_ci
7681cb0ef41Sopenharmony_ci  if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
7691cb0ef41Sopenharmony_ci      session->remote_settings.no_rfc7540_priorities != 1) {
7701cb0ef41Sopenharmony_ci    rv = detect_self_dependency(session, -1, pri_spec);
7711cb0ef41Sopenharmony_ci    if (rv != 0) {
7721cb0ef41Sopenharmony_ci      return rv;
7731cb0ef41Sopenharmony_ci    }
7741cb0ef41Sopenharmony_ci  } else {
7751cb0ef41Sopenharmony_ci    pri_spec = NULL;
7761cb0ef41Sopenharmony_ci  }
7771cb0ef41Sopenharmony_ci
7781cb0ef41Sopenharmony_ci  flags = set_request_flags(pri_spec, data_prd);
7791cb0ef41Sopenharmony_ci
7801cb0ef41Sopenharmony_ci  return submit_headers_shared_nva(session, flags, -1, pri_spec, nva, nvlen,
7811cb0ef41Sopenharmony_ci                                   data_prd, stream_user_data);
7821cb0ef41Sopenharmony_ci}
7831cb0ef41Sopenharmony_ci
7841cb0ef41Sopenharmony_cistatic uint8_t set_response_flags(const nghttp2_data_provider *data_prd) {
7851cb0ef41Sopenharmony_ci  uint8_t flags = NGHTTP2_FLAG_NONE;
7861cb0ef41Sopenharmony_ci  if (data_prd == NULL || data_prd->read_callback == NULL) {
7871cb0ef41Sopenharmony_ci    flags |= NGHTTP2_FLAG_END_STREAM;
7881cb0ef41Sopenharmony_ci  }
7891cb0ef41Sopenharmony_ci  return flags;
7901cb0ef41Sopenharmony_ci}
7911cb0ef41Sopenharmony_ci
7921cb0ef41Sopenharmony_ciint nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
7931cb0ef41Sopenharmony_ci                            const nghttp2_nv *nva, size_t nvlen,
7941cb0ef41Sopenharmony_ci                            const nghttp2_data_provider *data_prd) {
7951cb0ef41Sopenharmony_ci  uint8_t flags;
7961cb0ef41Sopenharmony_ci
7971cb0ef41Sopenharmony_ci  if (stream_id <= 0) {
7981cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
7991cb0ef41Sopenharmony_ci  }
8001cb0ef41Sopenharmony_ci
8011cb0ef41Sopenharmony_ci  if (!session->server) {
8021cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_PROTO;
8031cb0ef41Sopenharmony_ci  }
8041cb0ef41Sopenharmony_ci
8051cb0ef41Sopenharmony_ci  flags = set_response_flags(data_prd);
8061cb0ef41Sopenharmony_ci  return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen,
8071cb0ef41Sopenharmony_ci                                   data_prd, NULL);
8081cb0ef41Sopenharmony_ci}
8091cb0ef41Sopenharmony_ci
8101cb0ef41Sopenharmony_ciint nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
8111cb0ef41Sopenharmony_ci                        int32_t stream_id,
8121cb0ef41Sopenharmony_ci                        const nghttp2_data_provider *data_prd) {
8131cb0ef41Sopenharmony_ci  int rv;
8141cb0ef41Sopenharmony_ci  nghttp2_outbound_item *item;
8151cb0ef41Sopenharmony_ci  nghttp2_frame *frame;
8161cb0ef41Sopenharmony_ci  nghttp2_data_aux_data *aux_data;
8171cb0ef41Sopenharmony_ci  uint8_t nflags = flags & NGHTTP2_FLAG_END_STREAM;
8181cb0ef41Sopenharmony_ci  nghttp2_mem *mem;
8191cb0ef41Sopenharmony_ci
8201cb0ef41Sopenharmony_ci  mem = &session->mem;
8211cb0ef41Sopenharmony_ci
8221cb0ef41Sopenharmony_ci  if (stream_id == 0) {
8231cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
8241cb0ef41Sopenharmony_ci  }
8251cb0ef41Sopenharmony_ci
8261cb0ef41Sopenharmony_ci  item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
8271cb0ef41Sopenharmony_ci  if (item == NULL) {
8281cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_NOMEM;
8291cb0ef41Sopenharmony_ci  }
8301cb0ef41Sopenharmony_ci
8311cb0ef41Sopenharmony_ci  nghttp2_outbound_item_init(item);
8321cb0ef41Sopenharmony_ci
8331cb0ef41Sopenharmony_ci  frame = &item->frame;
8341cb0ef41Sopenharmony_ci  aux_data = &item->aux_data.data;
8351cb0ef41Sopenharmony_ci  aux_data->data_prd = *data_prd;
8361cb0ef41Sopenharmony_ci  aux_data->eof = 0;
8371cb0ef41Sopenharmony_ci  aux_data->flags = nflags;
8381cb0ef41Sopenharmony_ci
8391cb0ef41Sopenharmony_ci  /* flags are sent on transmission */
8401cb0ef41Sopenharmony_ci  nghttp2_frame_data_init(&frame->data, NGHTTP2_FLAG_NONE, stream_id);
8411cb0ef41Sopenharmony_ci
8421cb0ef41Sopenharmony_ci  rv = nghttp2_session_add_item(session, item);
8431cb0ef41Sopenharmony_ci  if (rv != 0) {
8441cb0ef41Sopenharmony_ci    nghttp2_frame_data_free(&frame->data);
8451cb0ef41Sopenharmony_ci    nghttp2_mem_free(mem, item);
8461cb0ef41Sopenharmony_ci    return rv;
8471cb0ef41Sopenharmony_ci  }
8481cb0ef41Sopenharmony_ci  return 0;
8491cb0ef41Sopenharmony_ci}
8501cb0ef41Sopenharmony_ci
8511cb0ef41Sopenharmony_cissize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
8521cb0ef41Sopenharmony_ci                                      const nghttp2_settings_entry *iv,
8531cb0ef41Sopenharmony_ci                                      size_t niv) {
8541cb0ef41Sopenharmony_ci  if (!nghttp2_iv_check(iv, niv)) {
8551cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
8561cb0ef41Sopenharmony_ci  }
8571cb0ef41Sopenharmony_ci
8581cb0ef41Sopenharmony_ci  if (buflen < (niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH)) {
8591cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INSUFF_BUFSIZE;
8601cb0ef41Sopenharmony_ci  }
8611cb0ef41Sopenharmony_ci
8621cb0ef41Sopenharmony_ci  return (ssize_t)nghttp2_frame_pack_settings_payload(buf, iv, niv);
8631cb0ef41Sopenharmony_ci}
8641cb0ef41Sopenharmony_ci
8651cb0ef41Sopenharmony_ciint nghttp2_submit_extension(nghttp2_session *session, uint8_t type,
8661cb0ef41Sopenharmony_ci                             uint8_t flags, int32_t stream_id, void *payload) {
8671cb0ef41Sopenharmony_ci  int rv;
8681cb0ef41Sopenharmony_ci  nghttp2_outbound_item *item;
8691cb0ef41Sopenharmony_ci  nghttp2_frame *frame;
8701cb0ef41Sopenharmony_ci  nghttp2_mem *mem;
8711cb0ef41Sopenharmony_ci
8721cb0ef41Sopenharmony_ci  mem = &session->mem;
8731cb0ef41Sopenharmony_ci
8741cb0ef41Sopenharmony_ci  if (type <= NGHTTP2_CONTINUATION) {
8751cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_ARGUMENT;
8761cb0ef41Sopenharmony_ci  }
8771cb0ef41Sopenharmony_ci
8781cb0ef41Sopenharmony_ci  if (!session->callbacks.pack_extension_callback) {
8791cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_INVALID_STATE;
8801cb0ef41Sopenharmony_ci  }
8811cb0ef41Sopenharmony_ci
8821cb0ef41Sopenharmony_ci  item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
8831cb0ef41Sopenharmony_ci  if (item == NULL) {
8841cb0ef41Sopenharmony_ci    return NGHTTP2_ERR_NOMEM;
8851cb0ef41Sopenharmony_ci  }
8861cb0ef41Sopenharmony_ci
8871cb0ef41Sopenharmony_ci  nghttp2_outbound_item_init(item);
8881cb0ef41Sopenharmony_ci
8891cb0ef41Sopenharmony_ci  frame = &item->frame;
8901cb0ef41Sopenharmony_ci  nghttp2_frame_extension_init(&frame->ext, type, flags, stream_id, payload);
8911cb0ef41Sopenharmony_ci
8921cb0ef41Sopenharmony_ci  rv = nghttp2_session_add_item(session, item);
8931cb0ef41Sopenharmony_ci  if (rv != 0) {
8941cb0ef41Sopenharmony_ci    nghttp2_frame_extension_free(&frame->ext);
8951cb0ef41Sopenharmony_ci    nghttp2_mem_free(mem, item);
8961cb0ef41Sopenharmony_ci    return rv;
8971cb0ef41Sopenharmony_ci  }
8981cb0ef41Sopenharmony_ci
8991cb0ef41Sopenharmony_ci  return 0;
9001cb0ef41Sopenharmony_ci}
901