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(©_pri_spec); 1581cb0ef41Sopenharmony_ci } else { 1591cb0ef41Sopenharmony_ci nghttp2_priority_spec_default_init(©_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, ©_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(©_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, ©_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