11cb0ef41Sopenharmony_ci/* 21cb0ef41Sopenharmony_ci * nghttp2 - HTTP/2 C Library 31cb0ef41Sopenharmony_ci * 41cb0ef41Sopenharmony_ci * Copyright (c) 2012 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_session.h" 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ci#include <string.h> 281cb0ef41Sopenharmony_ci#include <stddef.h> 291cb0ef41Sopenharmony_ci#include <stdio.h> 301cb0ef41Sopenharmony_ci#include <assert.h> 311cb0ef41Sopenharmony_ci#include <stdarg.h> 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci#include "nghttp2_helper.h" 341cb0ef41Sopenharmony_ci#include "nghttp2_net.h" 351cb0ef41Sopenharmony_ci#include "nghttp2_priority_spec.h" 361cb0ef41Sopenharmony_ci#include "nghttp2_option.h" 371cb0ef41Sopenharmony_ci#include "nghttp2_http.h" 381cb0ef41Sopenharmony_ci#include "nghttp2_pq.h" 391cb0ef41Sopenharmony_ci#include "nghttp2_extpri.h" 401cb0ef41Sopenharmony_ci#include "nghttp2_time.h" 411cb0ef41Sopenharmony_ci#include "nghttp2_debug.h" 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci/* 441cb0ef41Sopenharmony_ci * Returns non-zero if the number of outgoing opened streams is larger 451cb0ef41Sopenharmony_ci * than or equal to 461cb0ef41Sopenharmony_ci * remote_settings.max_concurrent_streams. 471cb0ef41Sopenharmony_ci */ 481cb0ef41Sopenharmony_cistatic int 491cb0ef41Sopenharmony_cisession_is_outgoing_concurrent_streams_max(nghttp2_session *session) { 501cb0ef41Sopenharmony_ci return session->remote_settings.max_concurrent_streams <= 511cb0ef41Sopenharmony_ci session->num_outgoing_streams; 521cb0ef41Sopenharmony_ci} 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci/* 551cb0ef41Sopenharmony_ci * Returns non-zero if the number of incoming opened streams is larger 561cb0ef41Sopenharmony_ci * than or equal to 571cb0ef41Sopenharmony_ci * local_settings.max_concurrent_streams. 581cb0ef41Sopenharmony_ci */ 591cb0ef41Sopenharmony_cistatic int 601cb0ef41Sopenharmony_cisession_is_incoming_concurrent_streams_max(nghttp2_session *session) { 611cb0ef41Sopenharmony_ci return session->local_settings.max_concurrent_streams <= 621cb0ef41Sopenharmony_ci session->num_incoming_streams; 631cb0ef41Sopenharmony_ci} 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ci/* 661cb0ef41Sopenharmony_ci * Returns non-zero if the number of incoming opened streams is larger 671cb0ef41Sopenharmony_ci * than or equal to 681cb0ef41Sopenharmony_ci * session->pending_local_max_concurrent_stream. 691cb0ef41Sopenharmony_ci */ 701cb0ef41Sopenharmony_cistatic int 711cb0ef41Sopenharmony_cisession_is_incoming_concurrent_streams_pending_max(nghttp2_session *session) { 721cb0ef41Sopenharmony_ci return session->pending_local_max_concurrent_stream <= 731cb0ef41Sopenharmony_ci session->num_incoming_streams; 741cb0ef41Sopenharmony_ci} 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci/* 771cb0ef41Sopenharmony_ci * Returns non-zero if |lib_error| is non-fatal error. 781cb0ef41Sopenharmony_ci */ 791cb0ef41Sopenharmony_cistatic int is_non_fatal(int lib_error_code) { 801cb0ef41Sopenharmony_ci return lib_error_code < 0 && lib_error_code > NGHTTP2_ERR_FATAL; 811cb0ef41Sopenharmony_ci} 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ciint nghttp2_is_fatal(int lib_error_code) { 841cb0ef41Sopenharmony_ci return lib_error_code < NGHTTP2_ERR_FATAL; 851cb0ef41Sopenharmony_ci} 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_cistatic int session_enforce_http_messaging(nghttp2_session *session) { 881cb0ef41Sopenharmony_ci return (session->opt_flags & NGHTTP2_OPTMASK_NO_HTTP_MESSAGING) == 0; 891cb0ef41Sopenharmony_ci} 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci/* 921cb0ef41Sopenharmony_ci * Returns nonzero if |frame| is trailer headers. 931cb0ef41Sopenharmony_ci */ 941cb0ef41Sopenharmony_cistatic int session_trailer_headers(nghttp2_session *session, 951cb0ef41Sopenharmony_ci nghttp2_stream *stream, 961cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 971cb0ef41Sopenharmony_ci if (!stream || frame->hd.type != NGHTTP2_HEADERS) { 981cb0ef41Sopenharmony_ci return 0; 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci if (session->server) { 1011cb0ef41Sopenharmony_ci return frame->headers.cat == NGHTTP2_HCAT_HEADERS; 1021cb0ef41Sopenharmony_ci } 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci return frame->headers.cat == NGHTTP2_HCAT_HEADERS && 1051cb0ef41Sopenharmony_ci (stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) == 0; 1061cb0ef41Sopenharmony_ci} 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci/* Returns nonzero if the |stream| is in reserved(remote) state */ 1091cb0ef41Sopenharmony_cistatic int state_reserved_remote(nghttp2_session *session, 1101cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 1111cb0ef41Sopenharmony_ci return stream->state == NGHTTP2_STREAM_RESERVED && 1121cb0ef41Sopenharmony_ci !nghttp2_session_is_my_stream_id(session, stream->stream_id); 1131cb0ef41Sopenharmony_ci} 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci/* Returns nonzero if the |stream| is in reserved(local) state */ 1161cb0ef41Sopenharmony_cistatic int state_reserved_local(nghttp2_session *session, 1171cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 1181cb0ef41Sopenharmony_ci return stream->state == NGHTTP2_STREAM_RESERVED && 1191cb0ef41Sopenharmony_ci nghttp2_session_is_my_stream_id(session, stream->stream_id); 1201cb0ef41Sopenharmony_ci} 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci/* 1231cb0ef41Sopenharmony_ci * Checks whether received stream_id is valid. This function returns 1241cb0ef41Sopenharmony_ci * 1 if it succeeds, or 0. 1251cb0ef41Sopenharmony_ci */ 1261cb0ef41Sopenharmony_cistatic int session_is_new_peer_stream_id(nghttp2_session *session, 1271cb0ef41Sopenharmony_ci int32_t stream_id) { 1281cb0ef41Sopenharmony_ci return stream_id != 0 && 1291cb0ef41Sopenharmony_ci !nghttp2_session_is_my_stream_id(session, stream_id) && 1301cb0ef41Sopenharmony_ci session->last_recv_stream_id < stream_id; 1311cb0ef41Sopenharmony_ci} 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_cistatic int session_detect_idle_stream(nghttp2_session *session, 1341cb0ef41Sopenharmony_ci int32_t stream_id) { 1351cb0ef41Sopenharmony_ci /* Assume that stream object with stream_id does not exist */ 1361cb0ef41Sopenharmony_ci if (nghttp2_session_is_my_stream_id(session, stream_id)) { 1371cb0ef41Sopenharmony_ci if (session->last_sent_stream_id < stream_id) { 1381cb0ef41Sopenharmony_ci return 1; 1391cb0ef41Sopenharmony_ci } 1401cb0ef41Sopenharmony_ci return 0; 1411cb0ef41Sopenharmony_ci } 1421cb0ef41Sopenharmony_ci if (session_is_new_peer_stream_id(session, stream_id)) { 1431cb0ef41Sopenharmony_ci return 1; 1441cb0ef41Sopenharmony_ci } 1451cb0ef41Sopenharmony_ci return 0; 1461cb0ef41Sopenharmony_ci} 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_cistatic int session_no_rfc7540_pri_no_fallback(nghttp2_session *session) { 1491cb0ef41Sopenharmony_ci return session->pending_no_rfc7540_priorities == 1 && 1501cb0ef41Sopenharmony_ci !session->fallback_rfc7540_priorities; 1511cb0ef41Sopenharmony_ci} 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_cistatic int check_ext_type_set(const uint8_t *ext_types, uint8_t type) { 1541cb0ef41Sopenharmony_ci return (ext_types[type / 8] & (1 << (type & 0x7))) > 0; 1551cb0ef41Sopenharmony_ci} 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_cistatic int session_call_error_callback(nghttp2_session *session, 1581cb0ef41Sopenharmony_ci int lib_error_code, const char *fmt, 1591cb0ef41Sopenharmony_ci ...) { 1601cb0ef41Sopenharmony_ci size_t bufsize; 1611cb0ef41Sopenharmony_ci va_list ap; 1621cb0ef41Sopenharmony_ci char *buf; 1631cb0ef41Sopenharmony_ci int rv; 1641cb0ef41Sopenharmony_ci nghttp2_mem *mem; 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci if (!session->callbacks.error_callback && 1671cb0ef41Sopenharmony_ci !session->callbacks.error_callback2) { 1681cb0ef41Sopenharmony_ci return 0; 1691cb0ef41Sopenharmony_ci } 1701cb0ef41Sopenharmony_ci 1711cb0ef41Sopenharmony_ci mem = &session->mem; 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_ci va_start(ap, fmt); 1741cb0ef41Sopenharmony_ci rv = vsnprintf(NULL, 0, fmt, ap); 1751cb0ef41Sopenharmony_ci va_end(ap); 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ci if (rv < 0) { 1781cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 1791cb0ef41Sopenharmony_ci } 1801cb0ef41Sopenharmony_ci 1811cb0ef41Sopenharmony_ci bufsize = (size_t)(rv + 1); 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ci buf = nghttp2_mem_malloc(mem, bufsize); 1841cb0ef41Sopenharmony_ci if (buf == NULL) { 1851cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 1861cb0ef41Sopenharmony_ci } 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci va_start(ap, fmt); 1891cb0ef41Sopenharmony_ci rv = vsnprintf(buf, bufsize, fmt, ap); 1901cb0ef41Sopenharmony_ci va_end(ap); 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci if (rv < 0) { 1931cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, buf); 1941cb0ef41Sopenharmony_ci /* vsnprintf may return error because of various things we can 1951cb0ef41Sopenharmony_ci imagine, but typically we don't want to drop session just for 1961cb0ef41Sopenharmony_ci debug callback. */ 1971cb0ef41Sopenharmony_ci DEBUGF("error_callback: vsnprintf failed. The template was %s\n", fmt); 1981cb0ef41Sopenharmony_ci return 0; 1991cb0ef41Sopenharmony_ci } 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ci if (session->callbacks.error_callback2) { 2021cb0ef41Sopenharmony_ci rv = session->callbacks.error_callback2(session, lib_error_code, buf, 2031cb0ef41Sopenharmony_ci (size_t)rv, session->user_data); 2041cb0ef41Sopenharmony_ci } else { 2051cb0ef41Sopenharmony_ci rv = session->callbacks.error_callback(session, buf, (size_t)rv, 2061cb0ef41Sopenharmony_ci session->user_data); 2071cb0ef41Sopenharmony_ci } 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, buf); 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci if (rv != 0) { 2121cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 2131cb0ef41Sopenharmony_ci } 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci return 0; 2161cb0ef41Sopenharmony_ci} 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_cistatic int session_terminate_session(nghttp2_session *session, 2191cb0ef41Sopenharmony_ci int32_t last_stream_id, 2201cb0ef41Sopenharmony_ci uint32_t error_code, const char *reason) { 2211cb0ef41Sopenharmony_ci int rv; 2221cb0ef41Sopenharmony_ci const uint8_t *debug_data; 2231cb0ef41Sopenharmony_ci size_t debug_datalen; 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) { 2261cb0ef41Sopenharmony_ci return 0; 2271cb0ef41Sopenharmony_ci } 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci /* Ignore all incoming frames because we are going to tear down the 2301cb0ef41Sopenharmony_ci session. */ 2311cb0ef41Sopenharmony_ci session->iframe.state = NGHTTP2_IB_IGN_ALL; 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci if (reason == NULL) { 2341cb0ef41Sopenharmony_ci debug_data = NULL; 2351cb0ef41Sopenharmony_ci debug_datalen = 0; 2361cb0ef41Sopenharmony_ci } else { 2371cb0ef41Sopenharmony_ci debug_data = (const uint8_t *)reason; 2381cb0ef41Sopenharmony_ci debug_datalen = strlen(reason); 2391cb0ef41Sopenharmony_ci } 2401cb0ef41Sopenharmony_ci 2411cb0ef41Sopenharmony_ci rv = nghttp2_session_add_goaway(session, last_stream_id, error_code, 2421cb0ef41Sopenharmony_ci debug_data, debug_datalen, 2431cb0ef41Sopenharmony_ci NGHTTP2_GOAWAY_AUX_TERM_ON_SEND); 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci if (rv != 0) { 2461cb0ef41Sopenharmony_ci return rv; 2471cb0ef41Sopenharmony_ci } 2481cb0ef41Sopenharmony_ci 2491cb0ef41Sopenharmony_ci session->goaway_flags |= NGHTTP2_GOAWAY_TERM_ON_SEND; 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_ci return 0; 2521cb0ef41Sopenharmony_ci} 2531cb0ef41Sopenharmony_ci 2541cb0ef41Sopenharmony_ciint nghttp2_session_terminate_session(nghttp2_session *session, 2551cb0ef41Sopenharmony_ci uint32_t error_code) { 2561cb0ef41Sopenharmony_ci return session_terminate_session(session, session->last_proc_stream_id, 2571cb0ef41Sopenharmony_ci error_code, NULL); 2581cb0ef41Sopenharmony_ci} 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ciint nghttp2_session_terminate_session2(nghttp2_session *session, 2611cb0ef41Sopenharmony_ci int32_t last_stream_id, 2621cb0ef41Sopenharmony_ci uint32_t error_code) { 2631cb0ef41Sopenharmony_ci return session_terminate_session(session, last_stream_id, error_code, NULL); 2641cb0ef41Sopenharmony_ci} 2651cb0ef41Sopenharmony_ci 2661cb0ef41Sopenharmony_ciint nghttp2_session_terminate_session_with_reason(nghttp2_session *session, 2671cb0ef41Sopenharmony_ci uint32_t error_code, 2681cb0ef41Sopenharmony_ci const char *reason) { 2691cb0ef41Sopenharmony_ci return session_terminate_session(session, session->last_proc_stream_id, 2701cb0ef41Sopenharmony_ci error_code, reason); 2711cb0ef41Sopenharmony_ci} 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ciint nghttp2_session_is_my_stream_id(nghttp2_session *session, 2741cb0ef41Sopenharmony_ci int32_t stream_id) { 2751cb0ef41Sopenharmony_ci int rem; 2761cb0ef41Sopenharmony_ci if (stream_id == 0) { 2771cb0ef41Sopenharmony_ci return 0; 2781cb0ef41Sopenharmony_ci } 2791cb0ef41Sopenharmony_ci rem = stream_id & 0x1; 2801cb0ef41Sopenharmony_ci if (session->server) { 2811cb0ef41Sopenharmony_ci return rem == 0; 2821cb0ef41Sopenharmony_ci } 2831cb0ef41Sopenharmony_ci return rem == 1; 2841cb0ef41Sopenharmony_ci} 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_cinghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session, 2871cb0ef41Sopenharmony_ci int32_t stream_id) { 2881cb0ef41Sopenharmony_ci nghttp2_stream *stream; 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci stream = (nghttp2_stream *)nghttp2_map_find(&session->streams, stream_id); 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_ci if (stream == NULL || (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) || 2931cb0ef41Sopenharmony_ci stream->state == NGHTTP2_STREAM_IDLE) { 2941cb0ef41Sopenharmony_ci return NULL; 2951cb0ef41Sopenharmony_ci } 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_ci return stream; 2981cb0ef41Sopenharmony_ci} 2991cb0ef41Sopenharmony_ci 3001cb0ef41Sopenharmony_cinghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session, 3011cb0ef41Sopenharmony_ci int32_t stream_id) { 3021cb0ef41Sopenharmony_ci return (nghttp2_stream *)nghttp2_map_find(&session->streams, stream_id); 3031cb0ef41Sopenharmony_ci} 3041cb0ef41Sopenharmony_ci 3051cb0ef41Sopenharmony_cistatic void session_inbound_frame_reset(nghttp2_session *session) { 3061cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 3071cb0ef41Sopenharmony_ci nghttp2_mem *mem = &session->mem; 3081cb0ef41Sopenharmony_ci /* A bit risky code, since if this function is called from 3091cb0ef41Sopenharmony_ci nghttp2_session_new(), we rely on the fact that 3101cb0ef41Sopenharmony_ci iframe->frame.hd.type is 0, so that no free is performed. */ 3111cb0ef41Sopenharmony_ci switch (iframe->frame.hd.type) { 3121cb0ef41Sopenharmony_ci case NGHTTP2_DATA: 3131cb0ef41Sopenharmony_ci break; 3141cb0ef41Sopenharmony_ci case NGHTTP2_HEADERS: 3151cb0ef41Sopenharmony_ci nghttp2_frame_headers_free(&iframe->frame.headers, mem); 3161cb0ef41Sopenharmony_ci break; 3171cb0ef41Sopenharmony_ci case NGHTTP2_PRIORITY: 3181cb0ef41Sopenharmony_ci nghttp2_frame_priority_free(&iframe->frame.priority); 3191cb0ef41Sopenharmony_ci break; 3201cb0ef41Sopenharmony_ci case NGHTTP2_RST_STREAM: 3211cb0ef41Sopenharmony_ci nghttp2_frame_rst_stream_free(&iframe->frame.rst_stream); 3221cb0ef41Sopenharmony_ci break; 3231cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS: 3241cb0ef41Sopenharmony_ci nghttp2_frame_settings_free(&iframe->frame.settings, mem); 3251cb0ef41Sopenharmony_ci 3261cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, iframe->iv); 3271cb0ef41Sopenharmony_ci 3281cb0ef41Sopenharmony_ci iframe->iv = NULL; 3291cb0ef41Sopenharmony_ci iframe->niv = 0; 3301cb0ef41Sopenharmony_ci iframe->max_niv = 0; 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ci break; 3331cb0ef41Sopenharmony_ci case NGHTTP2_PUSH_PROMISE: 3341cb0ef41Sopenharmony_ci nghttp2_frame_push_promise_free(&iframe->frame.push_promise, mem); 3351cb0ef41Sopenharmony_ci break; 3361cb0ef41Sopenharmony_ci case NGHTTP2_PING: 3371cb0ef41Sopenharmony_ci nghttp2_frame_ping_free(&iframe->frame.ping); 3381cb0ef41Sopenharmony_ci break; 3391cb0ef41Sopenharmony_ci case NGHTTP2_GOAWAY: 3401cb0ef41Sopenharmony_ci nghttp2_frame_goaway_free(&iframe->frame.goaway, mem); 3411cb0ef41Sopenharmony_ci break; 3421cb0ef41Sopenharmony_ci case NGHTTP2_WINDOW_UPDATE: 3431cb0ef41Sopenharmony_ci nghttp2_frame_window_update_free(&iframe->frame.window_update); 3441cb0ef41Sopenharmony_ci break; 3451cb0ef41Sopenharmony_ci default: 3461cb0ef41Sopenharmony_ci /* extension frame */ 3471cb0ef41Sopenharmony_ci if (check_ext_type_set(session->user_recv_ext_types, 3481cb0ef41Sopenharmony_ci iframe->frame.hd.type)) { 3491cb0ef41Sopenharmony_ci nghttp2_frame_extension_free(&iframe->frame.ext); 3501cb0ef41Sopenharmony_ci } else { 3511cb0ef41Sopenharmony_ci switch (iframe->frame.hd.type) { 3521cb0ef41Sopenharmony_ci case NGHTTP2_ALTSVC: 3531cb0ef41Sopenharmony_ci if ((session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ALTSVC) == 0) { 3541cb0ef41Sopenharmony_ci break; 3551cb0ef41Sopenharmony_ci } 3561cb0ef41Sopenharmony_ci nghttp2_frame_altsvc_free(&iframe->frame.ext, mem); 3571cb0ef41Sopenharmony_ci break; 3581cb0ef41Sopenharmony_ci case NGHTTP2_ORIGIN: 3591cb0ef41Sopenharmony_ci if ((session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ORIGIN) == 0) { 3601cb0ef41Sopenharmony_ci break; 3611cb0ef41Sopenharmony_ci } 3621cb0ef41Sopenharmony_ci nghttp2_frame_origin_free(&iframe->frame.ext, mem); 3631cb0ef41Sopenharmony_ci break; 3641cb0ef41Sopenharmony_ci case NGHTTP2_PRIORITY_UPDATE: 3651cb0ef41Sopenharmony_ci if ((session->builtin_recv_ext_types & 3661cb0ef41Sopenharmony_ci NGHTTP2_TYPEMASK_PRIORITY_UPDATE) == 0) { 3671cb0ef41Sopenharmony_ci break; 3681cb0ef41Sopenharmony_ci } 3691cb0ef41Sopenharmony_ci /* Do not call nghttp2_frame_priority_update_free, because all 3701cb0ef41Sopenharmony_ci fields point to sbuf. */ 3711cb0ef41Sopenharmony_ci break; 3721cb0ef41Sopenharmony_ci } 3731cb0ef41Sopenharmony_ci } 3741cb0ef41Sopenharmony_ci 3751cb0ef41Sopenharmony_ci break; 3761cb0ef41Sopenharmony_ci } 3771cb0ef41Sopenharmony_ci 3781cb0ef41Sopenharmony_ci memset(&iframe->frame, 0, sizeof(nghttp2_frame)); 3791cb0ef41Sopenharmony_ci memset(&iframe->ext_frame_payload, 0, sizeof(nghttp2_ext_frame_payload)); 3801cb0ef41Sopenharmony_ci 3811cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_HEAD; 3821cb0ef41Sopenharmony_ci 3831cb0ef41Sopenharmony_ci nghttp2_buf_wrap_init(&iframe->sbuf, iframe->raw_sbuf, 3841cb0ef41Sopenharmony_ci sizeof(iframe->raw_sbuf)); 3851cb0ef41Sopenharmony_ci iframe->sbuf.mark += NGHTTP2_FRAME_HDLEN; 3861cb0ef41Sopenharmony_ci 3871cb0ef41Sopenharmony_ci nghttp2_buf_free(&iframe->lbuf, mem); 3881cb0ef41Sopenharmony_ci nghttp2_buf_wrap_init(&iframe->lbuf, NULL, 0); 3891cb0ef41Sopenharmony_ci 3901cb0ef41Sopenharmony_ci iframe->raw_lbuf = NULL; 3911cb0ef41Sopenharmony_ci 3921cb0ef41Sopenharmony_ci iframe->payloadleft = 0; 3931cb0ef41Sopenharmony_ci iframe->padlen = 0; 3941cb0ef41Sopenharmony_ci} 3951cb0ef41Sopenharmony_ci 3961cb0ef41Sopenharmony_cistatic void init_settings(nghttp2_settings_storage *settings) { 3971cb0ef41Sopenharmony_ci settings->header_table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; 3981cb0ef41Sopenharmony_ci settings->enable_push = 1; 3991cb0ef41Sopenharmony_ci settings->max_concurrent_streams = NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS; 4001cb0ef41Sopenharmony_ci settings->initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE; 4011cb0ef41Sopenharmony_ci settings->max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MIN; 4021cb0ef41Sopenharmony_ci settings->max_header_list_size = UINT32_MAX; 4031cb0ef41Sopenharmony_ci settings->no_rfc7540_priorities = UINT32_MAX; 4041cb0ef41Sopenharmony_ci} 4051cb0ef41Sopenharmony_ci 4061cb0ef41Sopenharmony_cistatic void active_outbound_item_reset(nghttp2_active_outbound_item *aob, 4071cb0ef41Sopenharmony_ci nghttp2_mem *mem) { 4081cb0ef41Sopenharmony_ci DEBUGF("send: reset nghttp2_active_outbound_item\n"); 4091cb0ef41Sopenharmony_ci DEBUGF("send: aob->item = %p\n", aob->item); 4101cb0ef41Sopenharmony_ci nghttp2_outbound_item_free(aob->item, mem); 4111cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, aob->item); 4121cb0ef41Sopenharmony_ci aob->item = NULL; 4131cb0ef41Sopenharmony_ci nghttp2_bufs_reset(&aob->framebufs); 4141cb0ef41Sopenharmony_ci aob->state = NGHTTP2_OB_POP_ITEM; 4151cb0ef41Sopenharmony_ci} 4161cb0ef41Sopenharmony_ci 4171cb0ef41Sopenharmony_ci#define NGHTTP2_STREAM_MAX_CYCLE_GAP ((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX) 4181cb0ef41Sopenharmony_ci 4191cb0ef41Sopenharmony_cistatic int stream_less(const void *lhsx, const void *rhsx) { 4201cb0ef41Sopenharmony_ci const nghttp2_stream *lhs, *rhs; 4211cb0ef41Sopenharmony_ci 4221cb0ef41Sopenharmony_ci lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry); 4231cb0ef41Sopenharmony_ci rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry); 4241cb0ef41Sopenharmony_ci 4251cb0ef41Sopenharmony_ci if (lhs->cycle == rhs->cycle) { 4261cb0ef41Sopenharmony_ci return lhs->seq < rhs->seq; 4271cb0ef41Sopenharmony_ci } 4281cb0ef41Sopenharmony_ci 4291cb0ef41Sopenharmony_ci return rhs->cycle - lhs->cycle <= NGHTTP2_STREAM_MAX_CYCLE_GAP; 4301cb0ef41Sopenharmony_ci} 4311cb0ef41Sopenharmony_ci 4321cb0ef41Sopenharmony_ciint nghttp2_enable_strict_preface = 1; 4331cb0ef41Sopenharmony_ci 4341cb0ef41Sopenharmony_cistatic int session_new(nghttp2_session **session_ptr, 4351cb0ef41Sopenharmony_ci const nghttp2_session_callbacks *callbacks, 4361cb0ef41Sopenharmony_ci void *user_data, int server, 4371cb0ef41Sopenharmony_ci const nghttp2_option *option, nghttp2_mem *mem) { 4381cb0ef41Sopenharmony_ci int rv; 4391cb0ef41Sopenharmony_ci size_t nbuffer; 4401cb0ef41Sopenharmony_ci size_t max_deflate_dynamic_table_size = 4411cb0ef41Sopenharmony_ci NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE; 4421cb0ef41Sopenharmony_ci size_t i; 4431cb0ef41Sopenharmony_ci 4441cb0ef41Sopenharmony_ci if (mem == NULL) { 4451cb0ef41Sopenharmony_ci mem = nghttp2_mem_default(); 4461cb0ef41Sopenharmony_ci } 4471cb0ef41Sopenharmony_ci 4481cb0ef41Sopenharmony_ci *session_ptr = nghttp2_mem_calloc(mem, 1, sizeof(nghttp2_session)); 4491cb0ef41Sopenharmony_ci if (*session_ptr == NULL) { 4501cb0ef41Sopenharmony_ci rv = NGHTTP2_ERR_NOMEM; 4511cb0ef41Sopenharmony_ci goto fail_session; 4521cb0ef41Sopenharmony_ci } 4531cb0ef41Sopenharmony_ci 4541cb0ef41Sopenharmony_ci (*session_ptr)->mem = *mem; 4551cb0ef41Sopenharmony_ci mem = &(*session_ptr)->mem; 4561cb0ef41Sopenharmony_ci 4571cb0ef41Sopenharmony_ci /* next_stream_id is initialized in either 4581cb0ef41Sopenharmony_ci nghttp2_session_client_new2 or nghttp2_session_server_new2 */ 4591cb0ef41Sopenharmony_ci 4601cb0ef41Sopenharmony_ci nghttp2_stream_init(&(*session_ptr)->root, 0, NGHTTP2_STREAM_FLAG_NONE, 4611cb0ef41Sopenharmony_ci NGHTTP2_STREAM_IDLE, NGHTTP2_DEFAULT_WEIGHT, 0, 0, NULL, 4621cb0ef41Sopenharmony_ci mem); 4631cb0ef41Sopenharmony_ci 4641cb0ef41Sopenharmony_ci (*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; 4651cb0ef41Sopenharmony_ci (*session_ptr)->recv_window_size = 0; 4661cb0ef41Sopenharmony_ci (*session_ptr)->consumed_size = 0; 4671cb0ef41Sopenharmony_ci (*session_ptr)->recv_reduction = 0; 4681cb0ef41Sopenharmony_ci (*session_ptr)->local_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; 4691cb0ef41Sopenharmony_ci 4701cb0ef41Sopenharmony_ci (*session_ptr)->goaway_flags = NGHTTP2_GOAWAY_NONE; 4711cb0ef41Sopenharmony_ci (*session_ptr)->local_last_stream_id = (1u << 31) - 1; 4721cb0ef41Sopenharmony_ci (*session_ptr)->remote_last_stream_id = (1u << 31) - 1; 4731cb0ef41Sopenharmony_ci 4741cb0ef41Sopenharmony_ci (*session_ptr)->pending_local_max_concurrent_stream = 4751cb0ef41Sopenharmony_ci NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS; 4761cb0ef41Sopenharmony_ci (*session_ptr)->pending_enable_push = 1; 4771cb0ef41Sopenharmony_ci (*session_ptr)->pending_no_rfc7540_priorities = UINT8_MAX; 4781cb0ef41Sopenharmony_ci 4791cb0ef41Sopenharmony_ci nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim, 4801cb0ef41Sopenharmony_ci NGHTTP2_DEFAULT_STREAM_RESET_BURST, 4811cb0ef41Sopenharmony_ci NGHTTP2_DEFAULT_STREAM_RESET_RATE); 4821cb0ef41Sopenharmony_ci 4831cb0ef41Sopenharmony_ci if (server) { 4841cb0ef41Sopenharmony_ci (*session_ptr)->server = 1; 4851cb0ef41Sopenharmony_ci } 4861cb0ef41Sopenharmony_ci 4871cb0ef41Sopenharmony_ci init_settings(&(*session_ptr)->remote_settings); 4881cb0ef41Sopenharmony_ci init_settings(&(*session_ptr)->local_settings); 4891cb0ef41Sopenharmony_ci 4901cb0ef41Sopenharmony_ci (*session_ptr)->max_incoming_reserved_streams = 4911cb0ef41Sopenharmony_ci NGHTTP2_MAX_INCOMING_RESERVED_STREAMS; 4921cb0ef41Sopenharmony_ci 4931cb0ef41Sopenharmony_ci /* Limit max outgoing concurrent streams to sensible value */ 4941cb0ef41Sopenharmony_ci (*session_ptr)->remote_settings.max_concurrent_streams = 100; 4951cb0ef41Sopenharmony_ci 4961cb0ef41Sopenharmony_ci (*session_ptr)->max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN; 4971cb0ef41Sopenharmony_ci (*session_ptr)->max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM; 4981cb0ef41Sopenharmony_ci (*session_ptr)->max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS; 4991cb0ef41Sopenharmony_ci 5001cb0ef41Sopenharmony_ci if (option) { 5011cb0ef41Sopenharmony_ci if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) && 5021cb0ef41Sopenharmony_ci option->no_auto_window_update) { 5031cb0ef41Sopenharmony_ci 5041cb0ef41Sopenharmony_ci (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE; 5051cb0ef41Sopenharmony_ci } 5061cb0ef41Sopenharmony_ci 5071cb0ef41Sopenharmony_ci if (option->opt_set_mask & NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS) { 5081cb0ef41Sopenharmony_ci 5091cb0ef41Sopenharmony_ci (*session_ptr)->remote_settings.max_concurrent_streams = 5101cb0ef41Sopenharmony_ci option->peer_max_concurrent_streams; 5111cb0ef41Sopenharmony_ci } 5121cb0ef41Sopenharmony_ci 5131cb0ef41Sopenharmony_ci if (option->opt_set_mask & NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS) { 5141cb0ef41Sopenharmony_ci 5151cb0ef41Sopenharmony_ci (*session_ptr)->max_incoming_reserved_streams = 5161cb0ef41Sopenharmony_ci option->max_reserved_remote_streams; 5171cb0ef41Sopenharmony_ci } 5181cb0ef41Sopenharmony_ci 5191cb0ef41Sopenharmony_ci if ((option->opt_set_mask & NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC) && 5201cb0ef41Sopenharmony_ci option->no_recv_client_magic) { 5211cb0ef41Sopenharmony_ci 5221cb0ef41Sopenharmony_ci (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC; 5231cb0ef41Sopenharmony_ci } 5241cb0ef41Sopenharmony_ci 5251cb0ef41Sopenharmony_ci if ((option->opt_set_mask & NGHTTP2_OPT_NO_HTTP_MESSAGING) && 5261cb0ef41Sopenharmony_ci option->no_http_messaging) { 5271cb0ef41Sopenharmony_ci 5281cb0ef41Sopenharmony_ci (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_HTTP_MESSAGING; 5291cb0ef41Sopenharmony_ci } 5301cb0ef41Sopenharmony_ci 5311cb0ef41Sopenharmony_ci if (option->opt_set_mask & NGHTTP2_OPT_USER_RECV_EXT_TYPES) { 5321cb0ef41Sopenharmony_ci memcpy((*session_ptr)->user_recv_ext_types, option->user_recv_ext_types, 5331cb0ef41Sopenharmony_ci sizeof((*session_ptr)->user_recv_ext_types)); 5341cb0ef41Sopenharmony_ci } 5351cb0ef41Sopenharmony_ci 5361cb0ef41Sopenharmony_ci if (option->opt_set_mask & NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES) { 5371cb0ef41Sopenharmony_ci (*session_ptr)->builtin_recv_ext_types = option->builtin_recv_ext_types; 5381cb0ef41Sopenharmony_ci } 5391cb0ef41Sopenharmony_ci 5401cb0ef41Sopenharmony_ci if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_PING_ACK) && 5411cb0ef41Sopenharmony_ci option->no_auto_ping_ack) { 5421cb0ef41Sopenharmony_ci (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_PING_ACK; 5431cb0ef41Sopenharmony_ci } 5441cb0ef41Sopenharmony_ci 5451cb0ef41Sopenharmony_ci if (option->opt_set_mask & NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH) { 5461cb0ef41Sopenharmony_ci (*session_ptr)->max_send_header_block_length = 5471cb0ef41Sopenharmony_ci option->max_send_header_block_length; 5481cb0ef41Sopenharmony_ci } 5491cb0ef41Sopenharmony_ci 5501cb0ef41Sopenharmony_ci if (option->opt_set_mask & NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE) { 5511cb0ef41Sopenharmony_ci max_deflate_dynamic_table_size = option->max_deflate_dynamic_table_size; 5521cb0ef41Sopenharmony_ci } 5531cb0ef41Sopenharmony_ci 5541cb0ef41Sopenharmony_ci if ((option->opt_set_mask & NGHTTP2_OPT_NO_CLOSED_STREAMS) && 5551cb0ef41Sopenharmony_ci option->no_closed_streams) { 5561cb0ef41Sopenharmony_ci (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_CLOSED_STREAMS; 5571cb0ef41Sopenharmony_ci } 5581cb0ef41Sopenharmony_ci 5591cb0ef41Sopenharmony_ci if (option->opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_ACK) { 5601cb0ef41Sopenharmony_ci (*session_ptr)->max_outbound_ack = option->max_outbound_ack; 5611cb0ef41Sopenharmony_ci } 5621cb0ef41Sopenharmony_ci 5631cb0ef41Sopenharmony_ci if ((option->opt_set_mask & NGHTTP2_OPT_MAX_SETTINGS) && 5641cb0ef41Sopenharmony_ci option->max_settings) { 5651cb0ef41Sopenharmony_ci (*session_ptr)->max_settings = option->max_settings; 5661cb0ef41Sopenharmony_ci } 5671cb0ef41Sopenharmony_ci 5681cb0ef41Sopenharmony_ci if ((option->opt_set_mask & 5691cb0ef41Sopenharmony_ci NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES) && 5701cb0ef41Sopenharmony_ci option->server_fallback_rfc7540_priorities) { 5711cb0ef41Sopenharmony_ci (*session_ptr)->opt_flags |= 5721cb0ef41Sopenharmony_ci NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES; 5731cb0ef41Sopenharmony_ci } 5741cb0ef41Sopenharmony_ci 5751cb0ef41Sopenharmony_ci if ((option->opt_set_mask & 5761cb0ef41Sopenharmony_ci NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) && 5771cb0ef41Sopenharmony_ci option->no_rfc9113_leading_and_trailing_ws_validation) { 5781cb0ef41Sopenharmony_ci (*session_ptr)->opt_flags |= 5791cb0ef41Sopenharmony_ci NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION; 5801cb0ef41Sopenharmony_ci } 5811cb0ef41Sopenharmony_ci 5821cb0ef41Sopenharmony_ci if (option->opt_set_mask & NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT) { 5831cb0ef41Sopenharmony_ci nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim, 5841cb0ef41Sopenharmony_ci option->stream_reset_burst, 5851cb0ef41Sopenharmony_ci option->stream_reset_rate); 5861cb0ef41Sopenharmony_ci } 5871cb0ef41Sopenharmony_ci } 5881cb0ef41Sopenharmony_ci 5891cb0ef41Sopenharmony_ci rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater, 5901cb0ef41Sopenharmony_ci max_deflate_dynamic_table_size, mem); 5911cb0ef41Sopenharmony_ci if (rv != 0) { 5921cb0ef41Sopenharmony_ci goto fail_hd_deflater; 5931cb0ef41Sopenharmony_ci } 5941cb0ef41Sopenharmony_ci rv = nghttp2_hd_inflate_init(&(*session_ptr)->hd_inflater, mem); 5951cb0ef41Sopenharmony_ci if (rv != 0) { 5961cb0ef41Sopenharmony_ci goto fail_hd_inflater; 5971cb0ef41Sopenharmony_ci } 5981cb0ef41Sopenharmony_ci 5991cb0ef41Sopenharmony_ci nbuffer = ((*session_ptr)->max_send_header_block_length + 6001cb0ef41Sopenharmony_ci NGHTTP2_FRAMEBUF_CHUNKLEN - 1) / 6011cb0ef41Sopenharmony_ci NGHTTP2_FRAMEBUF_CHUNKLEN; 6021cb0ef41Sopenharmony_ci 6031cb0ef41Sopenharmony_ci if (nbuffer == 0) { 6041cb0ef41Sopenharmony_ci nbuffer = 1; 6051cb0ef41Sopenharmony_ci } 6061cb0ef41Sopenharmony_ci 6071cb0ef41Sopenharmony_ci /* 1 for Pad Field. */ 6081cb0ef41Sopenharmony_ci rv = nghttp2_bufs_init3(&(*session_ptr)->aob.framebufs, 6091cb0ef41Sopenharmony_ci NGHTTP2_FRAMEBUF_CHUNKLEN, nbuffer, 1, 6101cb0ef41Sopenharmony_ci NGHTTP2_FRAME_HDLEN + 1, mem); 6111cb0ef41Sopenharmony_ci if (rv != 0) { 6121cb0ef41Sopenharmony_ci goto fail_aob_framebuf; 6131cb0ef41Sopenharmony_ci } 6141cb0ef41Sopenharmony_ci 6151cb0ef41Sopenharmony_ci nghttp2_map_init(&(*session_ptr)->streams, mem); 6161cb0ef41Sopenharmony_ci 6171cb0ef41Sopenharmony_ci active_outbound_item_reset(&(*session_ptr)->aob, mem); 6181cb0ef41Sopenharmony_ci 6191cb0ef41Sopenharmony_ci (*session_ptr)->callbacks = *callbacks; 6201cb0ef41Sopenharmony_ci (*session_ptr)->user_data = user_data; 6211cb0ef41Sopenharmony_ci 6221cb0ef41Sopenharmony_ci session_inbound_frame_reset(*session_ptr); 6231cb0ef41Sopenharmony_ci 6241cb0ef41Sopenharmony_ci if (nghttp2_enable_strict_preface) { 6251cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &(*session_ptr)->iframe; 6261cb0ef41Sopenharmony_ci 6271cb0ef41Sopenharmony_ci if (server && ((*session_ptr)->opt_flags & 6281cb0ef41Sopenharmony_ci NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC) == 0) { 6291cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_CLIENT_MAGIC; 6301cb0ef41Sopenharmony_ci iframe->payloadleft = NGHTTP2_CLIENT_MAGIC_LEN; 6311cb0ef41Sopenharmony_ci } else { 6321cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_FIRST_SETTINGS; 6331cb0ef41Sopenharmony_ci } 6341cb0ef41Sopenharmony_ci 6351cb0ef41Sopenharmony_ci if (!server) { 6361cb0ef41Sopenharmony_ci (*session_ptr)->aob.state = NGHTTP2_OB_SEND_CLIENT_MAGIC; 6371cb0ef41Sopenharmony_ci nghttp2_bufs_add(&(*session_ptr)->aob.framebufs, NGHTTP2_CLIENT_MAGIC, 6381cb0ef41Sopenharmony_ci NGHTTP2_CLIENT_MAGIC_LEN); 6391cb0ef41Sopenharmony_ci } 6401cb0ef41Sopenharmony_ci } 6411cb0ef41Sopenharmony_ci 6421cb0ef41Sopenharmony_ci for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) { 6431cb0ef41Sopenharmony_ci nghttp2_pq_init(&(*session_ptr)->sched[i].ob_data, stream_less, mem); 6441cb0ef41Sopenharmony_ci } 6451cb0ef41Sopenharmony_ci 6461cb0ef41Sopenharmony_ci return 0; 6471cb0ef41Sopenharmony_ci 6481cb0ef41Sopenharmony_cifail_aob_framebuf: 6491cb0ef41Sopenharmony_ci nghttp2_hd_inflate_free(&(*session_ptr)->hd_inflater); 6501cb0ef41Sopenharmony_cifail_hd_inflater: 6511cb0ef41Sopenharmony_ci nghttp2_hd_deflate_free(&(*session_ptr)->hd_deflater); 6521cb0ef41Sopenharmony_cifail_hd_deflater: 6531cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, *session_ptr); 6541cb0ef41Sopenharmony_cifail_session: 6551cb0ef41Sopenharmony_ci return rv; 6561cb0ef41Sopenharmony_ci} 6571cb0ef41Sopenharmony_ci 6581cb0ef41Sopenharmony_ciint nghttp2_session_client_new(nghttp2_session **session_ptr, 6591cb0ef41Sopenharmony_ci const nghttp2_session_callbacks *callbacks, 6601cb0ef41Sopenharmony_ci void *user_data) { 6611cb0ef41Sopenharmony_ci return nghttp2_session_client_new3(session_ptr, callbacks, user_data, NULL, 6621cb0ef41Sopenharmony_ci NULL); 6631cb0ef41Sopenharmony_ci} 6641cb0ef41Sopenharmony_ci 6651cb0ef41Sopenharmony_ciint nghttp2_session_client_new2(nghttp2_session **session_ptr, 6661cb0ef41Sopenharmony_ci const nghttp2_session_callbacks *callbacks, 6671cb0ef41Sopenharmony_ci void *user_data, const nghttp2_option *option) { 6681cb0ef41Sopenharmony_ci return nghttp2_session_client_new3(session_ptr, callbacks, user_data, option, 6691cb0ef41Sopenharmony_ci NULL); 6701cb0ef41Sopenharmony_ci} 6711cb0ef41Sopenharmony_ci 6721cb0ef41Sopenharmony_ciint nghttp2_session_client_new3(nghttp2_session **session_ptr, 6731cb0ef41Sopenharmony_ci const nghttp2_session_callbacks *callbacks, 6741cb0ef41Sopenharmony_ci void *user_data, const nghttp2_option *option, 6751cb0ef41Sopenharmony_ci nghttp2_mem *mem) { 6761cb0ef41Sopenharmony_ci int rv; 6771cb0ef41Sopenharmony_ci nghttp2_session *session; 6781cb0ef41Sopenharmony_ci 6791cb0ef41Sopenharmony_ci rv = session_new(&session, callbacks, user_data, 0, option, mem); 6801cb0ef41Sopenharmony_ci 6811cb0ef41Sopenharmony_ci if (rv != 0) { 6821cb0ef41Sopenharmony_ci return rv; 6831cb0ef41Sopenharmony_ci } 6841cb0ef41Sopenharmony_ci /* IDs for use in client */ 6851cb0ef41Sopenharmony_ci session->next_stream_id = 1; 6861cb0ef41Sopenharmony_ci 6871cb0ef41Sopenharmony_ci *session_ptr = session; 6881cb0ef41Sopenharmony_ci 6891cb0ef41Sopenharmony_ci return 0; 6901cb0ef41Sopenharmony_ci} 6911cb0ef41Sopenharmony_ci 6921cb0ef41Sopenharmony_ciint nghttp2_session_server_new(nghttp2_session **session_ptr, 6931cb0ef41Sopenharmony_ci const nghttp2_session_callbacks *callbacks, 6941cb0ef41Sopenharmony_ci void *user_data) { 6951cb0ef41Sopenharmony_ci return nghttp2_session_server_new3(session_ptr, callbacks, user_data, NULL, 6961cb0ef41Sopenharmony_ci NULL); 6971cb0ef41Sopenharmony_ci} 6981cb0ef41Sopenharmony_ci 6991cb0ef41Sopenharmony_ciint nghttp2_session_server_new2(nghttp2_session **session_ptr, 7001cb0ef41Sopenharmony_ci const nghttp2_session_callbacks *callbacks, 7011cb0ef41Sopenharmony_ci void *user_data, const nghttp2_option *option) { 7021cb0ef41Sopenharmony_ci return nghttp2_session_server_new3(session_ptr, callbacks, user_data, option, 7031cb0ef41Sopenharmony_ci NULL); 7041cb0ef41Sopenharmony_ci} 7051cb0ef41Sopenharmony_ci 7061cb0ef41Sopenharmony_ciint nghttp2_session_server_new3(nghttp2_session **session_ptr, 7071cb0ef41Sopenharmony_ci const nghttp2_session_callbacks *callbacks, 7081cb0ef41Sopenharmony_ci void *user_data, const nghttp2_option *option, 7091cb0ef41Sopenharmony_ci nghttp2_mem *mem) { 7101cb0ef41Sopenharmony_ci int rv; 7111cb0ef41Sopenharmony_ci nghttp2_session *session; 7121cb0ef41Sopenharmony_ci 7131cb0ef41Sopenharmony_ci rv = session_new(&session, callbacks, user_data, 1, option, mem); 7141cb0ef41Sopenharmony_ci 7151cb0ef41Sopenharmony_ci if (rv != 0) { 7161cb0ef41Sopenharmony_ci return rv; 7171cb0ef41Sopenharmony_ci } 7181cb0ef41Sopenharmony_ci /* IDs for use in client */ 7191cb0ef41Sopenharmony_ci session->next_stream_id = 2; 7201cb0ef41Sopenharmony_ci 7211cb0ef41Sopenharmony_ci *session_ptr = session; 7221cb0ef41Sopenharmony_ci 7231cb0ef41Sopenharmony_ci return 0; 7241cb0ef41Sopenharmony_ci} 7251cb0ef41Sopenharmony_ci 7261cb0ef41Sopenharmony_cistatic int free_streams(void *entry, void *ptr) { 7271cb0ef41Sopenharmony_ci nghttp2_session *session; 7281cb0ef41Sopenharmony_ci nghttp2_stream *stream; 7291cb0ef41Sopenharmony_ci nghttp2_outbound_item *item; 7301cb0ef41Sopenharmony_ci nghttp2_mem *mem; 7311cb0ef41Sopenharmony_ci 7321cb0ef41Sopenharmony_ci session = (nghttp2_session *)ptr; 7331cb0ef41Sopenharmony_ci mem = &session->mem; 7341cb0ef41Sopenharmony_ci stream = (nghttp2_stream *)entry; 7351cb0ef41Sopenharmony_ci item = stream->item; 7361cb0ef41Sopenharmony_ci 7371cb0ef41Sopenharmony_ci if (item && !item->queued && item != session->aob.item) { 7381cb0ef41Sopenharmony_ci nghttp2_outbound_item_free(item, mem); 7391cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, item); 7401cb0ef41Sopenharmony_ci } 7411cb0ef41Sopenharmony_ci 7421cb0ef41Sopenharmony_ci nghttp2_stream_free(stream); 7431cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, stream); 7441cb0ef41Sopenharmony_ci 7451cb0ef41Sopenharmony_ci return 0; 7461cb0ef41Sopenharmony_ci} 7471cb0ef41Sopenharmony_ci 7481cb0ef41Sopenharmony_cistatic void ob_q_free(nghttp2_outbound_queue *q, nghttp2_mem *mem) { 7491cb0ef41Sopenharmony_ci nghttp2_outbound_item *item, *next; 7501cb0ef41Sopenharmony_ci for (item = q->head; item;) { 7511cb0ef41Sopenharmony_ci next = item->qnext; 7521cb0ef41Sopenharmony_ci nghttp2_outbound_item_free(item, mem); 7531cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, item); 7541cb0ef41Sopenharmony_ci item = next; 7551cb0ef41Sopenharmony_ci } 7561cb0ef41Sopenharmony_ci} 7571cb0ef41Sopenharmony_ci 7581cb0ef41Sopenharmony_cistatic int inflight_settings_new(nghttp2_inflight_settings **settings_ptr, 7591cb0ef41Sopenharmony_ci const nghttp2_settings_entry *iv, size_t niv, 7601cb0ef41Sopenharmony_ci nghttp2_mem *mem) { 7611cb0ef41Sopenharmony_ci *settings_ptr = nghttp2_mem_malloc(mem, sizeof(nghttp2_inflight_settings)); 7621cb0ef41Sopenharmony_ci if (!*settings_ptr) { 7631cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 7641cb0ef41Sopenharmony_ci } 7651cb0ef41Sopenharmony_ci 7661cb0ef41Sopenharmony_ci if (niv > 0) { 7671cb0ef41Sopenharmony_ci (*settings_ptr)->iv = nghttp2_frame_iv_copy(iv, niv, mem); 7681cb0ef41Sopenharmony_ci if (!(*settings_ptr)->iv) { 7691cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, *settings_ptr); 7701cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 7711cb0ef41Sopenharmony_ci } 7721cb0ef41Sopenharmony_ci } else { 7731cb0ef41Sopenharmony_ci (*settings_ptr)->iv = NULL; 7741cb0ef41Sopenharmony_ci } 7751cb0ef41Sopenharmony_ci 7761cb0ef41Sopenharmony_ci (*settings_ptr)->niv = niv; 7771cb0ef41Sopenharmony_ci (*settings_ptr)->next = NULL; 7781cb0ef41Sopenharmony_ci 7791cb0ef41Sopenharmony_ci return 0; 7801cb0ef41Sopenharmony_ci} 7811cb0ef41Sopenharmony_ci 7821cb0ef41Sopenharmony_cistatic void inflight_settings_del(nghttp2_inflight_settings *settings, 7831cb0ef41Sopenharmony_ci nghttp2_mem *mem) { 7841cb0ef41Sopenharmony_ci if (!settings) { 7851cb0ef41Sopenharmony_ci return; 7861cb0ef41Sopenharmony_ci } 7871cb0ef41Sopenharmony_ci 7881cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, settings->iv); 7891cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, settings); 7901cb0ef41Sopenharmony_ci} 7911cb0ef41Sopenharmony_ci 7921cb0ef41Sopenharmony_civoid nghttp2_session_del(nghttp2_session *session) { 7931cb0ef41Sopenharmony_ci nghttp2_mem *mem; 7941cb0ef41Sopenharmony_ci nghttp2_inflight_settings *settings; 7951cb0ef41Sopenharmony_ci size_t i; 7961cb0ef41Sopenharmony_ci 7971cb0ef41Sopenharmony_ci if (session == NULL) { 7981cb0ef41Sopenharmony_ci return; 7991cb0ef41Sopenharmony_ci } 8001cb0ef41Sopenharmony_ci 8011cb0ef41Sopenharmony_ci mem = &session->mem; 8021cb0ef41Sopenharmony_ci 8031cb0ef41Sopenharmony_ci for (settings = session->inflight_settings_head; settings;) { 8041cb0ef41Sopenharmony_ci nghttp2_inflight_settings *next = settings->next; 8051cb0ef41Sopenharmony_ci inflight_settings_del(settings, mem); 8061cb0ef41Sopenharmony_ci settings = next; 8071cb0ef41Sopenharmony_ci } 8081cb0ef41Sopenharmony_ci 8091cb0ef41Sopenharmony_ci for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) { 8101cb0ef41Sopenharmony_ci nghttp2_pq_free(&session->sched[i].ob_data); 8111cb0ef41Sopenharmony_ci } 8121cb0ef41Sopenharmony_ci nghttp2_stream_free(&session->root); 8131cb0ef41Sopenharmony_ci 8141cb0ef41Sopenharmony_ci /* Have to free streams first, so that we can check 8151cb0ef41Sopenharmony_ci stream->item->queued */ 8161cb0ef41Sopenharmony_ci nghttp2_map_each_free(&session->streams, free_streams, session); 8171cb0ef41Sopenharmony_ci nghttp2_map_free(&session->streams); 8181cb0ef41Sopenharmony_ci 8191cb0ef41Sopenharmony_ci ob_q_free(&session->ob_urgent, mem); 8201cb0ef41Sopenharmony_ci ob_q_free(&session->ob_reg, mem); 8211cb0ef41Sopenharmony_ci ob_q_free(&session->ob_syn, mem); 8221cb0ef41Sopenharmony_ci 8231cb0ef41Sopenharmony_ci active_outbound_item_reset(&session->aob, mem); 8241cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 8251cb0ef41Sopenharmony_ci nghttp2_hd_deflate_free(&session->hd_deflater); 8261cb0ef41Sopenharmony_ci nghttp2_hd_inflate_free(&session->hd_inflater); 8271cb0ef41Sopenharmony_ci nghttp2_bufs_free(&session->aob.framebufs); 8281cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, session); 8291cb0ef41Sopenharmony_ci} 8301cb0ef41Sopenharmony_ci 8311cb0ef41Sopenharmony_ciint nghttp2_session_reprioritize_stream( 8321cb0ef41Sopenharmony_ci nghttp2_session *session, nghttp2_stream *stream, 8331cb0ef41Sopenharmony_ci const nghttp2_priority_spec *pri_spec_in) { 8341cb0ef41Sopenharmony_ci int rv; 8351cb0ef41Sopenharmony_ci nghttp2_stream *dep_stream = NULL; 8361cb0ef41Sopenharmony_ci nghttp2_priority_spec pri_spec_default; 8371cb0ef41Sopenharmony_ci const nghttp2_priority_spec *pri_spec = pri_spec_in; 8381cb0ef41Sopenharmony_ci 8391cb0ef41Sopenharmony_ci assert((!session->server && session->pending_no_rfc7540_priorities != 1) || 8401cb0ef41Sopenharmony_ci (session->server && !session_no_rfc7540_pri_no_fallback(session))); 8411cb0ef41Sopenharmony_ci assert(pri_spec->stream_id != stream->stream_id); 8421cb0ef41Sopenharmony_ci 8431cb0ef41Sopenharmony_ci if (!nghttp2_stream_in_dep_tree(stream)) { 8441cb0ef41Sopenharmony_ci return 0; 8451cb0ef41Sopenharmony_ci } 8461cb0ef41Sopenharmony_ci 8471cb0ef41Sopenharmony_ci if (pri_spec->stream_id != 0) { 8481cb0ef41Sopenharmony_ci dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); 8491cb0ef41Sopenharmony_ci 8501cb0ef41Sopenharmony_ci if (!dep_stream && 8511cb0ef41Sopenharmony_ci session_detect_idle_stream(session, pri_spec->stream_id)) { 8521cb0ef41Sopenharmony_ci 8531cb0ef41Sopenharmony_ci nghttp2_priority_spec_default_init(&pri_spec_default); 8541cb0ef41Sopenharmony_ci 8551cb0ef41Sopenharmony_ci dep_stream = nghttp2_session_open_stream( 8561cb0ef41Sopenharmony_ci session, pri_spec->stream_id, NGHTTP2_FLAG_NONE, &pri_spec_default, 8571cb0ef41Sopenharmony_ci NGHTTP2_STREAM_IDLE, NULL); 8581cb0ef41Sopenharmony_ci 8591cb0ef41Sopenharmony_ci if (dep_stream == NULL) { 8601cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 8611cb0ef41Sopenharmony_ci } 8621cb0ef41Sopenharmony_ci } else if (!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) { 8631cb0ef41Sopenharmony_ci nghttp2_priority_spec_default_init(&pri_spec_default); 8641cb0ef41Sopenharmony_ci pri_spec = &pri_spec_default; 8651cb0ef41Sopenharmony_ci } 8661cb0ef41Sopenharmony_ci } 8671cb0ef41Sopenharmony_ci 8681cb0ef41Sopenharmony_ci if (pri_spec->stream_id == 0) { 8691cb0ef41Sopenharmony_ci dep_stream = &session->root; 8701cb0ef41Sopenharmony_ci } else if (nghttp2_stream_dep_find_ancestor(dep_stream, stream)) { 8711cb0ef41Sopenharmony_ci DEBUGF("stream: cycle detected, dep_stream(%p)=%d stream(%p)=%d\n", 8721cb0ef41Sopenharmony_ci dep_stream, dep_stream->stream_id, stream, stream->stream_id); 8731cb0ef41Sopenharmony_ci 8741cb0ef41Sopenharmony_ci nghttp2_stream_dep_remove_subtree(dep_stream); 8751cb0ef41Sopenharmony_ci rv = nghttp2_stream_dep_add_subtree(stream->dep_prev, dep_stream); 8761cb0ef41Sopenharmony_ci if (rv != 0) { 8771cb0ef41Sopenharmony_ci return rv; 8781cb0ef41Sopenharmony_ci } 8791cb0ef41Sopenharmony_ci } 8801cb0ef41Sopenharmony_ci 8811cb0ef41Sopenharmony_ci assert(dep_stream); 8821cb0ef41Sopenharmony_ci 8831cb0ef41Sopenharmony_ci if (dep_stream == stream->dep_prev && !pri_spec->exclusive) { 8841cb0ef41Sopenharmony_ci /* This is minor optimization when just weight is changed. */ 8851cb0ef41Sopenharmony_ci nghttp2_stream_change_weight(stream, pri_spec->weight); 8861cb0ef41Sopenharmony_ci 8871cb0ef41Sopenharmony_ci return 0; 8881cb0ef41Sopenharmony_ci } 8891cb0ef41Sopenharmony_ci 8901cb0ef41Sopenharmony_ci nghttp2_stream_dep_remove_subtree(stream); 8911cb0ef41Sopenharmony_ci 8921cb0ef41Sopenharmony_ci /* We have to update weight after removing stream from tree */ 8931cb0ef41Sopenharmony_ci stream->weight = pri_spec->weight; 8941cb0ef41Sopenharmony_ci 8951cb0ef41Sopenharmony_ci if (pri_spec->exclusive) { 8961cb0ef41Sopenharmony_ci rv = nghttp2_stream_dep_insert_subtree(dep_stream, stream); 8971cb0ef41Sopenharmony_ci } else { 8981cb0ef41Sopenharmony_ci rv = nghttp2_stream_dep_add_subtree(dep_stream, stream); 8991cb0ef41Sopenharmony_ci } 9001cb0ef41Sopenharmony_ci 9011cb0ef41Sopenharmony_ci if (rv != 0) { 9021cb0ef41Sopenharmony_ci return rv; 9031cb0ef41Sopenharmony_ci } 9041cb0ef41Sopenharmony_ci 9051cb0ef41Sopenharmony_ci return 0; 9061cb0ef41Sopenharmony_ci} 9071cb0ef41Sopenharmony_ci 9081cb0ef41Sopenharmony_cistatic uint64_t pq_get_first_cycle(nghttp2_pq *pq) { 9091cb0ef41Sopenharmony_ci nghttp2_stream *stream; 9101cb0ef41Sopenharmony_ci 9111cb0ef41Sopenharmony_ci if (nghttp2_pq_empty(pq)) { 9121cb0ef41Sopenharmony_ci return 0; 9131cb0ef41Sopenharmony_ci } 9141cb0ef41Sopenharmony_ci 9151cb0ef41Sopenharmony_ci stream = nghttp2_struct_of(nghttp2_pq_top(pq), nghttp2_stream, pq_entry); 9161cb0ef41Sopenharmony_ci return stream->cycle; 9171cb0ef41Sopenharmony_ci} 9181cb0ef41Sopenharmony_ci 9191cb0ef41Sopenharmony_cistatic int session_ob_data_push(nghttp2_session *session, 9201cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 9211cb0ef41Sopenharmony_ci int rv; 9221cb0ef41Sopenharmony_ci uint32_t urgency; 9231cb0ef41Sopenharmony_ci int inc; 9241cb0ef41Sopenharmony_ci nghttp2_pq *pq; 9251cb0ef41Sopenharmony_ci 9261cb0ef41Sopenharmony_ci assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES); 9271cb0ef41Sopenharmony_ci assert(stream->queued == 0); 9281cb0ef41Sopenharmony_ci 9291cb0ef41Sopenharmony_ci urgency = nghttp2_extpri_uint8_urgency(stream->extpri); 9301cb0ef41Sopenharmony_ci inc = nghttp2_extpri_uint8_inc(stream->extpri); 9311cb0ef41Sopenharmony_ci 9321cb0ef41Sopenharmony_ci assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS); 9331cb0ef41Sopenharmony_ci 9341cb0ef41Sopenharmony_ci pq = &session->sched[urgency].ob_data; 9351cb0ef41Sopenharmony_ci 9361cb0ef41Sopenharmony_ci stream->cycle = pq_get_first_cycle(pq); 9371cb0ef41Sopenharmony_ci if (inc) { 9381cb0ef41Sopenharmony_ci stream->cycle += stream->last_writelen; 9391cb0ef41Sopenharmony_ci } 9401cb0ef41Sopenharmony_ci 9411cb0ef41Sopenharmony_ci rv = nghttp2_pq_push(pq, &stream->pq_entry); 9421cb0ef41Sopenharmony_ci if (rv != 0) { 9431cb0ef41Sopenharmony_ci return rv; 9441cb0ef41Sopenharmony_ci } 9451cb0ef41Sopenharmony_ci 9461cb0ef41Sopenharmony_ci stream->queued = 1; 9471cb0ef41Sopenharmony_ci 9481cb0ef41Sopenharmony_ci return 0; 9491cb0ef41Sopenharmony_ci} 9501cb0ef41Sopenharmony_ci 9511cb0ef41Sopenharmony_cistatic void session_ob_data_remove(nghttp2_session *session, 9521cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 9531cb0ef41Sopenharmony_ci uint32_t urgency; 9541cb0ef41Sopenharmony_ci 9551cb0ef41Sopenharmony_ci assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES); 9561cb0ef41Sopenharmony_ci assert(stream->queued == 1); 9571cb0ef41Sopenharmony_ci 9581cb0ef41Sopenharmony_ci urgency = nghttp2_extpri_uint8_urgency(stream->extpri); 9591cb0ef41Sopenharmony_ci 9601cb0ef41Sopenharmony_ci assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS); 9611cb0ef41Sopenharmony_ci 9621cb0ef41Sopenharmony_ci nghttp2_pq_remove(&session->sched[urgency].ob_data, &stream->pq_entry); 9631cb0ef41Sopenharmony_ci 9641cb0ef41Sopenharmony_ci stream->queued = 0; 9651cb0ef41Sopenharmony_ci} 9661cb0ef41Sopenharmony_ci 9671cb0ef41Sopenharmony_cistatic int session_attach_stream_item(nghttp2_session *session, 9681cb0ef41Sopenharmony_ci nghttp2_stream *stream, 9691cb0ef41Sopenharmony_ci nghttp2_outbound_item *item) { 9701cb0ef41Sopenharmony_ci int rv; 9711cb0ef41Sopenharmony_ci 9721cb0ef41Sopenharmony_ci rv = nghttp2_stream_attach_item(stream, item); 9731cb0ef41Sopenharmony_ci if (rv != 0) { 9741cb0ef41Sopenharmony_ci return rv; 9751cb0ef41Sopenharmony_ci } 9761cb0ef41Sopenharmony_ci 9771cb0ef41Sopenharmony_ci if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) { 9781cb0ef41Sopenharmony_ci return 0; 9791cb0ef41Sopenharmony_ci } 9801cb0ef41Sopenharmony_ci 9811cb0ef41Sopenharmony_ci return session_ob_data_push(session, stream); 9821cb0ef41Sopenharmony_ci} 9831cb0ef41Sopenharmony_ci 9841cb0ef41Sopenharmony_cistatic void session_detach_stream_item(nghttp2_session *session, 9851cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 9861cb0ef41Sopenharmony_ci nghttp2_stream_detach_item(stream); 9871cb0ef41Sopenharmony_ci 9881cb0ef41Sopenharmony_ci if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || 9891cb0ef41Sopenharmony_ci !stream->queued) { 9901cb0ef41Sopenharmony_ci return; 9911cb0ef41Sopenharmony_ci } 9921cb0ef41Sopenharmony_ci 9931cb0ef41Sopenharmony_ci session_ob_data_remove(session, stream); 9941cb0ef41Sopenharmony_ci} 9951cb0ef41Sopenharmony_ci 9961cb0ef41Sopenharmony_cistatic void session_defer_stream_item(nghttp2_session *session, 9971cb0ef41Sopenharmony_ci nghttp2_stream *stream, uint8_t flags) { 9981cb0ef41Sopenharmony_ci nghttp2_stream_defer_item(stream, flags); 9991cb0ef41Sopenharmony_ci 10001cb0ef41Sopenharmony_ci if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || 10011cb0ef41Sopenharmony_ci !stream->queued) { 10021cb0ef41Sopenharmony_ci return; 10031cb0ef41Sopenharmony_ci } 10041cb0ef41Sopenharmony_ci 10051cb0ef41Sopenharmony_ci session_ob_data_remove(session, stream); 10061cb0ef41Sopenharmony_ci} 10071cb0ef41Sopenharmony_ci 10081cb0ef41Sopenharmony_cistatic int session_resume_deferred_stream_item(nghttp2_session *session, 10091cb0ef41Sopenharmony_ci nghttp2_stream *stream, 10101cb0ef41Sopenharmony_ci uint8_t flags) { 10111cb0ef41Sopenharmony_ci int rv; 10121cb0ef41Sopenharmony_ci 10131cb0ef41Sopenharmony_ci rv = nghttp2_stream_resume_deferred_item(stream, flags); 10141cb0ef41Sopenharmony_ci if (rv != 0) { 10151cb0ef41Sopenharmony_ci return rv; 10161cb0ef41Sopenharmony_ci } 10171cb0ef41Sopenharmony_ci 10181cb0ef41Sopenharmony_ci if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || 10191cb0ef41Sopenharmony_ci (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL)) { 10201cb0ef41Sopenharmony_ci return 0; 10211cb0ef41Sopenharmony_ci } 10221cb0ef41Sopenharmony_ci 10231cb0ef41Sopenharmony_ci return session_ob_data_push(session, stream); 10241cb0ef41Sopenharmony_ci} 10251cb0ef41Sopenharmony_ci 10261cb0ef41Sopenharmony_cistatic nghttp2_outbound_item * 10271cb0ef41Sopenharmony_cisession_sched_get_next_outbound_item(nghttp2_session *session) { 10281cb0ef41Sopenharmony_ci size_t i; 10291cb0ef41Sopenharmony_ci nghttp2_pq_entry *ent; 10301cb0ef41Sopenharmony_ci nghttp2_stream *stream; 10311cb0ef41Sopenharmony_ci 10321cb0ef41Sopenharmony_ci for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) { 10331cb0ef41Sopenharmony_ci ent = nghttp2_pq_top(&session->sched[i].ob_data); 10341cb0ef41Sopenharmony_ci if (!ent) { 10351cb0ef41Sopenharmony_ci continue; 10361cb0ef41Sopenharmony_ci } 10371cb0ef41Sopenharmony_ci 10381cb0ef41Sopenharmony_ci stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry); 10391cb0ef41Sopenharmony_ci return stream->item; 10401cb0ef41Sopenharmony_ci } 10411cb0ef41Sopenharmony_ci 10421cb0ef41Sopenharmony_ci return NULL; 10431cb0ef41Sopenharmony_ci} 10441cb0ef41Sopenharmony_ci 10451cb0ef41Sopenharmony_cistatic int session_sched_empty(nghttp2_session *session) { 10461cb0ef41Sopenharmony_ci size_t i; 10471cb0ef41Sopenharmony_ci 10481cb0ef41Sopenharmony_ci for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) { 10491cb0ef41Sopenharmony_ci if (!nghttp2_pq_empty(&session->sched[i].ob_data)) { 10501cb0ef41Sopenharmony_ci return 0; 10511cb0ef41Sopenharmony_ci } 10521cb0ef41Sopenharmony_ci } 10531cb0ef41Sopenharmony_ci 10541cb0ef41Sopenharmony_ci return 1; 10551cb0ef41Sopenharmony_ci} 10561cb0ef41Sopenharmony_ci 10571cb0ef41Sopenharmony_cistatic void session_sched_reschedule_stream(nghttp2_session *session, 10581cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 10591cb0ef41Sopenharmony_ci nghttp2_pq *pq; 10601cb0ef41Sopenharmony_ci uint32_t urgency = nghttp2_extpri_uint8_urgency(stream->extpri); 10611cb0ef41Sopenharmony_ci int inc = nghttp2_extpri_uint8_inc(stream->extpri); 10621cb0ef41Sopenharmony_ci uint64_t penalty = (uint64_t)stream->last_writelen; 10631cb0ef41Sopenharmony_ci int rv; 10641cb0ef41Sopenharmony_ci 10651cb0ef41Sopenharmony_ci (void)rv; 10661cb0ef41Sopenharmony_ci 10671cb0ef41Sopenharmony_ci assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS); 10681cb0ef41Sopenharmony_ci 10691cb0ef41Sopenharmony_ci pq = &session->sched[urgency].ob_data; 10701cb0ef41Sopenharmony_ci 10711cb0ef41Sopenharmony_ci if (!inc || nghttp2_pq_size(pq) == 1) { 10721cb0ef41Sopenharmony_ci return; 10731cb0ef41Sopenharmony_ci } 10741cb0ef41Sopenharmony_ci 10751cb0ef41Sopenharmony_ci nghttp2_pq_remove(pq, &stream->pq_entry); 10761cb0ef41Sopenharmony_ci 10771cb0ef41Sopenharmony_ci stream->cycle += penalty; 10781cb0ef41Sopenharmony_ci 10791cb0ef41Sopenharmony_ci rv = nghttp2_pq_push(pq, &stream->pq_entry); 10801cb0ef41Sopenharmony_ci 10811cb0ef41Sopenharmony_ci assert(0 == rv); 10821cb0ef41Sopenharmony_ci} 10831cb0ef41Sopenharmony_ci 10841cb0ef41Sopenharmony_cistatic int session_update_stream_priority(nghttp2_session *session, 10851cb0ef41Sopenharmony_ci nghttp2_stream *stream, 10861cb0ef41Sopenharmony_ci uint8_t u8extpri) { 10871cb0ef41Sopenharmony_ci if (stream->extpri == u8extpri) { 10881cb0ef41Sopenharmony_ci return 0; 10891cb0ef41Sopenharmony_ci } 10901cb0ef41Sopenharmony_ci 10911cb0ef41Sopenharmony_ci if (stream->queued) { 10921cb0ef41Sopenharmony_ci session_ob_data_remove(session, stream); 10931cb0ef41Sopenharmony_ci 10941cb0ef41Sopenharmony_ci stream->extpri = u8extpri; 10951cb0ef41Sopenharmony_ci 10961cb0ef41Sopenharmony_ci return session_ob_data_push(session, stream); 10971cb0ef41Sopenharmony_ci } 10981cb0ef41Sopenharmony_ci 10991cb0ef41Sopenharmony_ci stream->extpri = u8extpri; 11001cb0ef41Sopenharmony_ci 11011cb0ef41Sopenharmony_ci return 0; 11021cb0ef41Sopenharmony_ci} 11031cb0ef41Sopenharmony_ci 11041cb0ef41Sopenharmony_ciint nghttp2_session_add_item(nghttp2_session *session, 11051cb0ef41Sopenharmony_ci nghttp2_outbound_item *item) { 11061cb0ef41Sopenharmony_ci /* TODO Return error if stream is not found for the frame requiring 11071cb0ef41Sopenharmony_ci stream presence. */ 11081cb0ef41Sopenharmony_ci int rv = 0; 11091cb0ef41Sopenharmony_ci nghttp2_stream *stream; 11101cb0ef41Sopenharmony_ci nghttp2_frame *frame; 11111cb0ef41Sopenharmony_ci 11121cb0ef41Sopenharmony_ci frame = &item->frame; 11131cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 11141cb0ef41Sopenharmony_ci 11151cb0ef41Sopenharmony_ci switch (frame->hd.type) { 11161cb0ef41Sopenharmony_ci case NGHTTP2_DATA: 11171cb0ef41Sopenharmony_ci if (!stream) { 11181cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSED; 11191cb0ef41Sopenharmony_ci } 11201cb0ef41Sopenharmony_ci 11211cb0ef41Sopenharmony_ci if (stream->item) { 11221cb0ef41Sopenharmony_ci return NGHTTP2_ERR_DATA_EXIST; 11231cb0ef41Sopenharmony_ci } 11241cb0ef41Sopenharmony_ci 11251cb0ef41Sopenharmony_ci rv = session_attach_stream_item(session, stream, item); 11261cb0ef41Sopenharmony_ci 11271cb0ef41Sopenharmony_ci if (rv != 0) { 11281cb0ef41Sopenharmony_ci return rv; 11291cb0ef41Sopenharmony_ci } 11301cb0ef41Sopenharmony_ci 11311cb0ef41Sopenharmony_ci return 0; 11321cb0ef41Sopenharmony_ci case NGHTTP2_HEADERS: 11331cb0ef41Sopenharmony_ci /* We push request HEADERS and push response HEADERS to 11341cb0ef41Sopenharmony_ci dedicated queue because their transmission is affected by 11351cb0ef41Sopenharmony_ci SETTINGS_MAX_CONCURRENT_STREAMS */ 11361cb0ef41Sopenharmony_ci /* TODO If 2 HEADERS are submitted for reserved stream, then 11371cb0ef41Sopenharmony_ci both of them are queued into ob_syn, which is not 11381cb0ef41Sopenharmony_ci desirable. */ 11391cb0ef41Sopenharmony_ci if (frame->headers.cat == NGHTTP2_HCAT_REQUEST || 11401cb0ef41Sopenharmony_ci (stream && stream->state == NGHTTP2_STREAM_RESERVED)) { 11411cb0ef41Sopenharmony_ci nghttp2_outbound_queue_push(&session->ob_syn, item); 11421cb0ef41Sopenharmony_ci item->queued = 1; 11431cb0ef41Sopenharmony_ci return 0; 11441cb0ef41Sopenharmony_ci ; 11451cb0ef41Sopenharmony_ci } 11461cb0ef41Sopenharmony_ci 11471cb0ef41Sopenharmony_ci nghttp2_outbound_queue_push(&session->ob_reg, item); 11481cb0ef41Sopenharmony_ci item->queued = 1; 11491cb0ef41Sopenharmony_ci return 0; 11501cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS: 11511cb0ef41Sopenharmony_ci case NGHTTP2_PING: 11521cb0ef41Sopenharmony_ci nghttp2_outbound_queue_push(&session->ob_urgent, item); 11531cb0ef41Sopenharmony_ci item->queued = 1; 11541cb0ef41Sopenharmony_ci return 0; 11551cb0ef41Sopenharmony_ci case NGHTTP2_RST_STREAM: 11561cb0ef41Sopenharmony_ci if (stream) { 11571cb0ef41Sopenharmony_ci stream->state = NGHTTP2_STREAM_CLOSING; 11581cb0ef41Sopenharmony_ci } 11591cb0ef41Sopenharmony_ci nghttp2_outbound_queue_push(&session->ob_reg, item); 11601cb0ef41Sopenharmony_ci item->queued = 1; 11611cb0ef41Sopenharmony_ci return 0; 11621cb0ef41Sopenharmony_ci case NGHTTP2_PUSH_PROMISE: { 11631cb0ef41Sopenharmony_ci nghttp2_headers_aux_data *aux_data; 11641cb0ef41Sopenharmony_ci nghttp2_priority_spec pri_spec; 11651cb0ef41Sopenharmony_ci 11661cb0ef41Sopenharmony_ci aux_data = &item->aux_data.headers; 11671cb0ef41Sopenharmony_ci 11681cb0ef41Sopenharmony_ci if (!stream) { 11691cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSED; 11701cb0ef41Sopenharmony_ci } 11711cb0ef41Sopenharmony_ci 11721cb0ef41Sopenharmony_ci nghttp2_priority_spec_init(&pri_spec, stream->stream_id, 11731cb0ef41Sopenharmony_ci NGHTTP2_DEFAULT_WEIGHT, 0); 11741cb0ef41Sopenharmony_ci 11751cb0ef41Sopenharmony_ci if (!nghttp2_session_open_stream( 11761cb0ef41Sopenharmony_ci session, frame->push_promise.promised_stream_id, 11771cb0ef41Sopenharmony_ci NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_RESERVED, 11781cb0ef41Sopenharmony_ci aux_data->stream_user_data)) { 11791cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 11801cb0ef41Sopenharmony_ci } 11811cb0ef41Sopenharmony_ci 11821cb0ef41Sopenharmony_ci /* We don't have to call nghttp2_session_adjust_closed_stream() 11831cb0ef41Sopenharmony_ci here, since stream->stream_id is local stream_id, and it does 11841cb0ef41Sopenharmony_ci not affect closed stream count. */ 11851cb0ef41Sopenharmony_ci 11861cb0ef41Sopenharmony_ci nghttp2_outbound_queue_push(&session->ob_reg, item); 11871cb0ef41Sopenharmony_ci item->queued = 1; 11881cb0ef41Sopenharmony_ci 11891cb0ef41Sopenharmony_ci return 0; 11901cb0ef41Sopenharmony_ci } 11911cb0ef41Sopenharmony_ci case NGHTTP2_WINDOW_UPDATE: 11921cb0ef41Sopenharmony_ci if (stream) { 11931cb0ef41Sopenharmony_ci stream->window_update_queued = 1; 11941cb0ef41Sopenharmony_ci } else if (frame->hd.stream_id == 0) { 11951cb0ef41Sopenharmony_ci session->window_update_queued = 1; 11961cb0ef41Sopenharmony_ci } 11971cb0ef41Sopenharmony_ci nghttp2_outbound_queue_push(&session->ob_reg, item); 11981cb0ef41Sopenharmony_ci item->queued = 1; 11991cb0ef41Sopenharmony_ci return 0; 12001cb0ef41Sopenharmony_ci default: 12011cb0ef41Sopenharmony_ci nghttp2_outbound_queue_push(&session->ob_reg, item); 12021cb0ef41Sopenharmony_ci item->queued = 1; 12031cb0ef41Sopenharmony_ci return 0; 12041cb0ef41Sopenharmony_ci } 12051cb0ef41Sopenharmony_ci} 12061cb0ef41Sopenharmony_ci 12071cb0ef41Sopenharmony_ciint nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id, 12081cb0ef41Sopenharmony_ci uint32_t error_code) { 12091cb0ef41Sopenharmony_ci int rv; 12101cb0ef41Sopenharmony_ci nghttp2_outbound_item *item; 12111cb0ef41Sopenharmony_ci nghttp2_frame *frame; 12121cb0ef41Sopenharmony_ci nghttp2_stream *stream; 12131cb0ef41Sopenharmony_ci nghttp2_mem *mem; 12141cb0ef41Sopenharmony_ci 12151cb0ef41Sopenharmony_ci mem = &session->mem; 12161cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 12171cb0ef41Sopenharmony_ci if (stream && stream->state == NGHTTP2_STREAM_CLOSING) { 12181cb0ef41Sopenharmony_ci return 0; 12191cb0ef41Sopenharmony_ci } 12201cb0ef41Sopenharmony_ci 12211cb0ef41Sopenharmony_ci /* Sending RST_STREAM to an idle stream is subject to protocol 12221cb0ef41Sopenharmony_ci violation. Historically, nghttp2 allows this. In order not to 12231cb0ef41Sopenharmony_ci disrupt the existing applications, we don't error out this case 12241cb0ef41Sopenharmony_ci and simply ignore it. */ 12251cb0ef41Sopenharmony_ci if (nghttp2_session_is_my_stream_id(session, stream_id)) { 12261cb0ef41Sopenharmony_ci if ((uint32_t)stream_id >= session->next_stream_id) { 12271cb0ef41Sopenharmony_ci return 0; 12281cb0ef41Sopenharmony_ci } 12291cb0ef41Sopenharmony_ci } else if (session->last_recv_stream_id < stream_id) { 12301cb0ef41Sopenharmony_ci return 0; 12311cb0ef41Sopenharmony_ci } 12321cb0ef41Sopenharmony_ci 12331cb0ef41Sopenharmony_ci /* Cancel pending request HEADERS in ob_syn if this RST_STREAM 12341cb0ef41Sopenharmony_ci refers to that stream. */ 12351cb0ef41Sopenharmony_ci if (!session->server && nghttp2_session_is_my_stream_id(session, stream_id) && 12361cb0ef41Sopenharmony_ci nghttp2_outbound_queue_top(&session->ob_syn)) { 12371cb0ef41Sopenharmony_ci nghttp2_headers_aux_data *aux_data; 12381cb0ef41Sopenharmony_ci nghttp2_frame *headers_frame; 12391cb0ef41Sopenharmony_ci 12401cb0ef41Sopenharmony_ci headers_frame = &nghttp2_outbound_queue_top(&session->ob_syn)->frame; 12411cb0ef41Sopenharmony_ci assert(headers_frame->hd.type == NGHTTP2_HEADERS); 12421cb0ef41Sopenharmony_ci 12431cb0ef41Sopenharmony_ci if (headers_frame->hd.stream_id <= stream_id) { 12441cb0ef41Sopenharmony_ci 12451cb0ef41Sopenharmony_ci for (item = session->ob_syn.head; item; item = item->qnext) { 12461cb0ef41Sopenharmony_ci aux_data = &item->aux_data.headers; 12471cb0ef41Sopenharmony_ci 12481cb0ef41Sopenharmony_ci if (item->frame.hd.stream_id < stream_id) { 12491cb0ef41Sopenharmony_ci continue; 12501cb0ef41Sopenharmony_ci } 12511cb0ef41Sopenharmony_ci 12521cb0ef41Sopenharmony_ci /* stream_id in ob_syn queue must be strictly increasing. If 12531cb0ef41Sopenharmony_ci we found larger ID, then we can break here. */ 12541cb0ef41Sopenharmony_ci if (item->frame.hd.stream_id > stream_id || aux_data->canceled) { 12551cb0ef41Sopenharmony_ci break; 12561cb0ef41Sopenharmony_ci } 12571cb0ef41Sopenharmony_ci 12581cb0ef41Sopenharmony_ci aux_data->error_code = error_code; 12591cb0ef41Sopenharmony_ci aux_data->canceled = 1; 12601cb0ef41Sopenharmony_ci 12611cb0ef41Sopenharmony_ci return 0; 12621cb0ef41Sopenharmony_ci } 12631cb0ef41Sopenharmony_ci } 12641cb0ef41Sopenharmony_ci } 12651cb0ef41Sopenharmony_ci 12661cb0ef41Sopenharmony_ci item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); 12671cb0ef41Sopenharmony_ci if (item == NULL) { 12681cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 12691cb0ef41Sopenharmony_ci } 12701cb0ef41Sopenharmony_ci 12711cb0ef41Sopenharmony_ci nghttp2_outbound_item_init(item); 12721cb0ef41Sopenharmony_ci 12731cb0ef41Sopenharmony_ci frame = &item->frame; 12741cb0ef41Sopenharmony_ci 12751cb0ef41Sopenharmony_ci nghttp2_frame_rst_stream_init(&frame->rst_stream, stream_id, error_code); 12761cb0ef41Sopenharmony_ci rv = nghttp2_session_add_item(session, item); 12771cb0ef41Sopenharmony_ci if (rv != 0) { 12781cb0ef41Sopenharmony_ci nghttp2_frame_rst_stream_free(&frame->rst_stream); 12791cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, item); 12801cb0ef41Sopenharmony_ci return rv; 12811cb0ef41Sopenharmony_ci } 12821cb0ef41Sopenharmony_ci return 0; 12831cb0ef41Sopenharmony_ci} 12841cb0ef41Sopenharmony_ci 12851cb0ef41Sopenharmony_cinghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, 12861cb0ef41Sopenharmony_ci int32_t stream_id, uint8_t flags, 12871cb0ef41Sopenharmony_ci nghttp2_priority_spec *pri_spec_in, 12881cb0ef41Sopenharmony_ci nghttp2_stream_state initial_state, 12891cb0ef41Sopenharmony_ci void *stream_user_data) { 12901cb0ef41Sopenharmony_ci int rv; 12911cb0ef41Sopenharmony_ci nghttp2_stream *stream; 12921cb0ef41Sopenharmony_ci nghttp2_stream *dep_stream = NULL; 12931cb0ef41Sopenharmony_ci int stream_alloc = 0; 12941cb0ef41Sopenharmony_ci nghttp2_priority_spec pri_spec_default; 12951cb0ef41Sopenharmony_ci nghttp2_priority_spec *pri_spec = pri_spec_in; 12961cb0ef41Sopenharmony_ci nghttp2_mem *mem; 12971cb0ef41Sopenharmony_ci 12981cb0ef41Sopenharmony_ci mem = &session->mem; 12991cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream_raw(session, stream_id); 13001cb0ef41Sopenharmony_ci 13011cb0ef41Sopenharmony_ci if (session->opt_flags & 13021cb0ef41Sopenharmony_ci NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) { 13031cb0ef41Sopenharmony_ci flags |= NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION; 13041cb0ef41Sopenharmony_ci } 13051cb0ef41Sopenharmony_ci 13061cb0ef41Sopenharmony_ci if (stream) { 13071cb0ef41Sopenharmony_ci assert(stream->state == NGHTTP2_STREAM_IDLE); 13081cb0ef41Sopenharmony_ci assert((stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || 13091cb0ef41Sopenharmony_ci nghttp2_stream_in_dep_tree(stream)); 13101cb0ef41Sopenharmony_ci 13111cb0ef41Sopenharmony_ci if (nghttp2_stream_in_dep_tree(stream)) { 13121cb0ef41Sopenharmony_ci assert(!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)); 13131cb0ef41Sopenharmony_ci nghttp2_session_detach_idle_stream(session, stream); 13141cb0ef41Sopenharmony_ci rv = nghttp2_stream_dep_remove(stream); 13151cb0ef41Sopenharmony_ci if (rv != 0) { 13161cb0ef41Sopenharmony_ci return NULL; 13171cb0ef41Sopenharmony_ci } 13181cb0ef41Sopenharmony_ci 13191cb0ef41Sopenharmony_ci if (session_no_rfc7540_pri_no_fallback(session)) { 13201cb0ef41Sopenharmony_ci stream->flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES; 13211cb0ef41Sopenharmony_ci } 13221cb0ef41Sopenharmony_ci } 13231cb0ef41Sopenharmony_ci } else { 13241cb0ef41Sopenharmony_ci stream = nghttp2_mem_malloc(mem, sizeof(nghttp2_stream)); 13251cb0ef41Sopenharmony_ci if (stream == NULL) { 13261cb0ef41Sopenharmony_ci return NULL; 13271cb0ef41Sopenharmony_ci } 13281cb0ef41Sopenharmony_ci 13291cb0ef41Sopenharmony_ci stream_alloc = 1; 13301cb0ef41Sopenharmony_ci } 13311cb0ef41Sopenharmony_ci 13321cb0ef41Sopenharmony_ci if (session_no_rfc7540_pri_no_fallback(session) || 13331cb0ef41Sopenharmony_ci session->remote_settings.no_rfc7540_priorities == 1) { 13341cb0ef41Sopenharmony_ci /* For client which has not received server 13351cb0ef41Sopenharmony_ci SETTINGS_NO_RFC7540_PRIORITIES = 1, send a priority signal 13361cb0ef41Sopenharmony_ci opportunistically. */ 13371cb0ef41Sopenharmony_ci if (session->server || 13381cb0ef41Sopenharmony_ci session->remote_settings.no_rfc7540_priorities == 1) { 13391cb0ef41Sopenharmony_ci nghttp2_priority_spec_default_init(&pri_spec_default); 13401cb0ef41Sopenharmony_ci pri_spec = &pri_spec_default; 13411cb0ef41Sopenharmony_ci } 13421cb0ef41Sopenharmony_ci 13431cb0ef41Sopenharmony_ci if (session->pending_no_rfc7540_priorities == 1) { 13441cb0ef41Sopenharmony_ci flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES; 13451cb0ef41Sopenharmony_ci } 13461cb0ef41Sopenharmony_ci } else if (pri_spec->stream_id != 0) { 13471cb0ef41Sopenharmony_ci dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); 13481cb0ef41Sopenharmony_ci 13491cb0ef41Sopenharmony_ci if (!dep_stream && 13501cb0ef41Sopenharmony_ci session_detect_idle_stream(session, pri_spec->stream_id)) { 13511cb0ef41Sopenharmony_ci /* Depends on idle stream, which does not exist in memory. 13521cb0ef41Sopenharmony_ci Assign default priority for it. */ 13531cb0ef41Sopenharmony_ci nghttp2_priority_spec_default_init(&pri_spec_default); 13541cb0ef41Sopenharmony_ci 13551cb0ef41Sopenharmony_ci dep_stream = nghttp2_session_open_stream( 13561cb0ef41Sopenharmony_ci session, pri_spec->stream_id, NGHTTP2_FLAG_NONE, &pri_spec_default, 13571cb0ef41Sopenharmony_ci NGHTTP2_STREAM_IDLE, NULL); 13581cb0ef41Sopenharmony_ci 13591cb0ef41Sopenharmony_ci if (dep_stream == NULL) { 13601cb0ef41Sopenharmony_ci if (stream_alloc) { 13611cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, stream); 13621cb0ef41Sopenharmony_ci } 13631cb0ef41Sopenharmony_ci 13641cb0ef41Sopenharmony_ci return NULL; 13651cb0ef41Sopenharmony_ci } 13661cb0ef41Sopenharmony_ci } else if (!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) { 13671cb0ef41Sopenharmony_ci /* If dep_stream is not part of dependency tree, stream will get 13681cb0ef41Sopenharmony_ci default priority. This handles the case when 13691cb0ef41Sopenharmony_ci pri_spec->stream_id == stream_id. This happens because we 13701cb0ef41Sopenharmony_ci don't check pri_spec->stream_id against new stream ID in 13711cb0ef41Sopenharmony_ci nghttp2_submit_request. This also handles the case when idle 13721cb0ef41Sopenharmony_ci stream created by PRIORITY frame was opened. Somehow we 13731cb0ef41Sopenharmony_ci first remove the idle stream from dependency tree. This is 13741cb0ef41Sopenharmony_ci done to simplify code base, but ideally we should retain old 13751cb0ef41Sopenharmony_ci dependency. But I'm not sure this adds values. */ 13761cb0ef41Sopenharmony_ci nghttp2_priority_spec_default_init(&pri_spec_default); 13771cb0ef41Sopenharmony_ci pri_spec = &pri_spec_default; 13781cb0ef41Sopenharmony_ci } 13791cb0ef41Sopenharmony_ci } 13801cb0ef41Sopenharmony_ci 13811cb0ef41Sopenharmony_ci if (initial_state == NGHTTP2_STREAM_RESERVED) { 13821cb0ef41Sopenharmony_ci flags |= NGHTTP2_STREAM_FLAG_PUSH; 13831cb0ef41Sopenharmony_ci } 13841cb0ef41Sopenharmony_ci 13851cb0ef41Sopenharmony_ci if (stream_alloc) { 13861cb0ef41Sopenharmony_ci nghttp2_stream_init(stream, stream_id, flags, initial_state, 13871cb0ef41Sopenharmony_ci pri_spec->weight, 13881cb0ef41Sopenharmony_ci (int32_t)session->remote_settings.initial_window_size, 13891cb0ef41Sopenharmony_ci (int32_t)session->local_settings.initial_window_size, 13901cb0ef41Sopenharmony_ci stream_user_data, mem); 13911cb0ef41Sopenharmony_ci 13921cb0ef41Sopenharmony_ci if (session_no_rfc7540_pri_no_fallback(session)) { 13931cb0ef41Sopenharmony_ci stream->seq = session->stream_seq++; 13941cb0ef41Sopenharmony_ci } 13951cb0ef41Sopenharmony_ci 13961cb0ef41Sopenharmony_ci rv = nghttp2_map_insert(&session->streams, stream_id, stream); 13971cb0ef41Sopenharmony_ci if (rv != 0) { 13981cb0ef41Sopenharmony_ci nghttp2_stream_free(stream); 13991cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, stream); 14001cb0ef41Sopenharmony_ci return NULL; 14011cb0ef41Sopenharmony_ci } 14021cb0ef41Sopenharmony_ci } else { 14031cb0ef41Sopenharmony_ci stream->flags = flags; 14041cb0ef41Sopenharmony_ci stream->state = initial_state; 14051cb0ef41Sopenharmony_ci stream->weight = pri_spec->weight; 14061cb0ef41Sopenharmony_ci stream->stream_user_data = stream_user_data; 14071cb0ef41Sopenharmony_ci } 14081cb0ef41Sopenharmony_ci 14091cb0ef41Sopenharmony_ci switch (initial_state) { 14101cb0ef41Sopenharmony_ci case NGHTTP2_STREAM_RESERVED: 14111cb0ef41Sopenharmony_ci if (nghttp2_session_is_my_stream_id(session, stream_id)) { 14121cb0ef41Sopenharmony_ci /* reserved (local) */ 14131cb0ef41Sopenharmony_ci nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); 14141cb0ef41Sopenharmony_ci } else { 14151cb0ef41Sopenharmony_ci /* reserved (remote) */ 14161cb0ef41Sopenharmony_ci nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); 14171cb0ef41Sopenharmony_ci ++session->num_incoming_reserved_streams; 14181cb0ef41Sopenharmony_ci } 14191cb0ef41Sopenharmony_ci /* Reserved stream does not count in the concurrent streams 14201cb0ef41Sopenharmony_ci limit. That is one of the DOS vector. */ 14211cb0ef41Sopenharmony_ci break; 14221cb0ef41Sopenharmony_ci case NGHTTP2_STREAM_IDLE: 14231cb0ef41Sopenharmony_ci /* Idle stream does not count toward the concurrent streams limit. 14241cb0ef41Sopenharmony_ci This is used as anchor node in dependency tree. */ 14251cb0ef41Sopenharmony_ci nghttp2_session_keep_idle_stream(session, stream); 14261cb0ef41Sopenharmony_ci break; 14271cb0ef41Sopenharmony_ci default: 14281cb0ef41Sopenharmony_ci if (nghttp2_session_is_my_stream_id(session, stream_id)) { 14291cb0ef41Sopenharmony_ci ++session->num_outgoing_streams; 14301cb0ef41Sopenharmony_ci } else { 14311cb0ef41Sopenharmony_ci ++session->num_incoming_streams; 14321cb0ef41Sopenharmony_ci } 14331cb0ef41Sopenharmony_ci } 14341cb0ef41Sopenharmony_ci 14351cb0ef41Sopenharmony_ci if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { 14361cb0ef41Sopenharmony_ci return stream; 14371cb0ef41Sopenharmony_ci } 14381cb0ef41Sopenharmony_ci 14391cb0ef41Sopenharmony_ci if (pri_spec->stream_id == 0) { 14401cb0ef41Sopenharmony_ci dep_stream = &session->root; 14411cb0ef41Sopenharmony_ci } 14421cb0ef41Sopenharmony_ci 14431cb0ef41Sopenharmony_ci assert(dep_stream); 14441cb0ef41Sopenharmony_ci 14451cb0ef41Sopenharmony_ci if (pri_spec->exclusive) { 14461cb0ef41Sopenharmony_ci rv = nghttp2_stream_dep_insert(dep_stream, stream); 14471cb0ef41Sopenharmony_ci if (rv != 0) { 14481cb0ef41Sopenharmony_ci return NULL; 14491cb0ef41Sopenharmony_ci } 14501cb0ef41Sopenharmony_ci } else { 14511cb0ef41Sopenharmony_ci nghttp2_stream_dep_add(dep_stream, stream); 14521cb0ef41Sopenharmony_ci } 14531cb0ef41Sopenharmony_ci 14541cb0ef41Sopenharmony_ci return stream; 14551cb0ef41Sopenharmony_ci} 14561cb0ef41Sopenharmony_ci 14571cb0ef41Sopenharmony_ciint nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, 14581cb0ef41Sopenharmony_ci uint32_t error_code) { 14591cb0ef41Sopenharmony_ci int rv; 14601cb0ef41Sopenharmony_ci nghttp2_stream *stream; 14611cb0ef41Sopenharmony_ci nghttp2_mem *mem; 14621cb0ef41Sopenharmony_ci int is_my_stream_id; 14631cb0ef41Sopenharmony_ci 14641cb0ef41Sopenharmony_ci mem = &session->mem; 14651cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 14661cb0ef41Sopenharmony_ci 14671cb0ef41Sopenharmony_ci if (!stream) { 14681cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 14691cb0ef41Sopenharmony_ci } 14701cb0ef41Sopenharmony_ci 14711cb0ef41Sopenharmony_ci DEBUGF("stream: stream(%p)=%d close\n", stream, stream->stream_id); 14721cb0ef41Sopenharmony_ci 14731cb0ef41Sopenharmony_ci if (stream->item) { 14741cb0ef41Sopenharmony_ci nghttp2_outbound_item *item; 14751cb0ef41Sopenharmony_ci 14761cb0ef41Sopenharmony_ci item = stream->item; 14771cb0ef41Sopenharmony_ci 14781cb0ef41Sopenharmony_ci session_detach_stream_item(session, stream); 14791cb0ef41Sopenharmony_ci 14801cb0ef41Sopenharmony_ci /* If item is queued, it will be deleted when it is popped 14811cb0ef41Sopenharmony_ci (nghttp2_session_prep_frame() will fail). If session->aob.item 14821cb0ef41Sopenharmony_ci points to this item, let active_outbound_item_reset() 14831cb0ef41Sopenharmony_ci free the item. */ 14841cb0ef41Sopenharmony_ci if (!item->queued && item != session->aob.item) { 14851cb0ef41Sopenharmony_ci nghttp2_outbound_item_free(item, mem); 14861cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, item); 14871cb0ef41Sopenharmony_ci } 14881cb0ef41Sopenharmony_ci } 14891cb0ef41Sopenharmony_ci 14901cb0ef41Sopenharmony_ci /* We call on_stream_close_callback even if stream->state is 14911cb0ef41Sopenharmony_ci NGHTTP2_STREAM_INITIAL. This will happen while sending request 14921cb0ef41Sopenharmony_ci HEADERS, a local endpoint receives RST_STREAM for that stream. It 14931cb0ef41Sopenharmony_ci may be PROTOCOL_ERROR, but without notifying stream closure will 14941cb0ef41Sopenharmony_ci hang the stream in a local endpoint. 14951cb0ef41Sopenharmony_ci */ 14961cb0ef41Sopenharmony_ci 14971cb0ef41Sopenharmony_ci if (session->callbacks.on_stream_close_callback) { 14981cb0ef41Sopenharmony_ci if (session->callbacks.on_stream_close_callback( 14991cb0ef41Sopenharmony_ci session, stream_id, error_code, session->user_data) != 0) { 15001cb0ef41Sopenharmony_ci 15011cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 15021cb0ef41Sopenharmony_ci } 15031cb0ef41Sopenharmony_ci } 15041cb0ef41Sopenharmony_ci 15051cb0ef41Sopenharmony_ci is_my_stream_id = nghttp2_session_is_my_stream_id(session, stream_id); 15061cb0ef41Sopenharmony_ci 15071cb0ef41Sopenharmony_ci /* pushed streams which is not opened yet is not counted toward max 15081cb0ef41Sopenharmony_ci concurrent limits */ 15091cb0ef41Sopenharmony_ci if ((stream->flags & NGHTTP2_STREAM_FLAG_PUSH)) { 15101cb0ef41Sopenharmony_ci if (!is_my_stream_id) { 15111cb0ef41Sopenharmony_ci --session->num_incoming_reserved_streams; 15121cb0ef41Sopenharmony_ci } 15131cb0ef41Sopenharmony_ci } else { 15141cb0ef41Sopenharmony_ci if (is_my_stream_id) { 15151cb0ef41Sopenharmony_ci --session->num_outgoing_streams; 15161cb0ef41Sopenharmony_ci } else { 15171cb0ef41Sopenharmony_ci --session->num_incoming_streams; 15181cb0ef41Sopenharmony_ci } 15191cb0ef41Sopenharmony_ci } 15201cb0ef41Sopenharmony_ci 15211cb0ef41Sopenharmony_ci /* Closes both directions just in case they are not closed yet */ 15221cb0ef41Sopenharmony_ci stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED; 15231cb0ef41Sopenharmony_ci 15241cb0ef41Sopenharmony_ci if (session->pending_no_rfc7540_priorities == 1) { 15251cb0ef41Sopenharmony_ci return nghttp2_session_destroy_stream(session, stream); 15261cb0ef41Sopenharmony_ci } 15271cb0ef41Sopenharmony_ci 15281cb0ef41Sopenharmony_ci if ((session->opt_flags & NGHTTP2_OPTMASK_NO_CLOSED_STREAMS) == 0 && 15291cb0ef41Sopenharmony_ci session->server && !is_my_stream_id && 15301cb0ef41Sopenharmony_ci nghttp2_stream_in_dep_tree(stream)) { 15311cb0ef41Sopenharmony_ci /* On server side, retain stream at most MAX_CONCURRENT_STREAMS 15321cb0ef41Sopenharmony_ci combined with the current active incoming streams to make 15331cb0ef41Sopenharmony_ci dependency tree work better. */ 15341cb0ef41Sopenharmony_ci nghttp2_session_keep_closed_stream(session, stream); 15351cb0ef41Sopenharmony_ci } else { 15361cb0ef41Sopenharmony_ci rv = nghttp2_session_destroy_stream(session, stream); 15371cb0ef41Sopenharmony_ci if (rv != 0) { 15381cb0ef41Sopenharmony_ci return rv; 15391cb0ef41Sopenharmony_ci } 15401cb0ef41Sopenharmony_ci } 15411cb0ef41Sopenharmony_ci 15421cb0ef41Sopenharmony_ci return 0; 15431cb0ef41Sopenharmony_ci} 15441cb0ef41Sopenharmony_ci 15451cb0ef41Sopenharmony_ciint nghttp2_session_destroy_stream(nghttp2_session *session, 15461cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 15471cb0ef41Sopenharmony_ci nghttp2_mem *mem; 15481cb0ef41Sopenharmony_ci int rv; 15491cb0ef41Sopenharmony_ci 15501cb0ef41Sopenharmony_ci DEBUGF("stream: destroy closed stream(%p)=%d\n", stream, stream->stream_id); 15511cb0ef41Sopenharmony_ci 15521cb0ef41Sopenharmony_ci mem = &session->mem; 15531cb0ef41Sopenharmony_ci 15541cb0ef41Sopenharmony_ci if (nghttp2_stream_in_dep_tree(stream)) { 15551cb0ef41Sopenharmony_ci rv = nghttp2_stream_dep_remove(stream); 15561cb0ef41Sopenharmony_ci if (rv != 0) { 15571cb0ef41Sopenharmony_ci return rv; 15581cb0ef41Sopenharmony_ci } 15591cb0ef41Sopenharmony_ci } 15601cb0ef41Sopenharmony_ci 15611cb0ef41Sopenharmony_ci nghttp2_map_remove(&session->streams, stream->stream_id); 15621cb0ef41Sopenharmony_ci nghttp2_stream_free(stream); 15631cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, stream); 15641cb0ef41Sopenharmony_ci 15651cb0ef41Sopenharmony_ci return 0; 15661cb0ef41Sopenharmony_ci} 15671cb0ef41Sopenharmony_ci 15681cb0ef41Sopenharmony_civoid nghttp2_session_keep_closed_stream(nghttp2_session *session, 15691cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 15701cb0ef41Sopenharmony_ci DEBUGF("stream: keep closed stream(%p)=%d, state=%d\n", stream, 15711cb0ef41Sopenharmony_ci stream->stream_id, stream->state); 15721cb0ef41Sopenharmony_ci 15731cb0ef41Sopenharmony_ci if (session->closed_stream_tail) { 15741cb0ef41Sopenharmony_ci session->closed_stream_tail->closed_next = stream; 15751cb0ef41Sopenharmony_ci stream->closed_prev = session->closed_stream_tail; 15761cb0ef41Sopenharmony_ci } else { 15771cb0ef41Sopenharmony_ci session->closed_stream_head = stream; 15781cb0ef41Sopenharmony_ci } 15791cb0ef41Sopenharmony_ci session->closed_stream_tail = stream; 15801cb0ef41Sopenharmony_ci 15811cb0ef41Sopenharmony_ci ++session->num_closed_streams; 15821cb0ef41Sopenharmony_ci} 15831cb0ef41Sopenharmony_ci 15841cb0ef41Sopenharmony_civoid nghttp2_session_keep_idle_stream(nghttp2_session *session, 15851cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 15861cb0ef41Sopenharmony_ci DEBUGF("stream: keep idle stream(%p)=%d, state=%d\n", stream, 15871cb0ef41Sopenharmony_ci stream->stream_id, stream->state); 15881cb0ef41Sopenharmony_ci 15891cb0ef41Sopenharmony_ci if (session->idle_stream_tail) { 15901cb0ef41Sopenharmony_ci session->idle_stream_tail->closed_next = stream; 15911cb0ef41Sopenharmony_ci stream->closed_prev = session->idle_stream_tail; 15921cb0ef41Sopenharmony_ci } else { 15931cb0ef41Sopenharmony_ci session->idle_stream_head = stream; 15941cb0ef41Sopenharmony_ci } 15951cb0ef41Sopenharmony_ci session->idle_stream_tail = stream; 15961cb0ef41Sopenharmony_ci 15971cb0ef41Sopenharmony_ci ++session->num_idle_streams; 15981cb0ef41Sopenharmony_ci} 15991cb0ef41Sopenharmony_ci 16001cb0ef41Sopenharmony_civoid nghttp2_session_detach_idle_stream(nghttp2_session *session, 16011cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 16021cb0ef41Sopenharmony_ci nghttp2_stream *prev_stream, *next_stream; 16031cb0ef41Sopenharmony_ci 16041cb0ef41Sopenharmony_ci DEBUGF("stream: detach idle stream(%p)=%d, state=%d\n", stream, 16051cb0ef41Sopenharmony_ci stream->stream_id, stream->state); 16061cb0ef41Sopenharmony_ci 16071cb0ef41Sopenharmony_ci prev_stream = stream->closed_prev; 16081cb0ef41Sopenharmony_ci next_stream = stream->closed_next; 16091cb0ef41Sopenharmony_ci 16101cb0ef41Sopenharmony_ci if (prev_stream) { 16111cb0ef41Sopenharmony_ci prev_stream->closed_next = next_stream; 16121cb0ef41Sopenharmony_ci } else { 16131cb0ef41Sopenharmony_ci session->idle_stream_head = next_stream; 16141cb0ef41Sopenharmony_ci } 16151cb0ef41Sopenharmony_ci 16161cb0ef41Sopenharmony_ci if (next_stream) { 16171cb0ef41Sopenharmony_ci next_stream->closed_prev = prev_stream; 16181cb0ef41Sopenharmony_ci } else { 16191cb0ef41Sopenharmony_ci session->idle_stream_tail = prev_stream; 16201cb0ef41Sopenharmony_ci } 16211cb0ef41Sopenharmony_ci 16221cb0ef41Sopenharmony_ci stream->closed_prev = NULL; 16231cb0ef41Sopenharmony_ci stream->closed_next = NULL; 16241cb0ef41Sopenharmony_ci 16251cb0ef41Sopenharmony_ci --session->num_idle_streams; 16261cb0ef41Sopenharmony_ci} 16271cb0ef41Sopenharmony_ci 16281cb0ef41Sopenharmony_ciint nghttp2_session_adjust_closed_stream(nghttp2_session *session) { 16291cb0ef41Sopenharmony_ci size_t num_stream_max; 16301cb0ef41Sopenharmony_ci int rv; 16311cb0ef41Sopenharmony_ci 16321cb0ef41Sopenharmony_ci if (session->local_settings.max_concurrent_streams == 16331cb0ef41Sopenharmony_ci NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS) { 16341cb0ef41Sopenharmony_ci num_stream_max = session->pending_local_max_concurrent_stream; 16351cb0ef41Sopenharmony_ci } else { 16361cb0ef41Sopenharmony_ci num_stream_max = session->local_settings.max_concurrent_streams; 16371cb0ef41Sopenharmony_ci } 16381cb0ef41Sopenharmony_ci 16391cb0ef41Sopenharmony_ci DEBUGF("stream: adjusting kept closed streams num_closed_streams=%zu, " 16401cb0ef41Sopenharmony_ci "num_incoming_streams=%zu, max_concurrent_streams=%zu\n", 16411cb0ef41Sopenharmony_ci session->num_closed_streams, session->num_incoming_streams, 16421cb0ef41Sopenharmony_ci num_stream_max); 16431cb0ef41Sopenharmony_ci 16441cb0ef41Sopenharmony_ci while (session->num_closed_streams > 0 && 16451cb0ef41Sopenharmony_ci session->num_closed_streams + session->num_incoming_streams > 16461cb0ef41Sopenharmony_ci num_stream_max) { 16471cb0ef41Sopenharmony_ci nghttp2_stream *head_stream; 16481cb0ef41Sopenharmony_ci nghttp2_stream *next; 16491cb0ef41Sopenharmony_ci 16501cb0ef41Sopenharmony_ci head_stream = session->closed_stream_head; 16511cb0ef41Sopenharmony_ci 16521cb0ef41Sopenharmony_ci assert(head_stream); 16531cb0ef41Sopenharmony_ci 16541cb0ef41Sopenharmony_ci next = head_stream->closed_next; 16551cb0ef41Sopenharmony_ci 16561cb0ef41Sopenharmony_ci rv = nghttp2_session_destroy_stream(session, head_stream); 16571cb0ef41Sopenharmony_ci if (rv != 0) { 16581cb0ef41Sopenharmony_ci return rv; 16591cb0ef41Sopenharmony_ci } 16601cb0ef41Sopenharmony_ci 16611cb0ef41Sopenharmony_ci /* head_stream is now freed */ 16621cb0ef41Sopenharmony_ci 16631cb0ef41Sopenharmony_ci session->closed_stream_head = next; 16641cb0ef41Sopenharmony_ci 16651cb0ef41Sopenharmony_ci if (session->closed_stream_head) { 16661cb0ef41Sopenharmony_ci session->closed_stream_head->closed_prev = NULL; 16671cb0ef41Sopenharmony_ci } else { 16681cb0ef41Sopenharmony_ci session->closed_stream_tail = NULL; 16691cb0ef41Sopenharmony_ci } 16701cb0ef41Sopenharmony_ci 16711cb0ef41Sopenharmony_ci --session->num_closed_streams; 16721cb0ef41Sopenharmony_ci } 16731cb0ef41Sopenharmony_ci 16741cb0ef41Sopenharmony_ci return 0; 16751cb0ef41Sopenharmony_ci} 16761cb0ef41Sopenharmony_ci 16771cb0ef41Sopenharmony_ciint nghttp2_session_adjust_idle_stream(nghttp2_session *session) { 16781cb0ef41Sopenharmony_ci size_t max; 16791cb0ef41Sopenharmony_ci int rv; 16801cb0ef41Sopenharmony_ci 16811cb0ef41Sopenharmony_ci /* Make minimum number of idle streams 16, and maximum 100, which 16821cb0ef41Sopenharmony_ci are arbitrary chosen numbers. */ 16831cb0ef41Sopenharmony_ci max = nghttp2_min( 16841cb0ef41Sopenharmony_ci 100, nghttp2_max( 16851cb0ef41Sopenharmony_ci 16, nghttp2_min(session->local_settings.max_concurrent_streams, 16861cb0ef41Sopenharmony_ci session->pending_local_max_concurrent_stream))); 16871cb0ef41Sopenharmony_ci 16881cb0ef41Sopenharmony_ci DEBUGF("stream: adjusting kept idle streams num_idle_streams=%zu, max=%zu\n", 16891cb0ef41Sopenharmony_ci session->num_idle_streams, max); 16901cb0ef41Sopenharmony_ci 16911cb0ef41Sopenharmony_ci while (session->num_idle_streams > max) { 16921cb0ef41Sopenharmony_ci nghttp2_stream *head; 16931cb0ef41Sopenharmony_ci nghttp2_stream *next; 16941cb0ef41Sopenharmony_ci 16951cb0ef41Sopenharmony_ci head = session->idle_stream_head; 16961cb0ef41Sopenharmony_ci assert(head); 16971cb0ef41Sopenharmony_ci 16981cb0ef41Sopenharmony_ci next = head->closed_next; 16991cb0ef41Sopenharmony_ci 17001cb0ef41Sopenharmony_ci rv = nghttp2_session_destroy_stream(session, head); 17011cb0ef41Sopenharmony_ci if (rv != 0) { 17021cb0ef41Sopenharmony_ci return rv; 17031cb0ef41Sopenharmony_ci } 17041cb0ef41Sopenharmony_ci 17051cb0ef41Sopenharmony_ci /* head is now destroyed */ 17061cb0ef41Sopenharmony_ci 17071cb0ef41Sopenharmony_ci session->idle_stream_head = next; 17081cb0ef41Sopenharmony_ci 17091cb0ef41Sopenharmony_ci if (session->idle_stream_head) { 17101cb0ef41Sopenharmony_ci session->idle_stream_head->closed_prev = NULL; 17111cb0ef41Sopenharmony_ci } else { 17121cb0ef41Sopenharmony_ci session->idle_stream_tail = NULL; 17131cb0ef41Sopenharmony_ci } 17141cb0ef41Sopenharmony_ci 17151cb0ef41Sopenharmony_ci --session->num_idle_streams; 17161cb0ef41Sopenharmony_ci } 17171cb0ef41Sopenharmony_ci 17181cb0ef41Sopenharmony_ci return 0; 17191cb0ef41Sopenharmony_ci} 17201cb0ef41Sopenharmony_ci 17211cb0ef41Sopenharmony_ci/* 17221cb0ef41Sopenharmony_ci * Closes stream with stream ID |stream_id| if both transmission and 17231cb0ef41Sopenharmony_ci * reception of the stream were disallowed. The |error_code| indicates 17241cb0ef41Sopenharmony_ci * the reason of the closure. 17251cb0ef41Sopenharmony_ci * 17261cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 17271cb0ef41Sopenharmony_ci * negative error codes: 17281cb0ef41Sopenharmony_ci * 17291cb0ef41Sopenharmony_ci * NGHTTP2_ERR_INVALID_ARGUMENT 17301cb0ef41Sopenharmony_ci * The stream is not found. 17311cb0ef41Sopenharmony_ci * NGHTTP2_ERR_CALLBACK_FAILURE 17321cb0ef41Sopenharmony_ci * The callback function failed. 17331cb0ef41Sopenharmony_ci */ 17341cb0ef41Sopenharmony_ciint nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session, 17351cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 17361cb0ef41Sopenharmony_ci if ((stream->shut_flags & NGHTTP2_SHUT_RDWR) == NGHTTP2_SHUT_RDWR) { 17371cb0ef41Sopenharmony_ci return nghttp2_session_close_stream(session, stream->stream_id, 17381cb0ef41Sopenharmony_ci NGHTTP2_NO_ERROR); 17391cb0ef41Sopenharmony_ci } 17401cb0ef41Sopenharmony_ci return 0; 17411cb0ef41Sopenharmony_ci} 17421cb0ef41Sopenharmony_ci 17431cb0ef41Sopenharmony_ci/* 17441cb0ef41Sopenharmony_ci * Returns nonzero if local endpoint allows reception of new stream 17451cb0ef41Sopenharmony_ci * from remote. 17461cb0ef41Sopenharmony_ci */ 17471cb0ef41Sopenharmony_cistatic int session_allow_incoming_new_stream(nghttp2_session *session) { 17481cb0ef41Sopenharmony_ci return (session->goaway_flags & 17491cb0ef41Sopenharmony_ci (NGHTTP2_GOAWAY_TERM_ON_SEND | NGHTTP2_GOAWAY_SENT)) == 0; 17501cb0ef41Sopenharmony_ci} 17511cb0ef41Sopenharmony_ci 17521cb0ef41Sopenharmony_ci/* 17531cb0ef41Sopenharmony_ci * This function returns nonzero if session is closing. 17541cb0ef41Sopenharmony_ci */ 17551cb0ef41Sopenharmony_cistatic int session_is_closing(nghttp2_session *session) { 17561cb0ef41Sopenharmony_ci return (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) != 0 || 17571cb0ef41Sopenharmony_ci (nghttp2_session_want_read(session) == 0 && 17581cb0ef41Sopenharmony_ci nghttp2_session_want_write(session) == 0); 17591cb0ef41Sopenharmony_ci} 17601cb0ef41Sopenharmony_ci 17611cb0ef41Sopenharmony_ci/* 17621cb0ef41Sopenharmony_ci * Check that we can send a frame to the |stream|. This function 17631cb0ef41Sopenharmony_ci * returns 0 if we can send a frame to the |frame|, or one of the 17641cb0ef41Sopenharmony_ci * following negative error codes: 17651cb0ef41Sopenharmony_ci * 17661cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSED 17671cb0ef41Sopenharmony_ci * The stream is already closed. 17681cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_SHUT_WR 17691cb0ef41Sopenharmony_ci * The stream is half-closed for transmission. 17701cb0ef41Sopenharmony_ci * NGHTTP2_ERR_SESSION_CLOSING 17711cb0ef41Sopenharmony_ci * This session is closing. 17721cb0ef41Sopenharmony_ci */ 17731cb0ef41Sopenharmony_cistatic int session_predicate_for_stream_send(nghttp2_session *session, 17741cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 17751cb0ef41Sopenharmony_ci if (stream == NULL) { 17761cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSED; 17771cb0ef41Sopenharmony_ci } 17781cb0ef41Sopenharmony_ci if (session_is_closing(session)) { 17791cb0ef41Sopenharmony_ci return NGHTTP2_ERR_SESSION_CLOSING; 17801cb0ef41Sopenharmony_ci } 17811cb0ef41Sopenharmony_ci if (stream->shut_flags & NGHTTP2_SHUT_WR) { 17821cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_SHUT_WR; 17831cb0ef41Sopenharmony_ci } 17841cb0ef41Sopenharmony_ci return 0; 17851cb0ef41Sopenharmony_ci} 17861cb0ef41Sopenharmony_ci 17871cb0ef41Sopenharmony_ciint nghttp2_session_check_request_allowed(nghttp2_session *session) { 17881cb0ef41Sopenharmony_ci return !session->server && session->next_stream_id <= INT32_MAX && 17891cb0ef41Sopenharmony_ci (session->goaway_flags & NGHTTP2_GOAWAY_RECV) == 0 && 17901cb0ef41Sopenharmony_ci !session_is_closing(session); 17911cb0ef41Sopenharmony_ci} 17921cb0ef41Sopenharmony_ci 17931cb0ef41Sopenharmony_ci/* 17941cb0ef41Sopenharmony_ci * This function checks request HEADERS frame, which opens stream, can 17951cb0ef41Sopenharmony_ci * be sent at this time. 17961cb0ef41Sopenharmony_ci * 17971cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 17981cb0ef41Sopenharmony_ci * negative error codes: 17991cb0ef41Sopenharmony_ci * 18001cb0ef41Sopenharmony_ci * NGHTTP2_ERR_START_STREAM_NOT_ALLOWED 18011cb0ef41Sopenharmony_ci * New stream cannot be created because of GOAWAY: session is 18021cb0ef41Sopenharmony_ci * going down or received last_stream_id is strictly less than 18031cb0ef41Sopenharmony_ci * frame->hd.stream_id. 18041cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSING 18051cb0ef41Sopenharmony_ci * request HEADERS was canceled by RST_STREAM while it is in queue. 18061cb0ef41Sopenharmony_ci */ 18071cb0ef41Sopenharmony_cistatic int session_predicate_request_headers_send(nghttp2_session *session, 18081cb0ef41Sopenharmony_ci nghttp2_outbound_item *item) { 18091cb0ef41Sopenharmony_ci if (item->aux_data.headers.canceled) { 18101cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSING; 18111cb0ef41Sopenharmony_ci } 18121cb0ef41Sopenharmony_ci /* If we are terminating session (NGHTTP2_GOAWAY_TERM_ON_SEND), 18131cb0ef41Sopenharmony_ci GOAWAY was received from peer, or session is about to close, new 18141cb0ef41Sopenharmony_ci request is not allowed. */ 18151cb0ef41Sopenharmony_ci if ((session->goaway_flags & NGHTTP2_GOAWAY_RECV) || 18161cb0ef41Sopenharmony_ci session_is_closing(session)) { 18171cb0ef41Sopenharmony_ci return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED; 18181cb0ef41Sopenharmony_ci } 18191cb0ef41Sopenharmony_ci return 0; 18201cb0ef41Sopenharmony_ci} 18211cb0ef41Sopenharmony_ci 18221cb0ef41Sopenharmony_ci/* 18231cb0ef41Sopenharmony_ci * This function checks HEADERS, which is the first frame from the 18241cb0ef41Sopenharmony_ci * server, with the |stream| can be sent at this time. The |stream| 18251cb0ef41Sopenharmony_ci * can be NULL. 18261cb0ef41Sopenharmony_ci * 18271cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 18281cb0ef41Sopenharmony_ci * negative error codes: 18291cb0ef41Sopenharmony_ci * 18301cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSED 18311cb0ef41Sopenharmony_ci * The stream is already closed or does not exist. 18321cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_SHUT_WR 18331cb0ef41Sopenharmony_ci * The transmission is not allowed for this stream (e.g., a frame 18341cb0ef41Sopenharmony_ci * with END_STREAM flag set has already sent) 18351cb0ef41Sopenharmony_ci * NGHTTP2_ERR_INVALID_STREAM_ID 18361cb0ef41Sopenharmony_ci * The stream ID is invalid. 18371cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSING 18381cb0ef41Sopenharmony_ci * RST_STREAM was queued for this stream. 18391cb0ef41Sopenharmony_ci * NGHTTP2_ERR_INVALID_STREAM_STATE 18401cb0ef41Sopenharmony_ci * The state of the stream is not valid. 18411cb0ef41Sopenharmony_ci * NGHTTP2_ERR_SESSION_CLOSING 18421cb0ef41Sopenharmony_ci * This session is closing. 18431cb0ef41Sopenharmony_ci * NGHTTP2_ERR_PROTO 18441cb0ef41Sopenharmony_ci * Client side attempted to send response. 18451cb0ef41Sopenharmony_ci */ 18461cb0ef41Sopenharmony_cistatic int session_predicate_response_headers_send(nghttp2_session *session, 18471cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 18481cb0ef41Sopenharmony_ci int rv; 18491cb0ef41Sopenharmony_ci rv = session_predicate_for_stream_send(session, stream); 18501cb0ef41Sopenharmony_ci if (rv != 0) { 18511cb0ef41Sopenharmony_ci return rv; 18521cb0ef41Sopenharmony_ci } 18531cb0ef41Sopenharmony_ci assert(stream); 18541cb0ef41Sopenharmony_ci if (!session->server) { 18551cb0ef41Sopenharmony_ci return NGHTTP2_ERR_PROTO; 18561cb0ef41Sopenharmony_ci } 18571cb0ef41Sopenharmony_ci if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { 18581cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_STREAM_ID; 18591cb0ef41Sopenharmony_ci } 18601cb0ef41Sopenharmony_ci switch (stream->state) { 18611cb0ef41Sopenharmony_ci case NGHTTP2_STREAM_OPENING: 18621cb0ef41Sopenharmony_ci return 0; 18631cb0ef41Sopenharmony_ci case NGHTTP2_STREAM_CLOSING: 18641cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSING; 18651cb0ef41Sopenharmony_ci default: 18661cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_STREAM_STATE; 18671cb0ef41Sopenharmony_ci } 18681cb0ef41Sopenharmony_ci} 18691cb0ef41Sopenharmony_ci 18701cb0ef41Sopenharmony_ci/* 18711cb0ef41Sopenharmony_ci * This function checks HEADERS for reserved stream can be sent. The 18721cb0ef41Sopenharmony_ci * |stream| must be reserved state and the |session| is server side. 18731cb0ef41Sopenharmony_ci * The |stream| can be NULL. 18741cb0ef41Sopenharmony_ci * 18751cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 18761cb0ef41Sopenharmony_ci * error codes: 18771cb0ef41Sopenharmony_ci * 18781cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSED 18791cb0ef41Sopenharmony_ci * The stream is already closed. 18801cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_SHUT_WR 18811cb0ef41Sopenharmony_ci * The stream is half-closed for transmission. 18821cb0ef41Sopenharmony_ci * NGHTTP2_ERR_PROTO 18831cb0ef41Sopenharmony_ci * The stream is not reserved state 18841cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSED 18851cb0ef41Sopenharmony_ci * RST_STREAM was queued for this stream. 18861cb0ef41Sopenharmony_ci * NGHTTP2_ERR_SESSION_CLOSING 18871cb0ef41Sopenharmony_ci * This session is closing. 18881cb0ef41Sopenharmony_ci * NGHTTP2_ERR_START_STREAM_NOT_ALLOWED 18891cb0ef41Sopenharmony_ci * New stream cannot be created because GOAWAY is already sent or 18901cb0ef41Sopenharmony_ci * received. 18911cb0ef41Sopenharmony_ci * NGHTTP2_ERR_PROTO 18921cb0ef41Sopenharmony_ci * Client side attempted to send push response. 18931cb0ef41Sopenharmony_ci */ 18941cb0ef41Sopenharmony_cistatic int 18951cb0ef41Sopenharmony_cisession_predicate_push_response_headers_send(nghttp2_session *session, 18961cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 18971cb0ef41Sopenharmony_ci int rv; 18981cb0ef41Sopenharmony_ci /* TODO Should disallow HEADERS if GOAWAY has already been issued? */ 18991cb0ef41Sopenharmony_ci rv = session_predicate_for_stream_send(session, stream); 19001cb0ef41Sopenharmony_ci if (rv != 0) { 19011cb0ef41Sopenharmony_ci return rv; 19021cb0ef41Sopenharmony_ci } 19031cb0ef41Sopenharmony_ci assert(stream); 19041cb0ef41Sopenharmony_ci if (!session->server) { 19051cb0ef41Sopenharmony_ci return NGHTTP2_ERR_PROTO; 19061cb0ef41Sopenharmony_ci } 19071cb0ef41Sopenharmony_ci if (stream->state != NGHTTP2_STREAM_RESERVED) { 19081cb0ef41Sopenharmony_ci return NGHTTP2_ERR_PROTO; 19091cb0ef41Sopenharmony_ci } 19101cb0ef41Sopenharmony_ci if (session->goaway_flags & NGHTTP2_GOAWAY_RECV) { 19111cb0ef41Sopenharmony_ci return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED; 19121cb0ef41Sopenharmony_ci } 19131cb0ef41Sopenharmony_ci return 0; 19141cb0ef41Sopenharmony_ci} 19151cb0ef41Sopenharmony_ci 19161cb0ef41Sopenharmony_ci/* 19171cb0ef41Sopenharmony_ci * This function checks HEADERS, which is neither stream-opening nor 19181cb0ef41Sopenharmony_ci * first response header, with the |stream| can be sent at this time. 19191cb0ef41Sopenharmony_ci * The |stream| can be NULL. 19201cb0ef41Sopenharmony_ci * 19211cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 19221cb0ef41Sopenharmony_ci * negative error codes: 19231cb0ef41Sopenharmony_ci * 19241cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSED 19251cb0ef41Sopenharmony_ci * The stream is already closed or does not exist. 19261cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_SHUT_WR 19271cb0ef41Sopenharmony_ci * The transmission is not allowed for this stream (e.g., a frame 19281cb0ef41Sopenharmony_ci * with END_STREAM flag set has already sent) 19291cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSING 19301cb0ef41Sopenharmony_ci * RST_STREAM was queued for this stream. 19311cb0ef41Sopenharmony_ci * NGHTTP2_ERR_INVALID_STREAM_STATE 19321cb0ef41Sopenharmony_ci * The state of the stream is not valid. 19331cb0ef41Sopenharmony_ci * NGHTTP2_ERR_SESSION_CLOSING 19341cb0ef41Sopenharmony_ci * This session is closing. 19351cb0ef41Sopenharmony_ci */ 19361cb0ef41Sopenharmony_cistatic int session_predicate_headers_send(nghttp2_session *session, 19371cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 19381cb0ef41Sopenharmony_ci int rv; 19391cb0ef41Sopenharmony_ci rv = session_predicate_for_stream_send(session, stream); 19401cb0ef41Sopenharmony_ci if (rv != 0) { 19411cb0ef41Sopenharmony_ci return rv; 19421cb0ef41Sopenharmony_ci } 19431cb0ef41Sopenharmony_ci assert(stream); 19441cb0ef41Sopenharmony_ci 19451cb0ef41Sopenharmony_ci switch (stream->state) { 19461cb0ef41Sopenharmony_ci case NGHTTP2_STREAM_OPENED: 19471cb0ef41Sopenharmony_ci return 0; 19481cb0ef41Sopenharmony_ci case NGHTTP2_STREAM_CLOSING: 19491cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSING; 19501cb0ef41Sopenharmony_ci default: 19511cb0ef41Sopenharmony_ci if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { 19521cb0ef41Sopenharmony_ci return 0; 19531cb0ef41Sopenharmony_ci } 19541cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_STREAM_STATE; 19551cb0ef41Sopenharmony_ci } 19561cb0ef41Sopenharmony_ci} 19571cb0ef41Sopenharmony_ci 19581cb0ef41Sopenharmony_ci/* 19591cb0ef41Sopenharmony_ci * This function checks PUSH_PROMISE frame |frame| with the |stream| 19601cb0ef41Sopenharmony_ci * can be sent at this time. The |stream| can be NULL. 19611cb0ef41Sopenharmony_ci * 19621cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 19631cb0ef41Sopenharmony_ci * negative error codes: 19641cb0ef41Sopenharmony_ci * 19651cb0ef41Sopenharmony_ci * NGHTTP2_ERR_START_STREAM_NOT_ALLOWED 19661cb0ef41Sopenharmony_ci * New stream cannot be created because GOAWAY is already sent or 19671cb0ef41Sopenharmony_ci * received. 19681cb0ef41Sopenharmony_ci * NGHTTP2_ERR_PROTO 19691cb0ef41Sopenharmony_ci * The client side attempts to send PUSH_PROMISE, or the server 19701cb0ef41Sopenharmony_ci * sends PUSH_PROMISE for the stream not initiated by the client. 19711cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSED 19721cb0ef41Sopenharmony_ci * The stream is already closed or does not exist. 19731cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSING 19741cb0ef41Sopenharmony_ci * RST_STREAM was queued for this stream. 19751cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_SHUT_WR 19761cb0ef41Sopenharmony_ci * The transmission is not allowed for this stream (e.g., a frame 19771cb0ef41Sopenharmony_ci * with END_STREAM flag set has already sent) 19781cb0ef41Sopenharmony_ci * NGHTTP2_ERR_PUSH_DISABLED 19791cb0ef41Sopenharmony_ci * The remote peer disabled reception of PUSH_PROMISE. 19801cb0ef41Sopenharmony_ci * NGHTTP2_ERR_SESSION_CLOSING 19811cb0ef41Sopenharmony_ci * This session is closing. 19821cb0ef41Sopenharmony_ci */ 19831cb0ef41Sopenharmony_cistatic int session_predicate_push_promise_send(nghttp2_session *session, 19841cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 19851cb0ef41Sopenharmony_ci int rv; 19861cb0ef41Sopenharmony_ci 19871cb0ef41Sopenharmony_ci if (!session->server) { 19881cb0ef41Sopenharmony_ci return NGHTTP2_ERR_PROTO; 19891cb0ef41Sopenharmony_ci } 19901cb0ef41Sopenharmony_ci 19911cb0ef41Sopenharmony_ci rv = session_predicate_for_stream_send(session, stream); 19921cb0ef41Sopenharmony_ci if (rv != 0) { 19931cb0ef41Sopenharmony_ci return rv; 19941cb0ef41Sopenharmony_ci } 19951cb0ef41Sopenharmony_ci 19961cb0ef41Sopenharmony_ci assert(stream); 19971cb0ef41Sopenharmony_ci 19981cb0ef41Sopenharmony_ci if (session->remote_settings.enable_push == 0) { 19991cb0ef41Sopenharmony_ci return NGHTTP2_ERR_PUSH_DISABLED; 20001cb0ef41Sopenharmony_ci } 20011cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_CLOSING) { 20021cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSING; 20031cb0ef41Sopenharmony_ci } 20041cb0ef41Sopenharmony_ci if (session->goaway_flags & NGHTTP2_GOAWAY_RECV) { 20051cb0ef41Sopenharmony_ci return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED; 20061cb0ef41Sopenharmony_ci } 20071cb0ef41Sopenharmony_ci return 0; 20081cb0ef41Sopenharmony_ci} 20091cb0ef41Sopenharmony_ci 20101cb0ef41Sopenharmony_ci/* 20111cb0ef41Sopenharmony_ci * This function checks WINDOW_UPDATE with the stream ID |stream_id| 20121cb0ef41Sopenharmony_ci * can be sent at this time. Note that END_STREAM flag of the previous 20131cb0ef41Sopenharmony_ci * frame does not affect the transmission of the WINDOW_UPDATE frame. 20141cb0ef41Sopenharmony_ci * 20151cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 20161cb0ef41Sopenharmony_ci * negative error codes: 20171cb0ef41Sopenharmony_ci * 20181cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSED 20191cb0ef41Sopenharmony_ci * The stream is already closed or does not exist. 20201cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSING 20211cb0ef41Sopenharmony_ci * RST_STREAM was queued for this stream. 20221cb0ef41Sopenharmony_ci * NGHTTP2_ERR_INVALID_STREAM_STATE 20231cb0ef41Sopenharmony_ci * The state of the stream is not valid. 20241cb0ef41Sopenharmony_ci * NGHTTP2_ERR_SESSION_CLOSING 20251cb0ef41Sopenharmony_ci * This session is closing. 20261cb0ef41Sopenharmony_ci */ 20271cb0ef41Sopenharmony_cistatic int session_predicate_window_update_send(nghttp2_session *session, 20281cb0ef41Sopenharmony_ci int32_t stream_id) { 20291cb0ef41Sopenharmony_ci nghttp2_stream *stream; 20301cb0ef41Sopenharmony_ci 20311cb0ef41Sopenharmony_ci if (session_is_closing(session)) { 20321cb0ef41Sopenharmony_ci return NGHTTP2_ERR_SESSION_CLOSING; 20331cb0ef41Sopenharmony_ci } 20341cb0ef41Sopenharmony_ci 20351cb0ef41Sopenharmony_ci if (stream_id == 0) { 20361cb0ef41Sopenharmony_ci /* Connection-level window update */ 20371cb0ef41Sopenharmony_ci return 0; 20381cb0ef41Sopenharmony_ci } 20391cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 20401cb0ef41Sopenharmony_ci if (stream == NULL) { 20411cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSED; 20421cb0ef41Sopenharmony_ci } 20431cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_CLOSING) { 20441cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSING; 20451cb0ef41Sopenharmony_ci } 20461cb0ef41Sopenharmony_ci if (state_reserved_local(session, stream)) { 20471cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_STREAM_STATE; 20481cb0ef41Sopenharmony_ci } 20491cb0ef41Sopenharmony_ci return 0; 20501cb0ef41Sopenharmony_ci} 20511cb0ef41Sopenharmony_ci 20521cb0ef41Sopenharmony_cistatic int session_predicate_altsvc_send(nghttp2_session *session, 20531cb0ef41Sopenharmony_ci int32_t stream_id) { 20541cb0ef41Sopenharmony_ci nghttp2_stream *stream; 20551cb0ef41Sopenharmony_ci 20561cb0ef41Sopenharmony_ci if (session_is_closing(session)) { 20571cb0ef41Sopenharmony_ci return NGHTTP2_ERR_SESSION_CLOSING; 20581cb0ef41Sopenharmony_ci } 20591cb0ef41Sopenharmony_ci 20601cb0ef41Sopenharmony_ci if (stream_id == 0) { 20611cb0ef41Sopenharmony_ci return 0; 20621cb0ef41Sopenharmony_ci } 20631cb0ef41Sopenharmony_ci 20641cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 20651cb0ef41Sopenharmony_ci if (stream == NULL) { 20661cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSED; 20671cb0ef41Sopenharmony_ci } 20681cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_CLOSING) { 20691cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSING; 20701cb0ef41Sopenharmony_ci } 20711cb0ef41Sopenharmony_ci 20721cb0ef41Sopenharmony_ci return 0; 20731cb0ef41Sopenharmony_ci} 20741cb0ef41Sopenharmony_ci 20751cb0ef41Sopenharmony_cistatic int session_predicate_origin_send(nghttp2_session *session) { 20761cb0ef41Sopenharmony_ci if (session_is_closing(session)) { 20771cb0ef41Sopenharmony_ci return NGHTTP2_ERR_SESSION_CLOSING; 20781cb0ef41Sopenharmony_ci } 20791cb0ef41Sopenharmony_ci return 0; 20801cb0ef41Sopenharmony_ci} 20811cb0ef41Sopenharmony_ci 20821cb0ef41Sopenharmony_cistatic int session_predicate_priority_update_send(nghttp2_session *session, 20831cb0ef41Sopenharmony_ci int32_t stream_id) { 20841cb0ef41Sopenharmony_ci nghttp2_stream *stream; 20851cb0ef41Sopenharmony_ci 20861cb0ef41Sopenharmony_ci if (session_is_closing(session)) { 20871cb0ef41Sopenharmony_ci return NGHTTP2_ERR_SESSION_CLOSING; 20881cb0ef41Sopenharmony_ci } 20891cb0ef41Sopenharmony_ci 20901cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 20911cb0ef41Sopenharmony_ci if (stream == NULL) { 20921cb0ef41Sopenharmony_ci return 0; 20931cb0ef41Sopenharmony_ci } 20941cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_CLOSING) { 20951cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSING; 20961cb0ef41Sopenharmony_ci } 20971cb0ef41Sopenharmony_ci if (stream->shut_flags & NGHTTP2_SHUT_RD) { 20981cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_STREAM_STATE; 20991cb0ef41Sopenharmony_ci } 21001cb0ef41Sopenharmony_ci 21011cb0ef41Sopenharmony_ci return 0; 21021cb0ef41Sopenharmony_ci} 21031cb0ef41Sopenharmony_ci 21041cb0ef41Sopenharmony_ci/* Take into account settings max frame size and both connection-level 21051cb0ef41Sopenharmony_ci flow control here */ 21061cb0ef41Sopenharmony_cistatic ssize_t 21071cb0ef41Sopenharmony_cinghttp2_session_enforce_flow_control_limits(nghttp2_session *session, 21081cb0ef41Sopenharmony_ci nghttp2_stream *stream, 21091cb0ef41Sopenharmony_ci ssize_t requested_window_size) { 21101cb0ef41Sopenharmony_ci DEBUGF("send: remote windowsize connection=%d, remote maxframsize=%u, " 21111cb0ef41Sopenharmony_ci "stream(id %d)=%d\n", 21121cb0ef41Sopenharmony_ci session->remote_window_size, session->remote_settings.max_frame_size, 21131cb0ef41Sopenharmony_ci stream->stream_id, stream->remote_window_size); 21141cb0ef41Sopenharmony_ci 21151cb0ef41Sopenharmony_ci return nghttp2_min(nghttp2_min(nghttp2_min(requested_window_size, 21161cb0ef41Sopenharmony_ci stream->remote_window_size), 21171cb0ef41Sopenharmony_ci session->remote_window_size), 21181cb0ef41Sopenharmony_ci (int32_t)session->remote_settings.max_frame_size); 21191cb0ef41Sopenharmony_ci} 21201cb0ef41Sopenharmony_ci 21211cb0ef41Sopenharmony_ci/* 21221cb0ef41Sopenharmony_ci * Returns the maximum length of next data read. If the 21231cb0ef41Sopenharmony_ci * connection-level and/or stream-wise flow control are enabled, the 21241cb0ef41Sopenharmony_ci * return value takes into account those current window sizes. The remote 21251cb0ef41Sopenharmony_ci * settings for max frame size is also taken into account. 21261cb0ef41Sopenharmony_ci */ 21271cb0ef41Sopenharmony_cistatic size_t nghttp2_session_next_data_read(nghttp2_session *session, 21281cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 21291cb0ef41Sopenharmony_ci ssize_t window_size; 21301cb0ef41Sopenharmony_ci 21311cb0ef41Sopenharmony_ci window_size = nghttp2_session_enforce_flow_control_limits( 21321cb0ef41Sopenharmony_ci session, stream, NGHTTP2_DATA_PAYLOADLEN); 21331cb0ef41Sopenharmony_ci 21341cb0ef41Sopenharmony_ci DEBUGF("send: available window=%zd\n", window_size); 21351cb0ef41Sopenharmony_ci 21361cb0ef41Sopenharmony_ci return window_size > 0 ? (size_t)window_size : 0; 21371cb0ef41Sopenharmony_ci} 21381cb0ef41Sopenharmony_ci 21391cb0ef41Sopenharmony_ci/* 21401cb0ef41Sopenharmony_ci * This function checks DATA with the |stream| can be sent at this 21411cb0ef41Sopenharmony_ci * time. The |stream| can be NULL. 21421cb0ef41Sopenharmony_ci * 21431cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 21441cb0ef41Sopenharmony_ci * negative error codes: 21451cb0ef41Sopenharmony_ci * 21461cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSED 21471cb0ef41Sopenharmony_ci * The stream is already closed or does not exist. 21481cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_SHUT_WR 21491cb0ef41Sopenharmony_ci * The transmission is not allowed for this stream (e.g., a frame 21501cb0ef41Sopenharmony_ci * with END_STREAM flag set has already sent) 21511cb0ef41Sopenharmony_ci * NGHTTP2_ERR_STREAM_CLOSING 21521cb0ef41Sopenharmony_ci * RST_STREAM was queued for this stream. 21531cb0ef41Sopenharmony_ci * NGHTTP2_ERR_INVALID_STREAM_STATE 21541cb0ef41Sopenharmony_ci * The state of the stream is not valid. 21551cb0ef41Sopenharmony_ci * NGHTTP2_ERR_SESSION_CLOSING 21561cb0ef41Sopenharmony_ci * This session is closing. 21571cb0ef41Sopenharmony_ci */ 21581cb0ef41Sopenharmony_cistatic int nghttp2_session_predicate_data_send(nghttp2_session *session, 21591cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 21601cb0ef41Sopenharmony_ci int rv; 21611cb0ef41Sopenharmony_ci rv = session_predicate_for_stream_send(session, stream); 21621cb0ef41Sopenharmony_ci if (rv != 0) { 21631cb0ef41Sopenharmony_ci return rv; 21641cb0ef41Sopenharmony_ci } 21651cb0ef41Sopenharmony_ci assert(stream); 21661cb0ef41Sopenharmony_ci if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { 21671cb0ef41Sopenharmony_ci /* Request body data */ 21681cb0ef41Sopenharmony_ci /* If stream->state is NGHTTP2_STREAM_CLOSING, RST_STREAM was 21691cb0ef41Sopenharmony_ci queued but not yet sent. In this case, we won't send DATA 21701cb0ef41Sopenharmony_ci frames. */ 21711cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_CLOSING) { 21721cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSING; 21731cb0ef41Sopenharmony_ci } 21741cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_RESERVED) { 21751cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_STREAM_STATE; 21761cb0ef41Sopenharmony_ci } 21771cb0ef41Sopenharmony_ci return 0; 21781cb0ef41Sopenharmony_ci } 21791cb0ef41Sopenharmony_ci /* Response body data */ 21801cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_OPENED) { 21811cb0ef41Sopenharmony_ci return 0; 21821cb0ef41Sopenharmony_ci } 21831cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_CLOSING) { 21841cb0ef41Sopenharmony_ci return NGHTTP2_ERR_STREAM_CLOSING; 21851cb0ef41Sopenharmony_ci } 21861cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_STREAM_STATE; 21871cb0ef41Sopenharmony_ci} 21881cb0ef41Sopenharmony_ci 21891cb0ef41Sopenharmony_cistatic ssize_t session_call_select_padding(nghttp2_session *session, 21901cb0ef41Sopenharmony_ci const nghttp2_frame *frame, 21911cb0ef41Sopenharmony_ci size_t max_payloadlen) { 21921cb0ef41Sopenharmony_ci ssize_t rv; 21931cb0ef41Sopenharmony_ci 21941cb0ef41Sopenharmony_ci if (frame->hd.length >= max_payloadlen) { 21951cb0ef41Sopenharmony_ci return (ssize_t)frame->hd.length; 21961cb0ef41Sopenharmony_ci } 21971cb0ef41Sopenharmony_ci 21981cb0ef41Sopenharmony_ci if (session->callbacks.select_padding_callback) { 21991cb0ef41Sopenharmony_ci size_t max_paddedlen; 22001cb0ef41Sopenharmony_ci 22011cb0ef41Sopenharmony_ci max_paddedlen = 22021cb0ef41Sopenharmony_ci nghttp2_min(frame->hd.length + NGHTTP2_MAX_PADLEN, max_payloadlen); 22031cb0ef41Sopenharmony_ci 22041cb0ef41Sopenharmony_ci rv = session->callbacks.select_padding_callback( 22051cb0ef41Sopenharmony_ci session, frame, max_paddedlen, session->user_data); 22061cb0ef41Sopenharmony_ci if (rv < (ssize_t)frame->hd.length || rv > (ssize_t)max_paddedlen) { 22071cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 22081cb0ef41Sopenharmony_ci } 22091cb0ef41Sopenharmony_ci return rv; 22101cb0ef41Sopenharmony_ci } 22111cb0ef41Sopenharmony_ci return (ssize_t)frame->hd.length; 22121cb0ef41Sopenharmony_ci} 22131cb0ef41Sopenharmony_ci 22141cb0ef41Sopenharmony_ci/* Add padding to HEADERS or PUSH_PROMISE. We use 22151cb0ef41Sopenharmony_ci frame->headers.padlen in this function to use the fact that 22161cb0ef41Sopenharmony_ci frame->push_promise has also padlen in the same position. */ 22171cb0ef41Sopenharmony_cistatic int session_headers_add_pad(nghttp2_session *session, 22181cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 22191cb0ef41Sopenharmony_ci ssize_t padded_payloadlen; 22201cb0ef41Sopenharmony_ci nghttp2_active_outbound_item *aob; 22211cb0ef41Sopenharmony_ci nghttp2_bufs *framebufs; 22221cb0ef41Sopenharmony_ci size_t padlen; 22231cb0ef41Sopenharmony_ci size_t max_payloadlen; 22241cb0ef41Sopenharmony_ci 22251cb0ef41Sopenharmony_ci aob = &session->aob; 22261cb0ef41Sopenharmony_ci framebufs = &aob->framebufs; 22271cb0ef41Sopenharmony_ci 22281cb0ef41Sopenharmony_ci max_payloadlen = nghttp2_min(NGHTTP2_MAX_PAYLOADLEN, 22291cb0ef41Sopenharmony_ci frame->hd.length + NGHTTP2_MAX_PADLEN); 22301cb0ef41Sopenharmony_ci 22311cb0ef41Sopenharmony_ci padded_payloadlen = 22321cb0ef41Sopenharmony_ci session_call_select_padding(session, frame, max_payloadlen); 22331cb0ef41Sopenharmony_ci 22341cb0ef41Sopenharmony_ci if (nghttp2_is_fatal((int)padded_payloadlen)) { 22351cb0ef41Sopenharmony_ci return (int)padded_payloadlen; 22361cb0ef41Sopenharmony_ci } 22371cb0ef41Sopenharmony_ci 22381cb0ef41Sopenharmony_ci padlen = (size_t)padded_payloadlen - frame->hd.length; 22391cb0ef41Sopenharmony_ci 22401cb0ef41Sopenharmony_ci DEBUGF("send: padding selected: payloadlen=%zd, padlen=%zu\n", 22411cb0ef41Sopenharmony_ci padded_payloadlen, padlen); 22421cb0ef41Sopenharmony_ci 22431cb0ef41Sopenharmony_ci nghttp2_frame_add_pad(framebufs, &frame->hd, padlen, 0); 22441cb0ef41Sopenharmony_ci 22451cb0ef41Sopenharmony_ci frame->headers.padlen = padlen; 22461cb0ef41Sopenharmony_ci 22471cb0ef41Sopenharmony_ci return 0; 22481cb0ef41Sopenharmony_ci} 22491cb0ef41Sopenharmony_ci 22501cb0ef41Sopenharmony_cistatic size_t session_estimate_headers_payload(nghttp2_session *session, 22511cb0ef41Sopenharmony_ci const nghttp2_nv *nva, 22521cb0ef41Sopenharmony_ci size_t nvlen, 22531cb0ef41Sopenharmony_ci size_t additional) { 22541cb0ef41Sopenharmony_ci return nghttp2_hd_deflate_bound(&session->hd_deflater, nva, nvlen) + 22551cb0ef41Sopenharmony_ci additional; 22561cb0ef41Sopenharmony_ci} 22571cb0ef41Sopenharmony_ci 22581cb0ef41Sopenharmony_cistatic int session_pack_extension(nghttp2_session *session, nghttp2_bufs *bufs, 22591cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 22601cb0ef41Sopenharmony_ci ssize_t rv; 22611cb0ef41Sopenharmony_ci nghttp2_buf *buf; 22621cb0ef41Sopenharmony_ci size_t buflen; 22631cb0ef41Sopenharmony_ci size_t framelen; 22641cb0ef41Sopenharmony_ci 22651cb0ef41Sopenharmony_ci assert(session->callbacks.pack_extension_callback); 22661cb0ef41Sopenharmony_ci 22671cb0ef41Sopenharmony_ci buf = &bufs->head->buf; 22681cb0ef41Sopenharmony_ci buflen = nghttp2_min(nghttp2_buf_avail(buf), NGHTTP2_MAX_PAYLOADLEN); 22691cb0ef41Sopenharmony_ci 22701cb0ef41Sopenharmony_ci rv = session->callbacks.pack_extension_callback(session, buf->last, buflen, 22711cb0ef41Sopenharmony_ci frame, session->user_data); 22721cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_CANCEL) { 22731cb0ef41Sopenharmony_ci return (int)rv; 22741cb0ef41Sopenharmony_ci } 22751cb0ef41Sopenharmony_ci 22761cb0ef41Sopenharmony_ci if (rv < 0 || (size_t)rv > buflen) { 22771cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 22781cb0ef41Sopenharmony_ci } 22791cb0ef41Sopenharmony_ci 22801cb0ef41Sopenharmony_ci framelen = (size_t)rv; 22811cb0ef41Sopenharmony_ci 22821cb0ef41Sopenharmony_ci frame->hd.length = framelen; 22831cb0ef41Sopenharmony_ci 22841cb0ef41Sopenharmony_ci assert(buf->pos == buf->last); 22851cb0ef41Sopenharmony_ci buf->last += framelen; 22861cb0ef41Sopenharmony_ci buf->pos -= NGHTTP2_FRAME_HDLEN; 22871cb0ef41Sopenharmony_ci 22881cb0ef41Sopenharmony_ci nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); 22891cb0ef41Sopenharmony_ci 22901cb0ef41Sopenharmony_ci return 0; 22911cb0ef41Sopenharmony_ci} 22921cb0ef41Sopenharmony_ci 22931cb0ef41Sopenharmony_ci/* 22941cb0ef41Sopenharmony_ci * This function serializes frame for transmission. 22951cb0ef41Sopenharmony_ci * 22961cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of negative error 22971cb0ef41Sopenharmony_ci * codes, including both fatal and non-fatal ones. 22981cb0ef41Sopenharmony_ci */ 22991cb0ef41Sopenharmony_cistatic int session_prep_frame(nghttp2_session *session, 23001cb0ef41Sopenharmony_ci nghttp2_outbound_item *item) { 23011cb0ef41Sopenharmony_ci int rv; 23021cb0ef41Sopenharmony_ci nghttp2_frame *frame; 23031cb0ef41Sopenharmony_ci nghttp2_mem *mem; 23041cb0ef41Sopenharmony_ci 23051cb0ef41Sopenharmony_ci mem = &session->mem; 23061cb0ef41Sopenharmony_ci frame = &item->frame; 23071cb0ef41Sopenharmony_ci 23081cb0ef41Sopenharmony_ci switch (frame->hd.type) { 23091cb0ef41Sopenharmony_ci case NGHTTP2_DATA: { 23101cb0ef41Sopenharmony_ci size_t next_readmax; 23111cb0ef41Sopenharmony_ci nghttp2_stream *stream; 23121cb0ef41Sopenharmony_ci 23131cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 23141cb0ef41Sopenharmony_ci 23151cb0ef41Sopenharmony_ci if (stream) { 23161cb0ef41Sopenharmony_ci assert(stream->item == item); 23171cb0ef41Sopenharmony_ci } 23181cb0ef41Sopenharmony_ci 23191cb0ef41Sopenharmony_ci rv = nghttp2_session_predicate_data_send(session, stream); 23201cb0ef41Sopenharmony_ci if (rv != 0) { 23211cb0ef41Sopenharmony_ci // If stream was already closed, nghttp2_session_get_stream() 23221cb0ef41Sopenharmony_ci // returns NULL, but item is still attached to the stream. 23231cb0ef41Sopenharmony_ci // Search stream including closed again. 23241cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); 23251cb0ef41Sopenharmony_ci if (stream) { 23261cb0ef41Sopenharmony_ci session_detach_stream_item(session, stream); 23271cb0ef41Sopenharmony_ci } 23281cb0ef41Sopenharmony_ci 23291cb0ef41Sopenharmony_ci return rv; 23301cb0ef41Sopenharmony_ci } 23311cb0ef41Sopenharmony_ci /* Assuming stream is not NULL */ 23321cb0ef41Sopenharmony_ci assert(stream); 23331cb0ef41Sopenharmony_ci next_readmax = nghttp2_session_next_data_read(session, stream); 23341cb0ef41Sopenharmony_ci 23351cb0ef41Sopenharmony_ci if (next_readmax == 0) { 23361cb0ef41Sopenharmony_ci 23371cb0ef41Sopenharmony_ci /* This must be true since we only pop DATA frame item from 23381cb0ef41Sopenharmony_ci queue when session->remote_window_size > 0 */ 23391cb0ef41Sopenharmony_ci assert(session->remote_window_size > 0); 23401cb0ef41Sopenharmony_ci 23411cb0ef41Sopenharmony_ci session_defer_stream_item(session, stream, 23421cb0ef41Sopenharmony_ci NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); 23431cb0ef41Sopenharmony_ci 23441cb0ef41Sopenharmony_ci session->aob.item = NULL; 23451cb0ef41Sopenharmony_ci active_outbound_item_reset(&session->aob, mem); 23461cb0ef41Sopenharmony_ci return NGHTTP2_ERR_DEFERRED; 23471cb0ef41Sopenharmony_ci } 23481cb0ef41Sopenharmony_ci 23491cb0ef41Sopenharmony_ci rv = nghttp2_session_pack_data(session, &session->aob.framebufs, 23501cb0ef41Sopenharmony_ci next_readmax, frame, &item->aux_data.data, 23511cb0ef41Sopenharmony_ci stream); 23521cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_PAUSE) { 23531cb0ef41Sopenharmony_ci return rv; 23541cb0ef41Sopenharmony_ci } 23551cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_DEFERRED) { 23561cb0ef41Sopenharmony_ci session_defer_stream_item(session, stream, 23571cb0ef41Sopenharmony_ci NGHTTP2_STREAM_FLAG_DEFERRED_USER); 23581cb0ef41Sopenharmony_ci 23591cb0ef41Sopenharmony_ci session->aob.item = NULL; 23601cb0ef41Sopenharmony_ci active_outbound_item_reset(&session->aob, mem); 23611cb0ef41Sopenharmony_ci return NGHTTP2_ERR_DEFERRED; 23621cb0ef41Sopenharmony_ci } 23631cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { 23641cb0ef41Sopenharmony_ci session_detach_stream_item(session, stream); 23651cb0ef41Sopenharmony_ci 23661cb0ef41Sopenharmony_ci rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id, 23671cb0ef41Sopenharmony_ci NGHTTP2_INTERNAL_ERROR); 23681cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 23691cb0ef41Sopenharmony_ci return rv; 23701cb0ef41Sopenharmony_ci } 23711cb0ef41Sopenharmony_ci return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 23721cb0ef41Sopenharmony_ci } 23731cb0ef41Sopenharmony_ci if (rv != 0) { 23741cb0ef41Sopenharmony_ci session_detach_stream_item(session, stream); 23751cb0ef41Sopenharmony_ci 23761cb0ef41Sopenharmony_ci return rv; 23771cb0ef41Sopenharmony_ci } 23781cb0ef41Sopenharmony_ci return 0; 23791cb0ef41Sopenharmony_ci } 23801cb0ef41Sopenharmony_ci case NGHTTP2_HEADERS: { 23811cb0ef41Sopenharmony_ci nghttp2_headers_aux_data *aux_data; 23821cb0ef41Sopenharmony_ci size_t estimated_payloadlen; 23831cb0ef41Sopenharmony_ci 23841cb0ef41Sopenharmony_ci aux_data = &item->aux_data.headers; 23851cb0ef41Sopenharmony_ci 23861cb0ef41Sopenharmony_ci if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) { 23871cb0ef41Sopenharmony_ci /* initial HEADERS, which opens stream */ 23881cb0ef41Sopenharmony_ci nghttp2_stream *stream; 23891cb0ef41Sopenharmony_ci 23901cb0ef41Sopenharmony_ci stream = nghttp2_session_open_stream( 23911cb0ef41Sopenharmony_ci session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, 23921cb0ef41Sopenharmony_ci &frame->headers.pri_spec, NGHTTP2_STREAM_INITIAL, 23931cb0ef41Sopenharmony_ci aux_data->stream_user_data); 23941cb0ef41Sopenharmony_ci 23951cb0ef41Sopenharmony_ci if (stream == NULL) { 23961cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 23971cb0ef41Sopenharmony_ci } 23981cb0ef41Sopenharmony_ci 23991cb0ef41Sopenharmony_ci /* We don't call nghttp2_session_adjust_closed_stream() here, 24001cb0ef41Sopenharmony_ci since we don't keep closed stream in client side */ 24011cb0ef41Sopenharmony_ci 24021cb0ef41Sopenharmony_ci rv = session_predicate_request_headers_send(session, item); 24031cb0ef41Sopenharmony_ci if (rv != 0) { 24041cb0ef41Sopenharmony_ci return rv; 24051cb0ef41Sopenharmony_ci } 24061cb0ef41Sopenharmony_ci 24071cb0ef41Sopenharmony_ci if (session_enforce_http_messaging(session)) { 24081cb0ef41Sopenharmony_ci nghttp2_http_record_request_method(stream, frame); 24091cb0ef41Sopenharmony_ci } 24101cb0ef41Sopenharmony_ci } else { 24111cb0ef41Sopenharmony_ci nghttp2_stream *stream; 24121cb0ef41Sopenharmony_ci 24131cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 24141cb0ef41Sopenharmony_ci 24151cb0ef41Sopenharmony_ci if (stream && stream->state == NGHTTP2_STREAM_RESERVED) { 24161cb0ef41Sopenharmony_ci rv = session_predicate_push_response_headers_send(session, stream); 24171cb0ef41Sopenharmony_ci if (rv == 0) { 24181cb0ef41Sopenharmony_ci frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE; 24191cb0ef41Sopenharmony_ci 24201cb0ef41Sopenharmony_ci if (aux_data->stream_user_data) { 24211cb0ef41Sopenharmony_ci stream->stream_user_data = aux_data->stream_user_data; 24221cb0ef41Sopenharmony_ci } 24231cb0ef41Sopenharmony_ci } 24241cb0ef41Sopenharmony_ci } else if (session_predicate_response_headers_send(session, stream) == 24251cb0ef41Sopenharmony_ci 0) { 24261cb0ef41Sopenharmony_ci frame->headers.cat = NGHTTP2_HCAT_RESPONSE; 24271cb0ef41Sopenharmony_ci rv = 0; 24281cb0ef41Sopenharmony_ci } else { 24291cb0ef41Sopenharmony_ci frame->headers.cat = NGHTTP2_HCAT_HEADERS; 24301cb0ef41Sopenharmony_ci 24311cb0ef41Sopenharmony_ci rv = session_predicate_headers_send(session, stream); 24321cb0ef41Sopenharmony_ci } 24331cb0ef41Sopenharmony_ci 24341cb0ef41Sopenharmony_ci if (rv != 0) { 24351cb0ef41Sopenharmony_ci return rv; 24361cb0ef41Sopenharmony_ci } 24371cb0ef41Sopenharmony_ci } 24381cb0ef41Sopenharmony_ci 24391cb0ef41Sopenharmony_ci estimated_payloadlen = session_estimate_headers_payload( 24401cb0ef41Sopenharmony_ci session, frame->headers.nva, frame->headers.nvlen, 24411cb0ef41Sopenharmony_ci NGHTTP2_PRIORITY_SPECLEN); 24421cb0ef41Sopenharmony_ci 24431cb0ef41Sopenharmony_ci if (estimated_payloadlen > session->max_send_header_block_length) { 24441cb0ef41Sopenharmony_ci return NGHTTP2_ERR_FRAME_SIZE_ERROR; 24451cb0ef41Sopenharmony_ci } 24461cb0ef41Sopenharmony_ci 24471cb0ef41Sopenharmony_ci rv = nghttp2_frame_pack_headers(&session->aob.framebufs, &frame->headers, 24481cb0ef41Sopenharmony_ci &session->hd_deflater); 24491cb0ef41Sopenharmony_ci 24501cb0ef41Sopenharmony_ci if (rv != 0) { 24511cb0ef41Sopenharmony_ci return rv; 24521cb0ef41Sopenharmony_ci } 24531cb0ef41Sopenharmony_ci 24541cb0ef41Sopenharmony_ci DEBUGF("send: before padding, HEADERS serialized in %zd bytes\n", 24551cb0ef41Sopenharmony_ci nghttp2_bufs_len(&session->aob.framebufs)); 24561cb0ef41Sopenharmony_ci 24571cb0ef41Sopenharmony_ci rv = session_headers_add_pad(session, frame); 24581cb0ef41Sopenharmony_ci 24591cb0ef41Sopenharmony_ci if (rv != 0) { 24601cb0ef41Sopenharmony_ci return rv; 24611cb0ef41Sopenharmony_ci } 24621cb0ef41Sopenharmony_ci 24631cb0ef41Sopenharmony_ci DEBUGF("send: HEADERS finally serialized in %zd bytes\n", 24641cb0ef41Sopenharmony_ci nghttp2_bufs_len(&session->aob.framebufs)); 24651cb0ef41Sopenharmony_ci 24661cb0ef41Sopenharmony_ci if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) { 24671cb0ef41Sopenharmony_ci assert(session->last_sent_stream_id < frame->hd.stream_id); 24681cb0ef41Sopenharmony_ci session->last_sent_stream_id = frame->hd.stream_id; 24691cb0ef41Sopenharmony_ci } 24701cb0ef41Sopenharmony_ci 24711cb0ef41Sopenharmony_ci return 0; 24721cb0ef41Sopenharmony_ci } 24731cb0ef41Sopenharmony_ci case NGHTTP2_PRIORITY: { 24741cb0ef41Sopenharmony_ci if (session_is_closing(session)) { 24751cb0ef41Sopenharmony_ci return NGHTTP2_ERR_SESSION_CLOSING; 24761cb0ef41Sopenharmony_ci } 24771cb0ef41Sopenharmony_ci /* PRIORITY frame can be sent at any time and to any stream 24781cb0ef41Sopenharmony_ci ID. */ 24791cb0ef41Sopenharmony_ci nghttp2_frame_pack_priority(&session->aob.framebufs, &frame->priority); 24801cb0ef41Sopenharmony_ci 24811cb0ef41Sopenharmony_ci /* Peer can send PRIORITY frame against idle stream to create 24821cb0ef41Sopenharmony_ci "anchor" in dependency tree. Only client can do this in 24831cb0ef41Sopenharmony_ci nghttp2. In nghttp2, only server retains non-active (closed 24841cb0ef41Sopenharmony_ci or idle) streams in memory, so we don't open stream here. */ 24851cb0ef41Sopenharmony_ci return 0; 24861cb0ef41Sopenharmony_ci } 24871cb0ef41Sopenharmony_ci case NGHTTP2_RST_STREAM: 24881cb0ef41Sopenharmony_ci if (session_is_closing(session)) { 24891cb0ef41Sopenharmony_ci return NGHTTP2_ERR_SESSION_CLOSING; 24901cb0ef41Sopenharmony_ci } 24911cb0ef41Sopenharmony_ci nghttp2_frame_pack_rst_stream(&session->aob.framebufs, &frame->rst_stream); 24921cb0ef41Sopenharmony_ci return 0; 24931cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS: { 24941cb0ef41Sopenharmony_ci if (frame->hd.flags & NGHTTP2_FLAG_ACK) { 24951cb0ef41Sopenharmony_ci assert(session->obq_flood_counter_ > 0); 24961cb0ef41Sopenharmony_ci --session->obq_flood_counter_; 24971cb0ef41Sopenharmony_ci /* When session is about to close, don't send SETTINGS ACK. 24981cb0ef41Sopenharmony_ci We are required to send SETTINGS without ACK though; for 24991cb0ef41Sopenharmony_ci example, we have to send SETTINGS as a part of connection 25001cb0ef41Sopenharmony_ci preface. */ 25011cb0ef41Sopenharmony_ci if (session_is_closing(session)) { 25021cb0ef41Sopenharmony_ci return NGHTTP2_ERR_SESSION_CLOSING; 25031cb0ef41Sopenharmony_ci } 25041cb0ef41Sopenharmony_ci } 25051cb0ef41Sopenharmony_ci 25061cb0ef41Sopenharmony_ci rv = nghttp2_frame_pack_settings(&session->aob.framebufs, &frame->settings); 25071cb0ef41Sopenharmony_ci if (rv != 0) { 25081cb0ef41Sopenharmony_ci return rv; 25091cb0ef41Sopenharmony_ci } 25101cb0ef41Sopenharmony_ci return 0; 25111cb0ef41Sopenharmony_ci } 25121cb0ef41Sopenharmony_ci case NGHTTP2_PUSH_PROMISE: { 25131cb0ef41Sopenharmony_ci nghttp2_stream *stream; 25141cb0ef41Sopenharmony_ci size_t estimated_payloadlen; 25151cb0ef41Sopenharmony_ci 25161cb0ef41Sopenharmony_ci /* stream could be NULL if associated stream was already 25171cb0ef41Sopenharmony_ci closed. */ 25181cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 25191cb0ef41Sopenharmony_ci 25201cb0ef41Sopenharmony_ci /* predicate should fail if stream is NULL. */ 25211cb0ef41Sopenharmony_ci rv = session_predicate_push_promise_send(session, stream); 25221cb0ef41Sopenharmony_ci if (rv != 0) { 25231cb0ef41Sopenharmony_ci return rv; 25241cb0ef41Sopenharmony_ci } 25251cb0ef41Sopenharmony_ci 25261cb0ef41Sopenharmony_ci assert(stream); 25271cb0ef41Sopenharmony_ci 25281cb0ef41Sopenharmony_ci estimated_payloadlen = session_estimate_headers_payload( 25291cb0ef41Sopenharmony_ci session, frame->push_promise.nva, frame->push_promise.nvlen, 0); 25301cb0ef41Sopenharmony_ci 25311cb0ef41Sopenharmony_ci if (estimated_payloadlen > session->max_send_header_block_length) { 25321cb0ef41Sopenharmony_ci return NGHTTP2_ERR_FRAME_SIZE_ERROR; 25331cb0ef41Sopenharmony_ci } 25341cb0ef41Sopenharmony_ci 25351cb0ef41Sopenharmony_ci rv = nghttp2_frame_pack_push_promise( 25361cb0ef41Sopenharmony_ci &session->aob.framebufs, &frame->push_promise, &session->hd_deflater); 25371cb0ef41Sopenharmony_ci if (rv != 0) { 25381cb0ef41Sopenharmony_ci return rv; 25391cb0ef41Sopenharmony_ci } 25401cb0ef41Sopenharmony_ci rv = session_headers_add_pad(session, frame); 25411cb0ef41Sopenharmony_ci if (rv != 0) { 25421cb0ef41Sopenharmony_ci return rv; 25431cb0ef41Sopenharmony_ci } 25441cb0ef41Sopenharmony_ci 25451cb0ef41Sopenharmony_ci assert(session->last_sent_stream_id + 2 <= 25461cb0ef41Sopenharmony_ci frame->push_promise.promised_stream_id); 25471cb0ef41Sopenharmony_ci session->last_sent_stream_id = frame->push_promise.promised_stream_id; 25481cb0ef41Sopenharmony_ci 25491cb0ef41Sopenharmony_ci return 0; 25501cb0ef41Sopenharmony_ci } 25511cb0ef41Sopenharmony_ci case NGHTTP2_PING: 25521cb0ef41Sopenharmony_ci if (frame->hd.flags & NGHTTP2_FLAG_ACK) { 25531cb0ef41Sopenharmony_ci assert(session->obq_flood_counter_ > 0); 25541cb0ef41Sopenharmony_ci --session->obq_flood_counter_; 25551cb0ef41Sopenharmony_ci } 25561cb0ef41Sopenharmony_ci /* PING frame is allowed to be sent unless termination GOAWAY is 25571cb0ef41Sopenharmony_ci sent */ 25581cb0ef41Sopenharmony_ci if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) { 25591cb0ef41Sopenharmony_ci return NGHTTP2_ERR_SESSION_CLOSING; 25601cb0ef41Sopenharmony_ci } 25611cb0ef41Sopenharmony_ci nghttp2_frame_pack_ping(&session->aob.framebufs, &frame->ping); 25621cb0ef41Sopenharmony_ci return 0; 25631cb0ef41Sopenharmony_ci case NGHTTP2_GOAWAY: 25641cb0ef41Sopenharmony_ci rv = nghttp2_frame_pack_goaway(&session->aob.framebufs, &frame->goaway); 25651cb0ef41Sopenharmony_ci if (rv != 0) { 25661cb0ef41Sopenharmony_ci return rv; 25671cb0ef41Sopenharmony_ci } 25681cb0ef41Sopenharmony_ci session->local_last_stream_id = frame->goaway.last_stream_id; 25691cb0ef41Sopenharmony_ci 25701cb0ef41Sopenharmony_ci return 0; 25711cb0ef41Sopenharmony_ci case NGHTTP2_WINDOW_UPDATE: 25721cb0ef41Sopenharmony_ci rv = session_predicate_window_update_send(session, frame->hd.stream_id); 25731cb0ef41Sopenharmony_ci if (rv != 0) { 25741cb0ef41Sopenharmony_ci return rv; 25751cb0ef41Sopenharmony_ci } 25761cb0ef41Sopenharmony_ci nghttp2_frame_pack_window_update(&session->aob.framebufs, 25771cb0ef41Sopenharmony_ci &frame->window_update); 25781cb0ef41Sopenharmony_ci return 0; 25791cb0ef41Sopenharmony_ci case NGHTTP2_CONTINUATION: 25801cb0ef41Sopenharmony_ci /* We never handle CONTINUATION here. */ 25811cb0ef41Sopenharmony_ci assert(0); 25821cb0ef41Sopenharmony_ci return 0; 25831cb0ef41Sopenharmony_ci default: { 25841cb0ef41Sopenharmony_ci nghttp2_ext_aux_data *aux_data; 25851cb0ef41Sopenharmony_ci 25861cb0ef41Sopenharmony_ci /* extension frame */ 25871cb0ef41Sopenharmony_ci 25881cb0ef41Sopenharmony_ci aux_data = &item->aux_data.ext; 25891cb0ef41Sopenharmony_ci 25901cb0ef41Sopenharmony_ci if (aux_data->builtin == 0) { 25911cb0ef41Sopenharmony_ci if (session_is_closing(session)) { 25921cb0ef41Sopenharmony_ci return NGHTTP2_ERR_SESSION_CLOSING; 25931cb0ef41Sopenharmony_ci } 25941cb0ef41Sopenharmony_ci 25951cb0ef41Sopenharmony_ci return session_pack_extension(session, &session->aob.framebufs, frame); 25961cb0ef41Sopenharmony_ci } 25971cb0ef41Sopenharmony_ci 25981cb0ef41Sopenharmony_ci switch (frame->hd.type) { 25991cb0ef41Sopenharmony_ci case NGHTTP2_ALTSVC: 26001cb0ef41Sopenharmony_ci rv = session_predicate_altsvc_send(session, frame->hd.stream_id); 26011cb0ef41Sopenharmony_ci if (rv != 0) { 26021cb0ef41Sopenharmony_ci return rv; 26031cb0ef41Sopenharmony_ci } 26041cb0ef41Sopenharmony_ci 26051cb0ef41Sopenharmony_ci nghttp2_frame_pack_altsvc(&session->aob.framebufs, &frame->ext); 26061cb0ef41Sopenharmony_ci 26071cb0ef41Sopenharmony_ci return 0; 26081cb0ef41Sopenharmony_ci case NGHTTP2_ORIGIN: 26091cb0ef41Sopenharmony_ci rv = session_predicate_origin_send(session); 26101cb0ef41Sopenharmony_ci if (rv != 0) { 26111cb0ef41Sopenharmony_ci return rv; 26121cb0ef41Sopenharmony_ci } 26131cb0ef41Sopenharmony_ci 26141cb0ef41Sopenharmony_ci rv = nghttp2_frame_pack_origin(&session->aob.framebufs, &frame->ext); 26151cb0ef41Sopenharmony_ci if (rv != 0) { 26161cb0ef41Sopenharmony_ci return rv; 26171cb0ef41Sopenharmony_ci } 26181cb0ef41Sopenharmony_ci 26191cb0ef41Sopenharmony_ci return 0; 26201cb0ef41Sopenharmony_ci case NGHTTP2_PRIORITY_UPDATE: { 26211cb0ef41Sopenharmony_ci nghttp2_ext_priority_update *priority_update = frame->ext.payload; 26221cb0ef41Sopenharmony_ci rv = session_predicate_priority_update_send(session, 26231cb0ef41Sopenharmony_ci priority_update->stream_id); 26241cb0ef41Sopenharmony_ci if (rv != 0) { 26251cb0ef41Sopenharmony_ci return rv; 26261cb0ef41Sopenharmony_ci } 26271cb0ef41Sopenharmony_ci 26281cb0ef41Sopenharmony_ci nghttp2_frame_pack_priority_update(&session->aob.framebufs, &frame->ext); 26291cb0ef41Sopenharmony_ci 26301cb0ef41Sopenharmony_ci return 0; 26311cb0ef41Sopenharmony_ci } 26321cb0ef41Sopenharmony_ci default: 26331cb0ef41Sopenharmony_ci /* Unreachable here */ 26341cb0ef41Sopenharmony_ci assert(0); 26351cb0ef41Sopenharmony_ci return 0; 26361cb0ef41Sopenharmony_ci } 26371cb0ef41Sopenharmony_ci } 26381cb0ef41Sopenharmony_ci } 26391cb0ef41Sopenharmony_ci} 26401cb0ef41Sopenharmony_ci 26411cb0ef41Sopenharmony_cinghttp2_outbound_item * 26421cb0ef41Sopenharmony_cinghttp2_session_get_next_ob_item(nghttp2_session *session) { 26431cb0ef41Sopenharmony_ci nghttp2_outbound_item *item; 26441cb0ef41Sopenharmony_ci 26451cb0ef41Sopenharmony_ci if (nghttp2_outbound_queue_top(&session->ob_urgent)) { 26461cb0ef41Sopenharmony_ci return nghttp2_outbound_queue_top(&session->ob_urgent); 26471cb0ef41Sopenharmony_ci } 26481cb0ef41Sopenharmony_ci 26491cb0ef41Sopenharmony_ci if (nghttp2_outbound_queue_top(&session->ob_reg)) { 26501cb0ef41Sopenharmony_ci return nghttp2_outbound_queue_top(&session->ob_reg); 26511cb0ef41Sopenharmony_ci } 26521cb0ef41Sopenharmony_ci 26531cb0ef41Sopenharmony_ci if (!session_is_outgoing_concurrent_streams_max(session)) { 26541cb0ef41Sopenharmony_ci if (nghttp2_outbound_queue_top(&session->ob_syn)) { 26551cb0ef41Sopenharmony_ci return nghttp2_outbound_queue_top(&session->ob_syn); 26561cb0ef41Sopenharmony_ci } 26571cb0ef41Sopenharmony_ci } 26581cb0ef41Sopenharmony_ci 26591cb0ef41Sopenharmony_ci if (session->remote_window_size > 0) { 26601cb0ef41Sopenharmony_ci item = nghttp2_stream_next_outbound_item(&session->root); 26611cb0ef41Sopenharmony_ci if (item) { 26621cb0ef41Sopenharmony_ci return item; 26631cb0ef41Sopenharmony_ci } 26641cb0ef41Sopenharmony_ci 26651cb0ef41Sopenharmony_ci return session_sched_get_next_outbound_item(session); 26661cb0ef41Sopenharmony_ci } 26671cb0ef41Sopenharmony_ci 26681cb0ef41Sopenharmony_ci return NULL; 26691cb0ef41Sopenharmony_ci} 26701cb0ef41Sopenharmony_ci 26711cb0ef41Sopenharmony_cinghttp2_outbound_item * 26721cb0ef41Sopenharmony_cinghttp2_session_pop_next_ob_item(nghttp2_session *session) { 26731cb0ef41Sopenharmony_ci nghttp2_outbound_item *item; 26741cb0ef41Sopenharmony_ci 26751cb0ef41Sopenharmony_ci item = nghttp2_outbound_queue_top(&session->ob_urgent); 26761cb0ef41Sopenharmony_ci if (item) { 26771cb0ef41Sopenharmony_ci nghttp2_outbound_queue_pop(&session->ob_urgent); 26781cb0ef41Sopenharmony_ci item->queued = 0; 26791cb0ef41Sopenharmony_ci return item; 26801cb0ef41Sopenharmony_ci } 26811cb0ef41Sopenharmony_ci 26821cb0ef41Sopenharmony_ci item = nghttp2_outbound_queue_top(&session->ob_reg); 26831cb0ef41Sopenharmony_ci if (item) { 26841cb0ef41Sopenharmony_ci nghttp2_outbound_queue_pop(&session->ob_reg); 26851cb0ef41Sopenharmony_ci item->queued = 0; 26861cb0ef41Sopenharmony_ci return item; 26871cb0ef41Sopenharmony_ci } 26881cb0ef41Sopenharmony_ci 26891cb0ef41Sopenharmony_ci if (!session_is_outgoing_concurrent_streams_max(session)) { 26901cb0ef41Sopenharmony_ci item = nghttp2_outbound_queue_top(&session->ob_syn); 26911cb0ef41Sopenharmony_ci if (item) { 26921cb0ef41Sopenharmony_ci nghttp2_outbound_queue_pop(&session->ob_syn); 26931cb0ef41Sopenharmony_ci item->queued = 0; 26941cb0ef41Sopenharmony_ci return item; 26951cb0ef41Sopenharmony_ci } 26961cb0ef41Sopenharmony_ci } 26971cb0ef41Sopenharmony_ci 26981cb0ef41Sopenharmony_ci if (session->remote_window_size > 0) { 26991cb0ef41Sopenharmony_ci item = nghttp2_stream_next_outbound_item(&session->root); 27001cb0ef41Sopenharmony_ci if (item) { 27011cb0ef41Sopenharmony_ci return item; 27021cb0ef41Sopenharmony_ci } 27031cb0ef41Sopenharmony_ci 27041cb0ef41Sopenharmony_ci return session_sched_get_next_outbound_item(session); 27051cb0ef41Sopenharmony_ci } 27061cb0ef41Sopenharmony_ci 27071cb0ef41Sopenharmony_ci return NULL; 27081cb0ef41Sopenharmony_ci} 27091cb0ef41Sopenharmony_ci 27101cb0ef41Sopenharmony_cistatic int session_call_before_frame_send(nghttp2_session *session, 27111cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 27121cb0ef41Sopenharmony_ci int rv; 27131cb0ef41Sopenharmony_ci if (session->callbacks.before_frame_send_callback) { 27141cb0ef41Sopenharmony_ci rv = session->callbacks.before_frame_send_callback(session, frame, 27151cb0ef41Sopenharmony_ci session->user_data); 27161cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_CANCEL) { 27171cb0ef41Sopenharmony_ci return rv; 27181cb0ef41Sopenharmony_ci } 27191cb0ef41Sopenharmony_ci 27201cb0ef41Sopenharmony_ci if (rv != 0) { 27211cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 27221cb0ef41Sopenharmony_ci } 27231cb0ef41Sopenharmony_ci } 27241cb0ef41Sopenharmony_ci return 0; 27251cb0ef41Sopenharmony_ci} 27261cb0ef41Sopenharmony_ci 27271cb0ef41Sopenharmony_cistatic int session_call_on_frame_send(nghttp2_session *session, 27281cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 27291cb0ef41Sopenharmony_ci int rv; 27301cb0ef41Sopenharmony_ci if (session->callbacks.on_frame_send_callback) { 27311cb0ef41Sopenharmony_ci rv = session->callbacks.on_frame_send_callback(session, frame, 27321cb0ef41Sopenharmony_ci session->user_data); 27331cb0ef41Sopenharmony_ci if (rv != 0) { 27341cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 27351cb0ef41Sopenharmony_ci } 27361cb0ef41Sopenharmony_ci } 27371cb0ef41Sopenharmony_ci return 0; 27381cb0ef41Sopenharmony_ci} 27391cb0ef41Sopenharmony_ci 27401cb0ef41Sopenharmony_cistatic int find_stream_on_goaway_func(void *entry, void *ptr) { 27411cb0ef41Sopenharmony_ci nghttp2_close_stream_on_goaway_arg *arg; 27421cb0ef41Sopenharmony_ci nghttp2_stream *stream; 27431cb0ef41Sopenharmony_ci 27441cb0ef41Sopenharmony_ci arg = (nghttp2_close_stream_on_goaway_arg *)ptr; 27451cb0ef41Sopenharmony_ci stream = (nghttp2_stream *)entry; 27461cb0ef41Sopenharmony_ci 27471cb0ef41Sopenharmony_ci if (nghttp2_session_is_my_stream_id(arg->session, stream->stream_id)) { 27481cb0ef41Sopenharmony_ci if (arg->incoming) { 27491cb0ef41Sopenharmony_ci return 0; 27501cb0ef41Sopenharmony_ci } 27511cb0ef41Sopenharmony_ci } else if (!arg->incoming) { 27521cb0ef41Sopenharmony_ci return 0; 27531cb0ef41Sopenharmony_ci } 27541cb0ef41Sopenharmony_ci 27551cb0ef41Sopenharmony_ci if (stream->state != NGHTTP2_STREAM_IDLE && 27561cb0ef41Sopenharmony_ci (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) == 0 && 27571cb0ef41Sopenharmony_ci stream->stream_id > arg->last_stream_id) { 27581cb0ef41Sopenharmony_ci /* We are collecting streams to close because we cannot call 27591cb0ef41Sopenharmony_ci nghttp2_session_close_stream() inside nghttp2_map_each(). 27601cb0ef41Sopenharmony_ci Reuse closed_next member.. bad choice? */ 27611cb0ef41Sopenharmony_ci assert(stream->closed_next == NULL); 27621cb0ef41Sopenharmony_ci assert(stream->closed_prev == NULL); 27631cb0ef41Sopenharmony_ci 27641cb0ef41Sopenharmony_ci if (arg->head) { 27651cb0ef41Sopenharmony_ci stream->closed_next = arg->head; 27661cb0ef41Sopenharmony_ci arg->head = stream; 27671cb0ef41Sopenharmony_ci } else { 27681cb0ef41Sopenharmony_ci arg->head = stream; 27691cb0ef41Sopenharmony_ci } 27701cb0ef41Sopenharmony_ci } 27711cb0ef41Sopenharmony_ci 27721cb0ef41Sopenharmony_ci return 0; 27731cb0ef41Sopenharmony_ci} 27741cb0ef41Sopenharmony_ci 27751cb0ef41Sopenharmony_ci/* Closes non-idle and non-closed streams whose stream ID > 27761cb0ef41Sopenharmony_ci last_stream_id. If incoming is nonzero, we are going to close 27771cb0ef41Sopenharmony_ci incoming streams. Otherwise, close outgoing streams. */ 27781cb0ef41Sopenharmony_cistatic int session_close_stream_on_goaway(nghttp2_session *session, 27791cb0ef41Sopenharmony_ci int32_t last_stream_id, 27801cb0ef41Sopenharmony_ci int incoming) { 27811cb0ef41Sopenharmony_ci int rv; 27821cb0ef41Sopenharmony_ci nghttp2_stream *stream, *next_stream; 27831cb0ef41Sopenharmony_ci nghttp2_close_stream_on_goaway_arg arg = {session, NULL, last_stream_id, 27841cb0ef41Sopenharmony_ci incoming}; 27851cb0ef41Sopenharmony_ci 27861cb0ef41Sopenharmony_ci rv = nghttp2_map_each(&session->streams, find_stream_on_goaway_func, &arg); 27871cb0ef41Sopenharmony_ci assert(rv == 0); 27881cb0ef41Sopenharmony_ci 27891cb0ef41Sopenharmony_ci stream = arg.head; 27901cb0ef41Sopenharmony_ci while (stream) { 27911cb0ef41Sopenharmony_ci next_stream = stream->closed_next; 27921cb0ef41Sopenharmony_ci stream->closed_next = NULL; 27931cb0ef41Sopenharmony_ci rv = nghttp2_session_close_stream(session, stream->stream_id, 27941cb0ef41Sopenharmony_ci NGHTTP2_REFUSED_STREAM); 27951cb0ef41Sopenharmony_ci 27961cb0ef41Sopenharmony_ci /* stream may be deleted here */ 27971cb0ef41Sopenharmony_ci 27981cb0ef41Sopenharmony_ci stream = next_stream; 27991cb0ef41Sopenharmony_ci 28001cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 28011cb0ef41Sopenharmony_ci /* Clean up closed_next member just in case */ 28021cb0ef41Sopenharmony_ci while (stream) { 28031cb0ef41Sopenharmony_ci next_stream = stream->closed_next; 28041cb0ef41Sopenharmony_ci stream->closed_next = NULL; 28051cb0ef41Sopenharmony_ci stream = next_stream; 28061cb0ef41Sopenharmony_ci } 28071cb0ef41Sopenharmony_ci return rv; 28081cb0ef41Sopenharmony_ci } 28091cb0ef41Sopenharmony_ci } 28101cb0ef41Sopenharmony_ci 28111cb0ef41Sopenharmony_ci return 0; 28121cb0ef41Sopenharmony_ci} 28131cb0ef41Sopenharmony_ci 28141cb0ef41Sopenharmony_cistatic void session_reschedule_stream(nghttp2_session *session, 28151cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 28161cb0ef41Sopenharmony_ci stream->last_writelen = stream->item->frame.hd.length; 28171cb0ef41Sopenharmony_ci 28181cb0ef41Sopenharmony_ci if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) { 28191cb0ef41Sopenharmony_ci nghttp2_stream_reschedule(stream); 28201cb0ef41Sopenharmony_ci return; 28211cb0ef41Sopenharmony_ci } 28221cb0ef41Sopenharmony_ci 28231cb0ef41Sopenharmony_ci if (!session->server) { 28241cb0ef41Sopenharmony_ci return; 28251cb0ef41Sopenharmony_ci } 28261cb0ef41Sopenharmony_ci 28271cb0ef41Sopenharmony_ci session_sched_reschedule_stream(session, stream); 28281cb0ef41Sopenharmony_ci} 28291cb0ef41Sopenharmony_ci 28301cb0ef41Sopenharmony_cistatic int session_update_stream_consumed_size(nghttp2_session *session, 28311cb0ef41Sopenharmony_ci nghttp2_stream *stream, 28321cb0ef41Sopenharmony_ci size_t delta_size); 28331cb0ef41Sopenharmony_ci 28341cb0ef41Sopenharmony_cistatic int session_update_connection_consumed_size(nghttp2_session *session, 28351cb0ef41Sopenharmony_ci size_t delta_size); 28361cb0ef41Sopenharmony_ci 28371cb0ef41Sopenharmony_ci/* 28381cb0ef41Sopenharmony_ci * Called after a frame is sent. This function runs 28391cb0ef41Sopenharmony_ci * on_frame_send_callback and handles stream closure upon END_STREAM 28401cb0ef41Sopenharmony_ci * or RST_STREAM. This function does not reset session->aob. It is a 28411cb0ef41Sopenharmony_ci * responsibility of session_after_frame_sent2. 28421cb0ef41Sopenharmony_ci * 28431cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 28441cb0ef41Sopenharmony_ci * negative error codes: 28451cb0ef41Sopenharmony_ci * 28461cb0ef41Sopenharmony_ci * NGHTTP2_ERR_NOMEM 28471cb0ef41Sopenharmony_ci * Out of memory. 28481cb0ef41Sopenharmony_ci * NGHTTP2_ERR_CALLBACK_FAILURE 28491cb0ef41Sopenharmony_ci * The callback function failed. 28501cb0ef41Sopenharmony_ci */ 28511cb0ef41Sopenharmony_cistatic int session_after_frame_sent1(nghttp2_session *session) { 28521cb0ef41Sopenharmony_ci int rv; 28531cb0ef41Sopenharmony_ci nghttp2_active_outbound_item *aob = &session->aob; 28541cb0ef41Sopenharmony_ci nghttp2_outbound_item *item = aob->item; 28551cb0ef41Sopenharmony_ci nghttp2_bufs *framebufs = &aob->framebufs; 28561cb0ef41Sopenharmony_ci nghttp2_frame *frame; 28571cb0ef41Sopenharmony_ci nghttp2_stream *stream; 28581cb0ef41Sopenharmony_ci 28591cb0ef41Sopenharmony_ci frame = &item->frame; 28601cb0ef41Sopenharmony_ci 28611cb0ef41Sopenharmony_ci if (frame->hd.type == NGHTTP2_DATA) { 28621cb0ef41Sopenharmony_ci nghttp2_data_aux_data *aux_data; 28631cb0ef41Sopenharmony_ci 28641cb0ef41Sopenharmony_ci aux_data = &item->aux_data.data; 28651cb0ef41Sopenharmony_ci 28661cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 28671cb0ef41Sopenharmony_ci /* We update flow control window after a frame was completely 28681cb0ef41Sopenharmony_ci sent. This is possible because we choose payload length not to 28691cb0ef41Sopenharmony_ci exceed the window */ 28701cb0ef41Sopenharmony_ci session->remote_window_size -= (int32_t)frame->hd.length; 28711cb0ef41Sopenharmony_ci if (stream) { 28721cb0ef41Sopenharmony_ci stream->remote_window_size -= (int32_t)frame->hd.length; 28731cb0ef41Sopenharmony_ci } 28741cb0ef41Sopenharmony_ci 28751cb0ef41Sopenharmony_ci if (stream && aux_data->eof) { 28761cb0ef41Sopenharmony_ci session_detach_stream_item(session, stream); 28771cb0ef41Sopenharmony_ci 28781cb0ef41Sopenharmony_ci /* Call on_frame_send_callback after 28791cb0ef41Sopenharmony_ci nghttp2_stream_detach_item(), so that application can issue 28801cb0ef41Sopenharmony_ci nghttp2_submit_data() in the callback. */ 28811cb0ef41Sopenharmony_ci if (session->callbacks.on_frame_send_callback) { 28821cb0ef41Sopenharmony_ci rv = session_call_on_frame_send(session, frame); 28831cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 28841cb0ef41Sopenharmony_ci return rv; 28851cb0ef41Sopenharmony_ci } 28861cb0ef41Sopenharmony_ci } 28871cb0ef41Sopenharmony_ci 28881cb0ef41Sopenharmony_ci if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { 28891cb0ef41Sopenharmony_ci int stream_closed; 28901cb0ef41Sopenharmony_ci 28911cb0ef41Sopenharmony_ci stream_closed = 28921cb0ef41Sopenharmony_ci (stream->shut_flags & NGHTTP2_SHUT_RDWR) == NGHTTP2_SHUT_RDWR; 28931cb0ef41Sopenharmony_ci 28941cb0ef41Sopenharmony_ci nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); 28951cb0ef41Sopenharmony_ci 28961cb0ef41Sopenharmony_ci rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); 28971cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 28981cb0ef41Sopenharmony_ci return rv; 28991cb0ef41Sopenharmony_ci } 29001cb0ef41Sopenharmony_ci /* stream may be NULL if it was closed */ 29011cb0ef41Sopenharmony_ci if (stream_closed) { 29021cb0ef41Sopenharmony_ci stream = NULL; 29031cb0ef41Sopenharmony_ci } 29041cb0ef41Sopenharmony_ci } 29051cb0ef41Sopenharmony_ci return 0; 29061cb0ef41Sopenharmony_ci } 29071cb0ef41Sopenharmony_ci 29081cb0ef41Sopenharmony_ci if (session->callbacks.on_frame_send_callback) { 29091cb0ef41Sopenharmony_ci rv = session_call_on_frame_send(session, frame); 29101cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 29111cb0ef41Sopenharmony_ci return rv; 29121cb0ef41Sopenharmony_ci } 29131cb0ef41Sopenharmony_ci } 29141cb0ef41Sopenharmony_ci 29151cb0ef41Sopenharmony_ci return 0; 29161cb0ef41Sopenharmony_ci } 29171cb0ef41Sopenharmony_ci 29181cb0ef41Sopenharmony_ci /* non-DATA frame */ 29191cb0ef41Sopenharmony_ci 29201cb0ef41Sopenharmony_ci if (frame->hd.type == NGHTTP2_HEADERS || 29211cb0ef41Sopenharmony_ci frame->hd.type == NGHTTP2_PUSH_PROMISE) { 29221cb0ef41Sopenharmony_ci if (nghttp2_bufs_next_present(framebufs)) { 29231cb0ef41Sopenharmony_ci DEBUGF("send: CONTINUATION exists, just return\n"); 29241cb0ef41Sopenharmony_ci return 0; 29251cb0ef41Sopenharmony_ci } 29261cb0ef41Sopenharmony_ci } 29271cb0ef41Sopenharmony_ci rv = session_call_on_frame_send(session, frame); 29281cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 29291cb0ef41Sopenharmony_ci return rv; 29301cb0ef41Sopenharmony_ci } 29311cb0ef41Sopenharmony_ci switch (frame->hd.type) { 29321cb0ef41Sopenharmony_ci case NGHTTP2_HEADERS: { 29331cb0ef41Sopenharmony_ci nghttp2_headers_aux_data *aux_data; 29341cb0ef41Sopenharmony_ci 29351cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 29361cb0ef41Sopenharmony_ci if (!stream) { 29371cb0ef41Sopenharmony_ci return 0; 29381cb0ef41Sopenharmony_ci } 29391cb0ef41Sopenharmony_ci 29401cb0ef41Sopenharmony_ci switch (frame->headers.cat) { 29411cb0ef41Sopenharmony_ci case NGHTTP2_HCAT_REQUEST: { 29421cb0ef41Sopenharmony_ci stream->state = NGHTTP2_STREAM_OPENING; 29431cb0ef41Sopenharmony_ci if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { 29441cb0ef41Sopenharmony_ci nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); 29451cb0ef41Sopenharmony_ci } 29461cb0ef41Sopenharmony_ci rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); 29471cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 29481cb0ef41Sopenharmony_ci return rv; 29491cb0ef41Sopenharmony_ci } 29501cb0ef41Sopenharmony_ci /* We assume aux_data is a pointer to nghttp2_headers_aux_data */ 29511cb0ef41Sopenharmony_ci aux_data = &item->aux_data.headers; 29521cb0ef41Sopenharmony_ci if (aux_data->data_prd.read_callback) { 29531cb0ef41Sopenharmony_ci /* nghttp2_submit_data() makes a copy of aux_data->data_prd */ 29541cb0ef41Sopenharmony_ci rv = nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, 29551cb0ef41Sopenharmony_ci frame->hd.stream_id, &aux_data->data_prd); 29561cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 29571cb0ef41Sopenharmony_ci return rv; 29581cb0ef41Sopenharmony_ci } 29591cb0ef41Sopenharmony_ci /* TODO nghttp2_submit_data() may fail if stream has already 29601cb0ef41Sopenharmony_ci DATA frame item. We might have to handle it here. */ 29611cb0ef41Sopenharmony_ci } 29621cb0ef41Sopenharmony_ci return 0; 29631cb0ef41Sopenharmony_ci } 29641cb0ef41Sopenharmony_ci case NGHTTP2_HCAT_PUSH_RESPONSE: 29651cb0ef41Sopenharmony_ci stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH); 29661cb0ef41Sopenharmony_ci ++session->num_outgoing_streams; 29671cb0ef41Sopenharmony_ci /* Fall through */ 29681cb0ef41Sopenharmony_ci case NGHTTP2_HCAT_RESPONSE: 29691cb0ef41Sopenharmony_ci stream->state = NGHTTP2_STREAM_OPENED; 29701cb0ef41Sopenharmony_ci /* Fall through */ 29711cb0ef41Sopenharmony_ci case NGHTTP2_HCAT_HEADERS: 29721cb0ef41Sopenharmony_ci if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { 29731cb0ef41Sopenharmony_ci nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); 29741cb0ef41Sopenharmony_ci } 29751cb0ef41Sopenharmony_ci rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); 29761cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 29771cb0ef41Sopenharmony_ci return rv; 29781cb0ef41Sopenharmony_ci } 29791cb0ef41Sopenharmony_ci /* We assume aux_data is a pointer to nghttp2_headers_aux_data */ 29801cb0ef41Sopenharmony_ci aux_data = &item->aux_data.headers; 29811cb0ef41Sopenharmony_ci if (aux_data->data_prd.read_callback) { 29821cb0ef41Sopenharmony_ci rv = nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, 29831cb0ef41Sopenharmony_ci frame->hd.stream_id, &aux_data->data_prd); 29841cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 29851cb0ef41Sopenharmony_ci return rv; 29861cb0ef41Sopenharmony_ci } 29871cb0ef41Sopenharmony_ci /* TODO nghttp2_submit_data() may fail if stream has already 29881cb0ef41Sopenharmony_ci DATA frame item. We might have to handle it here. */ 29891cb0ef41Sopenharmony_ci } 29901cb0ef41Sopenharmony_ci return 0; 29911cb0ef41Sopenharmony_ci default: 29921cb0ef41Sopenharmony_ci /* Unreachable */ 29931cb0ef41Sopenharmony_ci assert(0); 29941cb0ef41Sopenharmony_ci return 0; 29951cb0ef41Sopenharmony_ci } 29961cb0ef41Sopenharmony_ci } 29971cb0ef41Sopenharmony_ci case NGHTTP2_PRIORITY: 29981cb0ef41Sopenharmony_ci if (session->server || session->pending_no_rfc7540_priorities == 1) { 29991cb0ef41Sopenharmony_ci return 0; 30001cb0ef41Sopenharmony_ci } 30011cb0ef41Sopenharmony_ci 30021cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); 30031cb0ef41Sopenharmony_ci 30041cb0ef41Sopenharmony_ci if (!stream) { 30051cb0ef41Sopenharmony_ci if (!session_detect_idle_stream(session, frame->hd.stream_id)) { 30061cb0ef41Sopenharmony_ci return 0; 30071cb0ef41Sopenharmony_ci } 30081cb0ef41Sopenharmony_ci 30091cb0ef41Sopenharmony_ci stream = nghttp2_session_open_stream( 30101cb0ef41Sopenharmony_ci session, frame->hd.stream_id, NGHTTP2_FLAG_NONE, 30111cb0ef41Sopenharmony_ci &frame->priority.pri_spec, NGHTTP2_STREAM_IDLE, NULL); 30121cb0ef41Sopenharmony_ci if (!stream) { 30131cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 30141cb0ef41Sopenharmony_ci } 30151cb0ef41Sopenharmony_ci } else { 30161cb0ef41Sopenharmony_ci rv = nghttp2_session_reprioritize_stream(session, stream, 30171cb0ef41Sopenharmony_ci &frame->priority.pri_spec); 30181cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 30191cb0ef41Sopenharmony_ci return rv; 30201cb0ef41Sopenharmony_ci } 30211cb0ef41Sopenharmony_ci } 30221cb0ef41Sopenharmony_ci 30231cb0ef41Sopenharmony_ci rv = nghttp2_session_adjust_idle_stream(session); 30241cb0ef41Sopenharmony_ci 30251cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 30261cb0ef41Sopenharmony_ci return rv; 30271cb0ef41Sopenharmony_ci } 30281cb0ef41Sopenharmony_ci 30291cb0ef41Sopenharmony_ci return 0; 30301cb0ef41Sopenharmony_ci case NGHTTP2_RST_STREAM: 30311cb0ef41Sopenharmony_ci rv = nghttp2_session_close_stream(session, frame->hd.stream_id, 30321cb0ef41Sopenharmony_ci frame->rst_stream.error_code); 30331cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 30341cb0ef41Sopenharmony_ci return rv; 30351cb0ef41Sopenharmony_ci } 30361cb0ef41Sopenharmony_ci return 0; 30371cb0ef41Sopenharmony_ci case NGHTTP2_GOAWAY: { 30381cb0ef41Sopenharmony_ci nghttp2_goaway_aux_data *aux_data; 30391cb0ef41Sopenharmony_ci 30401cb0ef41Sopenharmony_ci aux_data = &item->aux_data.goaway; 30411cb0ef41Sopenharmony_ci 30421cb0ef41Sopenharmony_ci if ((aux_data->flags & NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE) == 0) { 30431cb0ef41Sopenharmony_ci 30441cb0ef41Sopenharmony_ci if (aux_data->flags & NGHTTP2_GOAWAY_AUX_TERM_ON_SEND) { 30451cb0ef41Sopenharmony_ci session->goaway_flags |= NGHTTP2_GOAWAY_TERM_SENT; 30461cb0ef41Sopenharmony_ci } 30471cb0ef41Sopenharmony_ci 30481cb0ef41Sopenharmony_ci session->goaway_flags |= NGHTTP2_GOAWAY_SENT; 30491cb0ef41Sopenharmony_ci 30501cb0ef41Sopenharmony_ci rv = session_close_stream_on_goaway(session, frame->goaway.last_stream_id, 30511cb0ef41Sopenharmony_ci 1); 30521cb0ef41Sopenharmony_ci 30531cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 30541cb0ef41Sopenharmony_ci return rv; 30551cb0ef41Sopenharmony_ci } 30561cb0ef41Sopenharmony_ci } 30571cb0ef41Sopenharmony_ci 30581cb0ef41Sopenharmony_ci return 0; 30591cb0ef41Sopenharmony_ci } 30601cb0ef41Sopenharmony_ci case NGHTTP2_WINDOW_UPDATE: 30611cb0ef41Sopenharmony_ci if (frame->hd.stream_id == 0) { 30621cb0ef41Sopenharmony_ci session->window_update_queued = 0; 30631cb0ef41Sopenharmony_ci if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { 30641cb0ef41Sopenharmony_ci rv = session_update_connection_consumed_size(session, 0); 30651cb0ef41Sopenharmony_ci } else { 30661cb0ef41Sopenharmony_ci rv = nghttp2_session_update_recv_connection_window_size(session, 0); 30671cb0ef41Sopenharmony_ci } 30681cb0ef41Sopenharmony_ci 30691cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 30701cb0ef41Sopenharmony_ci return rv; 30711cb0ef41Sopenharmony_ci } 30721cb0ef41Sopenharmony_ci 30731cb0ef41Sopenharmony_ci return 0; 30741cb0ef41Sopenharmony_ci } 30751cb0ef41Sopenharmony_ci 30761cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 30771cb0ef41Sopenharmony_ci if (!stream) { 30781cb0ef41Sopenharmony_ci return 0; 30791cb0ef41Sopenharmony_ci } 30801cb0ef41Sopenharmony_ci 30811cb0ef41Sopenharmony_ci stream->window_update_queued = 0; 30821cb0ef41Sopenharmony_ci 30831cb0ef41Sopenharmony_ci /* We don't have to send WINDOW_UPDATE if END_STREAM from peer 30841cb0ef41Sopenharmony_ci is seen. */ 30851cb0ef41Sopenharmony_ci if (stream->shut_flags & NGHTTP2_SHUT_RD) { 30861cb0ef41Sopenharmony_ci return 0; 30871cb0ef41Sopenharmony_ci } 30881cb0ef41Sopenharmony_ci 30891cb0ef41Sopenharmony_ci if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { 30901cb0ef41Sopenharmony_ci rv = session_update_stream_consumed_size(session, stream, 0); 30911cb0ef41Sopenharmony_ci } else { 30921cb0ef41Sopenharmony_ci rv = 30931cb0ef41Sopenharmony_ci nghttp2_session_update_recv_stream_window_size(session, stream, 0, 1); 30941cb0ef41Sopenharmony_ci } 30951cb0ef41Sopenharmony_ci 30961cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 30971cb0ef41Sopenharmony_ci return rv; 30981cb0ef41Sopenharmony_ci } 30991cb0ef41Sopenharmony_ci 31001cb0ef41Sopenharmony_ci return 0; 31011cb0ef41Sopenharmony_ci default: 31021cb0ef41Sopenharmony_ci return 0; 31031cb0ef41Sopenharmony_ci } 31041cb0ef41Sopenharmony_ci} 31051cb0ef41Sopenharmony_ci 31061cb0ef41Sopenharmony_ci/* 31071cb0ef41Sopenharmony_ci * Called after a frame is sent and session_after_frame_sent1. This 31081cb0ef41Sopenharmony_ci * function is responsible to reset session->aob. 31091cb0ef41Sopenharmony_ci */ 31101cb0ef41Sopenharmony_cistatic void session_after_frame_sent2(nghttp2_session *session) { 31111cb0ef41Sopenharmony_ci nghttp2_active_outbound_item *aob = &session->aob; 31121cb0ef41Sopenharmony_ci nghttp2_outbound_item *item = aob->item; 31131cb0ef41Sopenharmony_ci nghttp2_bufs *framebufs = &aob->framebufs; 31141cb0ef41Sopenharmony_ci nghttp2_frame *frame; 31151cb0ef41Sopenharmony_ci nghttp2_mem *mem; 31161cb0ef41Sopenharmony_ci nghttp2_stream *stream; 31171cb0ef41Sopenharmony_ci nghttp2_data_aux_data *aux_data; 31181cb0ef41Sopenharmony_ci 31191cb0ef41Sopenharmony_ci mem = &session->mem; 31201cb0ef41Sopenharmony_ci frame = &item->frame; 31211cb0ef41Sopenharmony_ci 31221cb0ef41Sopenharmony_ci if (frame->hd.type != NGHTTP2_DATA) { 31231cb0ef41Sopenharmony_ci 31241cb0ef41Sopenharmony_ci if (frame->hd.type == NGHTTP2_HEADERS || 31251cb0ef41Sopenharmony_ci frame->hd.type == NGHTTP2_PUSH_PROMISE) { 31261cb0ef41Sopenharmony_ci 31271cb0ef41Sopenharmony_ci if (nghttp2_bufs_next_present(framebufs)) { 31281cb0ef41Sopenharmony_ci framebufs->cur = framebufs->cur->next; 31291cb0ef41Sopenharmony_ci 31301cb0ef41Sopenharmony_ci DEBUGF("send: next CONTINUATION frame, %zu bytes\n", 31311cb0ef41Sopenharmony_ci nghttp2_buf_len(&framebufs->cur->buf)); 31321cb0ef41Sopenharmony_ci 31331cb0ef41Sopenharmony_ci return; 31341cb0ef41Sopenharmony_ci } 31351cb0ef41Sopenharmony_ci } 31361cb0ef41Sopenharmony_ci 31371cb0ef41Sopenharmony_ci active_outbound_item_reset(&session->aob, mem); 31381cb0ef41Sopenharmony_ci 31391cb0ef41Sopenharmony_ci return; 31401cb0ef41Sopenharmony_ci } 31411cb0ef41Sopenharmony_ci 31421cb0ef41Sopenharmony_ci /* DATA frame */ 31431cb0ef41Sopenharmony_ci 31441cb0ef41Sopenharmony_ci aux_data = &item->aux_data.data; 31451cb0ef41Sopenharmony_ci 31461cb0ef41Sopenharmony_ci /* On EOF, we have already detached data. Please note that 31471cb0ef41Sopenharmony_ci application may issue nghttp2_submit_data() in 31481cb0ef41Sopenharmony_ci on_frame_send_callback (call from session_after_frame_sent1), 31491cb0ef41Sopenharmony_ci which attach data to stream. We don't want to detach it. */ 31501cb0ef41Sopenharmony_ci if (aux_data->eof) { 31511cb0ef41Sopenharmony_ci active_outbound_item_reset(aob, mem); 31521cb0ef41Sopenharmony_ci 31531cb0ef41Sopenharmony_ci return; 31541cb0ef41Sopenharmony_ci } 31551cb0ef41Sopenharmony_ci 31561cb0ef41Sopenharmony_ci /* Reset no_copy here because next write may not use this. */ 31571cb0ef41Sopenharmony_ci aux_data->no_copy = 0; 31581cb0ef41Sopenharmony_ci 31591cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 31601cb0ef41Sopenharmony_ci 31611cb0ef41Sopenharmony_ci /* If session is closed or RST_STREAM was queued, we won't send 31621cb0ef41Sopenharmony_ci further data. */ 31631cb0ef41Sopenharmony_ci if (nghttp2_session_predicate_data_send(session, stream) != 0) { 31641cb0ef41Sopenharmony_ci if (stream) { 31651cb0ef41Sopenharmony_ci session_detach_stream_item(session, stream); 31661cb0ef41Sopenharmony_ci } 31671cb0ef41Sopenharmony_ci 31681cb0ef41Sopenharmony_ci active_outbound_item_reset(aob, mem); 31691cb0ef41Sopenharmony_ci 31701cb0ef41Sopenharmony_ci return; 31711cb0ef41Sopenharmony_ci } 31721cb0ef41Sopenharmony_ci 31731cb0ef41Sopenharmony_ci aob->item = NULL; 31741cb0ef41Sopenharmony_ci active_outbound_item_reset(&session->aob, mem); 31751cb0ef41Sopenharmony_ci 31761cb0ef41Sopenharmony_ci return; 31771cb0ef41Sopenharmony_ci} 31781cb0ef41Sopenharmony_ci 31791cb0ef41Sopenharmony_cistatic int session_call_send_data(nghttp2_session *session, 31801cb0ef41Sopenharmony_ci nghttp2_outbound_item *item, 31811cb0ef41Sopenharmony_ci nghttp2_bufs *framebufs) { 31821cb0ef41Sopenharmony_ci int rv; 31831cb0ef41Sopenharmony_ci nghttp2_buf *buf; 31841cb0ef41Sopenharmony_ci size_t length; 31851cb0ef41Sopenharmony_ci nghttp2_frame *frame; 31861cb0ef41Sopenharmony_ci nghttp2_data_aux_data *aux_data; 31871cb0ef41Sopenharmony_ci 31881cb0ef41Sopenharmony_ci buf = &framebufs->cur->buf; 31891cb0ef41Sopenharmony_ci frame = &item->frame; 31901cb0ef41Sopenharmony_ci length = frame->hd.length - frame->data.padlen; 31911cb0ef41Sopenharmony_ci aux_data = &item->aux_data.data; 31921cb0ef41Sopenharmony_ci 31931cb0ef41Sopenharmony_ci rv = session->callbacks.send_data_callback(session, frame, buf->pos, length, 31941cb0ef41Sopenharmony_ci &aux_data->data_prd.source, 31951cb0ef41Sopenharmony_ci session->user_data); 31961cb0ef41Sopenharmony_ci 31971cb0ef41Sopenharmony_ci switch (rv) { 31981cb0ef41Sopenharmony_ci case 0: 31991cb0ef41Sopenharmony_ci case NGHTTP2_ERR_WOULDBLOCK: 32001cb0ef41Sopenharmony_ci case NGHTTP2_ERR_PAUSE: 32011cb0ef41Sopenharmony_ci case NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE: 32021cb0ef41Sopenharmony_ci return rv; 32031cb0ef41Sopenharmony_ci default: 32041cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 32051cb0ef41Sopenharmony_ci } 32061cb0ef41Sopenharmony_ci} 32071cb0ef41Sopenharmony_ci 32081cb0ef41Sopenharmony_cistatic ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, 32091cb0ef41Sopenharmony_ci const uint8_t **data_ptr, 32101cb0ef41Sopenharmony_ci int fast_cb) { 32111cb0ef41Sopenharmony_ci int rv; 32121cb0ef41Sopenharmony_ci nghttp2_active_outbound_item *aob; 32131cb0ef41Sopenharmony_ci nghttp2_bufs *framebufs; 32141cb0ef41Sopenharmony_ci nghttp2_mem *mem; 32151cb0ef41Sopenharmony_ci 32161cb0ef41Sopenharmony_ci mem = &session->mem; 32171cb0ef41Sopenharmony_ci aob = &session->aob; 32181cb0ef41Sopenharmony_ci framebufs = &aob->framebufs; 32191cb0ef41Sopenharmony_ci 32201cb0ef41Sopenharmony_ci /* We may have idle streams more than we expect (e.g., 32211cb0ef41Sopenharmony_ci nghttp2_session_change_stream_priority() or 32221cb0ef41Sopenharmony_ci nghttp2_session_create_idle_stream()). Adjust them here. */ 32231cb0ef41Sopenharmony_ci rv = nghttp2_session_adjust_idle_stream(session); 32241cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 32251cb0ef41Sopenharmony_ci return rv; 32261cb0ef41Sopenharmony_ci } 32271cb0ef41Sopenharmony_ci 32281cb0ef41Sopenharmony_ci for (;;) { 32291cb0ef41Sopenharmony_ci switch (aob->state) { 32301cb0ef41Sopenharmony_ci case NGHTTP2_OB_POP_ITEM: { 32311cb0ef41Sopenharmony_ci nghttp2_outbound_item *item; 32321cb0ef41Sopenharmony_ci 32331cb0ef41Sopenharmony_ci item = nghttp2_session_pop_next_ob_item(session); 32341cb0ef41Sopenharmony_ci if (item == NULL) { 32351cb0ef41Sopenharmony_ci return 0; 32361cb0ef41Sopenharmony_ci } 32371cb0ef41Sopenharmony_ci 32381cb0ef41Sopenharmony_ci rv = session_prep_frame(session, item); 32391cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_PAUSE) { 32401cb0ef41Sopenharmony_ci return 0; 32411cb0ef41Sopenharmony_ci } 32421cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_DEFERRED) { 32431cb0ef41Sopenharmony_ci DEBUGF("send: frame transmission deferred\n"); 32441cb0ef41Sopenharmony_ci break; 32451cb0ef41Sopenharmony_ci } 32461cb0ef41Sopenharmony_ci if (rv < 0) { 32471cb0ef41Sopenharmony_ci int32_t opened_stream_id = 0; 32481cb0ef41Sopenharmony_ci uint32_t error_code = NGHTTP2_INTERNAL_ERROR; 32491cb0ef41Sopenharmony_ci int rv2 = 0; 32501cb0ef41Sopenharmony_ci 32511cb0ef41Sopenharmony_ci DEBUGF("send: frame preparation failed with %s\n", 32521cb0ef41Sopenharmony_ci nghttp2_strerror(rv)); 32531cb0ef41Sopenharmony_ci /* TODO If the error comes from compressor, the connection 32541cb0ef41Sopenharmony_ci must be closed. */ 32551cb0ef41Sopenharmony_ci if (item->frame.hd.type != NGHTTP2_DATA && 32561cb0ef41Sopenharmony_ci session->callbacks.on_frame_not_send_callback && is_non_fatal(rv)) { 32571cb0ef41Sopenharmony_ci nghttp2_frame *frame = &item->frame; 32581cb0ef41Sopenharmony_ci /* The library is responsible for the transmission of 32591cb0ef41Sopenharmony_ci WINDOW_UPDATE frame, so we don't call error callback for 32601cb0ef41Sopenharmony_ci it. */ 32611cb0ef41Sopenharmony_ci if (frame->hd.type != NGHTTP2_WINDOW_UPDATE && 32621cb0ef41Sopenharmony_ci session->callbacks.on_frame_not_send_callback( 32631cb0ef41Sopenharmony_ci session, frame, rv, session->user_data) != 0) { 32641cb0ef41Sopenharmony_ci 32651cb0ef41Sopenharmony_ci nghttp2_outbound_item_free(item, mem); 32661cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, item); 32671cb0ef41Sopenharmony_ci 32681cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 32691cb0ef41Sopenharmony_ci } 32701cb0ef41Sopenharmony_ci } 32711cb0ef41Sopenharmony_ci /* We have to close stream opened by failed request HEADERS 32721cb0ef41Sopenharmony_ci or PUSH_PROMISE. */ 32731cb0ef41Sopenharmony_ci switch (item->frame.hd.type) { 32741cb0ef41Sopenharmony_ci case NGHTTP2_HEADERS: 32751cb0ef41Sopenharmony_ci if (item->frame.headers.cat == NGHTTP2_HCAT_REQUEST) { 32761cb0ef41Sopenharmony_ci opened_stream_id = item->frame.hd.stream_id; 32771cb0ef41Sopenharmony_ci if (item->aux_data.headers.canceled) { 32781cb0ef41Sopenharmony_ci error_code = item->aux_data.headers.error_code; 32791cb0ef41Sopenharmony_ci } else { 32801cb0ef41Sopenharmony_ci /* Set error_code to REFUSED_STREAM so that application 32811cb0ef41Sopenharmony_ci can send request again. */ 32821cb0ef41Sopenharmony_ci error_code = NGHTTP2_REFUSED_STREAM; 32831cb0ef41Sopenharmony_ci } 32841cb0ef41Sopenharmony_ci } 32851cb0ef41Sopenharmony_ci break; 32861cb0ef41Sopenharmony_ci case NGHTTP2_PUSH_PROMISE: 32871cb0ef41Sopenharmony_ci opened_stream_id = item->frame.push_promise.promised_stream_id; 32881cb0ef41Sopenharmony_ci break; 32891cb0ef41Sopenharmony_ci } 32901cb0ef41Sopenharmony_ci if (opened_stream_id) { 32911cb0ef41Sopenharmony_ci /* careful not to override rv */ 32921cb0ef41Sopenharmony_ci rv2 = nghttp2_session_close_stream(session, opened_stream_id, 32931cb0ef41Sopenharmony_ci error_code); 32941cb0ef41Sopenharmony_ci } 32951cb0ef41Sopenharmony_ci 32961cb0ef41Sopenharmony_ci nghttp2_outbound_item_free(item, mem); 32971cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, item); 32981cb0ef41Sopenharmony_ci active_outbound_item_reset(aob, mem); 32991cb0ef41Sopenharmony_ci 33001cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv2)) { 33011cb0ef41Sopenharmony_ci return rv2; 33021cb0ef41Sopenharmony_ci } 33031cb0ef41Sopenharmony_ci 33041cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_HEADER_COMP) { 33051cb0ef41Sopenharmony_ci /* If header compression error occurred, should terminiate 33061cb0ef41Sopenharmony_ci connection. */ 33071cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session(session, 33081cb0ef41Sopenharmony_ci NGHTTP2_INTERNAL_ERROR); 33091cb0ef41Sopenharmony_ci } 33101cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 33111cb0ef41Sopenharmony_ci return rv; 33121cb0ef41Sopenharmony_ci } 33131cb0ef41Sopenharmony_ci break; 33141cb0ef41Sopenharmony_ci } 33151cb0ef41Sopenharmony_ci 33161cb0ef41Sopenharmony_ci aob->item = item; 33171cb0ef41Sopenharmony_ci 33181cb0ef41Sopenharmony_ci nghttp2_bufs_rewind(framebufs); 33191cb0ef41Sopenharmony_ci 33201cb0ef41Sopenharmony_ci if (item->frame.hd.type != NGHTTP2_DATA) { 33211cb0ef41Sopenharmony_ci nghttp2_frame *frame; 33221cb0ef41Sopenharmony_ci 33231cb0ef41Sopenharmony_ci frame = &item->frame; 33241cb0ef41Sopenharmony_ci 33251cb0ef41Sopenharmony_ci DEBUGF("send: next frame: payloadlen=%zu, type=%u, flags=0x%02x, " 33261cb0ef41Sopenharmony_ci "stream_id=%d\n", 33271cb0ef41Sopenharmony_ci frame->hd.length, frame->hd.type, frame->hd.flags, 33281cb0ef41Sopenharmony_ci frame->hd.stream_id); 33291cb0ef41Sopenharmony_ci 33301cb0ef41Sopenharmony_ci rv = session_call_before_frame_send(session, frame); 33311cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 33321cb0ef41Sopenharmony_ci return rv; 33331cb0ef41Sopenharmony_ci } 33341cb0ef41Sopenharmony_ci 33351cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_CANCEL) { 33361cb0ef41Sopenharmony_ci int32_t opened_stream_id = 0; 33371cb0ef41Sopenharmony_ci uint32_t error_code = NGHTTP2_INTERNAL_ERROR; 33381cb0ef41Sopenharmony_ci 33391cb0ef41Sopenharmony_ci if (session->callbacks.on_frame_not_send_callback) { 33401cb0ef41Sopenharmony_ci if (session->callbacks.on_frame_not_send_callback( 33411cb0ef41Sopenharmony_ci session, frame, rv, session->user_data) != 0) { 33421cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 33431cb0ef41Sopenharmony_ci } 33441cb0ef41Sopenharmony_ci } 33451cb0ef41Sopenharmony_ci 33461cb0ef41Sopenharmony_ci /* We have to close stream opened by canceled request 33471cb0ef41Sopenharmony_ci HEADERS or PUSH_PROMISE. */ 33481cb0ef41Sopenharmony_ci switch (item->frame.hd.type) { 33491cb0ef41Sopenharmony_ci case NGHTTP2_HEADERS: 33501cb0ef41Sopenharmony_ci if (item->frame.headers.cat == NGHTTP2_HCAT_REQUEST) { 33511cb0ef41Sopenharmony_ci opened_stream_id = item->frame.hd.stream_id; 33521cb0ef41Sopenharmony_ci /* We don't have to check 33531cb0ef41Sopenharmony_ci item->aux_data.headers.canceled since it has already 33541cb0ef41Sopenharmony_ci been checked. */ 33551cb0ef41Sopenharmony_ci /* Set error_code to REFUSED_STREAM so that application 33561cb0ef41Sopenharmony_ci can send request again. */ 33571cb0ef41Sopenharmony_ci error_code = NGHTTP2_REFUSED_STREAM; 33581cb0ef41Sopenharmony_ci } 33591cb0ef41Sopenharmony_ci break; 33601cb0ef41Sopenharmony_ci case NGHTTP2_PUSH_PROMISE: 33611cb0ef41Sopenharmony_ci opened_stream_id = item->frame.push_promise.promised_stream_id; 33621cb0ef41Sopenharmony_ci break; 33631cb0ef41Sopenharmony_ci } 33641cb0ef41Sopenharmony_ci if (opened_stream_id) { 33651cb0ef41Sopenharmony_ci /* careful not to override rv */ 33661cb0ef41Sopenharmony_ci int rv2; 33671cb0ef41Sopenharmony_ci rv2 = nghttp2_session_close_stream(session, opened_stream_id, 33681cb0ef41Sopenharmony_ci error_code); 33691cb0ef41Sopenharmony_ci 33701cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv2)) { 33711cb0ef41Sopenharmony_ci return rv2; 33721cb0ef41Sopenharmony_ci } 33731cb0ef41Sopenharmony_ci } 33741cb0ef41Sopenharmony_ci 33751cb0ef41Sopenharmony_ci active_outbound_item_reset(aob, mem); 33761cb0ef41Sopenharmony_ci 33771cb0ef41Sopenharmony_ci break; 33781cb0ef41Sopenharmony_ci } 33791cb0ef41Sopenharmony_ci } else { 33801cb0ef41Sopenharmony_ci DEBUGF("send: next frame: DATA\n"); 33811cb0ef41Sopenharmony_ci 33821cb0ef41Sopenharmony_ci if (item->aux_data.data.no_copy) { 33831cb0ef41Sopenharmony_ci aob->state = NGHTTP2_OB_SEND_NO_COPY; 33841cb0ef41Sopenharmony_ci break; 33851cb0ef41Sopenharmony_ci } 33861cb0ef41Sopenharmony_ci } 33871cb0ef41Sopenharmony_ci 33881cb0ef41Sopenharmony_ci DEBUGF("send: start transmitting frame type=%u, length=%zd\n", 33891cb0ef41Sopenharmony_ci framebufs->cur->buf.pos[3], 33901cb0ef41Sopenharmony_ci framebufs->cur->buf.last - framebufs->cur->buf.pos); 33911cb0ef41Sopenharmony_ci 33921cb0ef41Sopenharmony_ci aob->state = NGHTTP2_OB_SEND_DATA; 33931cb0ef41Sopenharmony_ci 33941cb0ef41Sopenharmony_ci break; 33951cb0ef41Sopenharmony_ci } 33961cb0ef41Sopenharmony_ci case NGHTTP2_OB_SEND_DATA: { 33971cb0ef41Sopenharmony_ci size_t datalen; 33981cb0ef41Sopenharmony_ci nghttp2_buf *buf; 33991cb0ef41Sopenharmony_ci 34001cb0ef41Sopenharmony_ci buf = &framebufs->cur->buf; 34011cb0ef41Sopenharmony_ci 34021cb0ef41Sopenharmony_ci if (buf->pos == buf->last) { 34031cb0ef41Sopenharmony_ci DEBUGF("send: end transmission of a frame\n"); 34041cb0ef41Sopenharmony_ci 34051cb0ef41Sopenharmony_ci /* Frame has completely sent */ 34061cb0ef41Sopenharmony_ci if (fast_cb) { 34071cb0ef41Sopenharmony_ci session_after_frame_sent2(session); 34081cb0ef41Sopenharmony_ci } else { 34091cb0ef41Sopenharmony_ci rv = session_after_frame_sent1(session); 34101cb0ef41Sopenharmony_ci if (rv < 0) { 34111cb0ef41Sopenharmony_ci /* FATAL */ 34121cb0ef41Sopenharmony_ci assert(nghttp2_is_fatal(rv)); 34131cb0ef41Sopenharmony_ci return rv; 34141cb0ef41Sopenharmony_ci } 34151cb0ef41Sopenharmony_ci session_after_frame_sent2(session); 34161cb0ef41Sopenharmony_ci } 34171cb0ef41Sopenharmony_ci /* We have already adjusted the next state */ 34181cb0ef41Sopenharmony_ci break; 34191cb0ef41Sopenharmony_ci } 34201cb0ef41Sopenharmony_ci 34211cb0ef41Sopenharmony_ci *data_ptr = buf->pos; 34221cb0ef41Sopenharmony_ci datalen = nghttp2_buf_len(buf); 34231cb0ef41Sopenharmony_ci 34241cb0ef41Sopenharmony_ci /* We increment the offset here. If send_callback does not send 34251cb0ef41Sopenharmony_ci everything, we will adjust it. */ 34261cb0ef41Sopenharmony_ci buf->pos += datalen; 34271cb0ef41Sopenharmony_ci 34281cb0ef41Sopenharmony_ci return (ssize_t)datalen; 34291cb0ef41Sopenharmony_ci } 34301cb0ef41Sopenharmony_ci case NGHTTP2_OB_SEND_NO_COPY: { 34311cb0ef41Sopenharmony_ci nghttp2_stream *stream; 34321cb0ef41Sopenharmony_ci nghttp2_frame *frame; 34331cb0ef41Sopenharmony_ci int pause; 34341cb0ef41Sopenharmony_ci 34351cb0ef41Sopenharmony_ci DEBUGF("send: no copy DATA\n"); 34361cb0ef41Sopenharmony_ci 34371cb0ef41Sopenharmony_ci frame = &aob->item->frame; 34381cb0ef41Sopenharmony_ci 34391cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 34401cb0ef41Sopenharmony_ci if (stream == NULL) { 34411cb0ef41Sopenharmony_ci DEBUGF("send: no copy DATA cancelled because stream was closed\n"); 34421cb0ef41Sopenharmony_ci 34431cb0ef41Sopenharmony_ci active_outbound_item_reset(aob, mem); 34441cb0ef41Sopenharmony_ci 34451cb0ef41Sopenharmony_ci break; 34461cb0ef41Sopenharmony_ci } 34471cb0ef41Sopenharmony_ci 34481cb0ef41Sopenharmony_ci rv = session_call_send_data(session, aob->item, framebufs); 34491cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 34501cb0ef41Sopenharmony_ci return rv; 34511cb0ef41Sopenharmony_ci } 34521cb0ef41Sopenharmony_ci 34531cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { 34541cb0ef41Sopenharmony_ci session_detach_stream_item(session, stream); 34551cb0ef41Sopenharmony_ci 34561cb0ef41Sopenharmony_ci rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id, 34571cb0ef41Sopenharmony_ci NGHTTP2_INTERNAL_ERROR); 34581cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 34591cb0ef41Sopenharmony_ci return rv; 34601cb0ef41Sopenharmony_ci } 34611cb0ef41Sopenharmony_ci 34621cb0ef41Sopenharmony_ci active_outbound_item_reset(aob, mem); 34631cb0ef41Sopenharmony_ci 34641cb0ef41Sopenharmony_ci break; 34651cb0ef41Sopenharmony_ci } 34661cb0ef41Sopenharmony_ci 34671cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_WOULDBLOCK) { 34681cb0ef41Sopenharmony_ci return 0; 34691cb0ef41Sopenharmony_ci } 34701cb0ef41Sopenharmony_ci 34711cb0ef41Sopenharmony_ci pause = (rv == NGHTTP2_ERR_PAUSE); 34721cb0ef41Sopenharmony_ci 34731cb0ef41Sopenharmony_ci rv = session_after_frame_sent1(session); 34741cb0ef41Sopenharmony_ci if (rv < 0) { 34751cb0ef41Sopenharmony_ci assert(nghttp2_is_fatal(rv)); 34761cb0ef41Sopenharmony_ci return rv; 34771cb0ef41Sopenharmony_ci } 34781cb0ef41Sopenharmony_ci session_after_frame_sent2(session); 34791cb0ef41Sopenharmony_ci 34801cb0ef41Sopenharmony_ci /* We have already adjusted the next state */ 34811cb0ef41Sopenharmony_ci 34821cb0ef41Sopenharmony_ci if (pause) { 34831cb0ef41Sopenharmony_ci return 0; 34841cb0ef41Sopenharmony_ci } 34851cb0ef41Sopenharmony_ci 34861cb0ef41Sopenharmony_ci break; 34871cb0ef41Sopenharmony_ci } 34881cb0ef41Sopenharmony_ci case NGHTTP2_OB_SEND_CLIENT_MAGIC: { 34891cb0ef41Sopenharmony_ci size_t datalen; 34901cb0ef41Sopenharmony_ci nghttp2_buf *buf; 34911cb0ef41Sopenharmony_ci 34921cb0ef41Sopenharmony_ci buf = &framebufs->cur->buf; 34931cb0ef41Sopenharmony_ci 34941cb0ef41Sopenharmony_ci if (buf->pos == buf->last) { 34951cb0ef41Sopenharmony_ci DEBUGF("send: end transmission of client magic\n"); 34961cb0ef41Sopenharmony_ci active_outbound_item_reset(aob, mem); 34971cb0ef41Sopenharmony_ci break; 34981cb0ef41Sopenharmony_ci } 34991cb0ef41Sopenharmony_ci 35001cb0ef41Sopenharmony_ci *data_ptr = buf->pos; 35011cb0ef41Sopenharmony_ci datalen = nghttp2_buf_len(buf); 35021cb0ef41Sopenharmony_ci 35031cb0ef41Sopenharmony_ci buf->pos += datalen; 35041cb0ef41Sopenharmony_ci 35051cb0ef41Sopenharmony_ci return (ssize_t)datalen; 35061cb0ef41Sopenharmony_ci } 35071cb0ef41Sopenharmony_ci } 35081cb0ef41Sopenharmony_ci } 35091cb0ef41Sopenharmony_ci} 35101cb0ef41Sopenharmony_ci 35111cb0ef41Sopenharmony_cissize_t nghttp2_session_mem_send(nghttp2_session *session, 35121cb0ef41Sopenharmony_ci const uint8_t **data_ptr) { 35131cb0ef41Sopenharmony_ci int rv; 35141cb0ef41Sopenharmony_ci ssize_t len; 35151cb0ef41Sopenharmony_ci 35161cb0ef41Sopenharmony_ci *data_ptr = NULL; 35171cb0ef41Sopenharmony_ci 35181cb0ef41Sopenharmony_ci len = nghttp2_session_mem_send_internal(session, data_ptr, 1); 35191cb0ef41Sopenharmony_ci if (len <= 0) { 35201cb0ef41Sopenharmony_ci return len; 35211cb0ef41Sopenharmony_ci } 35221cb0ef41Sopenharmony_ci 35231cb0ef41Sopenharmony_ci if (session->aob.item) { 35241cb0ef41Sopenharmony_ci /* We have to call session_after_frame_sent1 here to handle stream 35251cb0ef41Sopenharmony_ci closure upon transmission of frames. Otherwise, END_STREAM may 35261cb0ef41Sopenharmony_ci be reached to client before we call nghttp2_session_mem_send 35271cb0ef41Sopenharmony_ci again and we may get exceeding number of incoming streams. */ 35281cb0ef41Sopenharmony_ci rv = session_after_frame_sent1(session); 35291cb0ef41Sopenharmony_ci if (rv < 0) { 35301cb0ef41Sopenharmony_ci assert(nghttp2_is_fatal(rv)); 35311cb0ef41Sopenharmony_ci return (ssize_t)rv; 35321cb0ef41Sopenharmony_ci } 35331cb0ef41Sopenharmony_ci } 35341cb0ef41Sopenharmony_ci 35351cb0ef41Sopenharmony_ci return len; 35361cb0ef41Sopenharmony_ci} 35371cb0ef41Sopenharmony_ci 35381cb0ef41Sopenharmony_ciint nghttp2_session_send(nghttp2_session *session) { 35391cb0ef41Sopenharmony_ci const uint8_t *data = NULL; 35401cb0ef41Sopenharmony_ci ssize_t datalen; 35411cb0ef41Sopenharmony_ci ssize_t sentlen; 35421cb0ef41Sopenharmony_ci nghttp2_bufs *framebufs; 35431cb0ef41Sopenharmony_ci 35441cb0ef41Sopenharmony_ci framebufs = &session->aob.framebufs; 35451cb0ef41Sopenharmony_ci 35461cb0ef41Sopenharmony_ci for (;;) { 35471cb0ef41Sopenharmony_ci datalen = nghttp2_session_mem_send_internal(session, &data, 0); 35481cb0ef41Sopenharmony_ci if (datalen <= 0) { 35491cb0ef41Sopenharmony_ci return (int)datalen; 35501cb0ef41Sopenharmony_ci } 35511cb0ef41Sopenharmony_ci sentlen = session->callbacks.send_callback(session, data, (size_t)datalen, 35521cb0ef41Sopenharmony_ci 0, session->user_data); 35531cb0ef41Sopenharmony_ci if (sentlen < 0) { 35541cb0ef41Sopenharmony_ci if (sentlen == NGHTTP2_ERR_WOULDBLOCK) { 35551cb0ef41Sopenharmony_ci /* Transmission canceled. Rewind the offset */ 35561cb0ef41Sopenharmony_ci framebufs->cur->buf.pos -= datalen; 35571cb0ef41Sopenharmony_ci 35581cb0ef41Sopenharmony_ci return 0; 35591cb0ef41Sopenharmony_ci } 35601cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 35611cb0ef41Sopenharmony_ci } 35621cb0ef41Sopenharmony_ci /* Rewind the offset to the amount of unsent bytes */ 35631cb0ef41Sopenharmony_ci framebufs->cur->buf.pos -= datalen - sentlen; 35641cb0ef41Sopenharmony_ci } 35651cb0ef41Sopenharmony_ci} 35661cb0ef41Sopenharmony_ci 35671cb0ef41Sopenharmony_cistatic ssize_t session_recv(nghttp2_session *session, uint8_t *buf, 35681cb0ef41Sopenharmony_ci size_t len) { 35691cb0ef41Sopenharmony_ci ssize_t rv; 35701cb0ef41Sopenharmony_ci rv = session->callbacks.recv_callback(session, buf, len, 0, 35711cb0ef41Sopenharmony_ci session->user_data); 35721cb0ef41Sopenharmony_ci if (rv > 0) { 35731cb0ef41Sopenharmony_ci if ((size_t)rv > len) { 35741cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 35751cb0ef41Sopenharmony_ci } 35761cb0ef41Sopenharmony_ci } else if (rv < 0 && rv != NGHTTP2_ERR_WOULDBLOCK && rv != NGHTTP2_ERR_EOF) { 35771cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 35781cb0ef41Sopenharmony_ci } 35791cb0ef41Sopenharmony_ci return rv; 35801cb0ef41Sopenharmony_ci} 35811cb0ef41Sopenharmony_ci 35821cb0ef41Sopenharmony_cistatic int session_call_on_begin_frame(nghttp2_session *session, 35831cb0ef41Sopenharmony_ci const nghttp2_frame_hd *hd) { 35841cb0ef41Sopenharmony_ci int rv; 35851cb0ef41Sopenharmony_ci 35861cb0ef41Sopenharmony_ci if (session->callbacks.on_begin_frame_callback) { 35871cb0ef41Sopenharmony_ci 35881cb0ef41Sopenharmony_ci rv = session->callbacks.on_begin_frame_callback(session, hd, 35891cb0ef41Sopenharmony_ci session->user_data); 35901cb0ef41Sopenharmony_ci 35911cb0ef41Sopenharmony_ci if (rv != 0) { 35921cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 35931cb0ef41Sopenharmony_ci } 35941cb0ef41Sopenharmony_ci } 35951cb0ef41Sopenharmony_ci 35961cb0ef41Sopenharmony_ci return 0; 35971cb0ef41Sopenharmony_ci} 35981cb0ef41Sopenharmony_ci 35991cb0ef41Sopenharmony_cistatic int session_call_on_frame_received(nghttp2_session *session, 36001cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 36011cb0ef41Sopenharmony_ci int rv; 36021cb0ef41Sopenharmony_ci if (session->callbacks.on_frame_recv_callback) { 36031cb0ef41Sopenharmony_ci rv = session->callbacks.on_frame_recv_callback(session, frame, 36041cb0ef41Sopenharmony_ci session->user_data); 36051cb0ef41Sopenharmony_ci if (rv != 0) { 36061cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 36071cb0ef41Sopenharmony_ci } 36081cb0ef41Sopenharmony_ci } 36091cb0ef41Sopenharmony_ci return 0; 36101cb0ef41Sopenharmony_ci} 36111cb0ef41Sopenharmony_ci 36121cb0ef41Sopenharmony_cistatic int session_call_on_begin_headers(nghttp2_session *session, 36131cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 36141cb0ef41Sopenharmony_ci int rv; 36151cb0ef41Sopenharmony_ci DEBUGF("recv: call on_begin_headers callback stream_id=%d\n", 36161cb0ef41Sopenharmony_ci frame->hd.stream_id); 36171cb0ef41Sopenharmony_ci if (session->callbacks.on_begin_headers_callback) { 36181cb0ef41Sopenharmony_ci rv = session->callbacks.on_begin_headers_callback(session, frame, 36191cb0ef41Sopenharmony_ci session->user_data); 36201cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { 36211cb0ef41Sopenharmony_ci return rv; 36221cb0ef41Sopenharmony_ci } 36231cb0ef41Sopenharmony_ci if (rv != 0) { 36241cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 36251cb0ef41Sopenharmony_ci } 36261cb0ef41Sopenharmony_ci } 36271cb0ef41Sopenharmony_ci return 0; 36281cb0ef41Sopenharmony_ci} 36291cb0ef41Sopenharmony_ci 36301cb0ef41Sopenharmony_cistatic int session_call_on_header(nghttp2_session *session, 36311cb0ef41Sopenharmony_ci const nghttp2_frame *frame, 36321cb0ef41Sopenharmony_ci const nghttp2_hd_nv *nv) { 36331cb0ef41Sopenharmony_ci int rv = 0; 36341cb0ef41Sopenharmony_ci if (session->callbacks.on_header_callback2) { 36351cb0ef41Sopenharmony_ci rv = session->callbacks.on_header_callback2( 36361cb0ef41Sopenharmony_ci session, frame, nv->name, nv->value, nv->flags, session->user_data); 36371cb0ef41Sopenharmony_ci } else if (session->callbacks.on_header_callback) { 36381cb0ef41Sopenharmony_ci rv = session->callbacks.on_header_callback( 36391cb0ef41Sopenharmony_ci session, frame, nv->name->base, nv->name->len, nv->value->base, 36401cb0ef41Sopenharmony_ci nv->value->len, nv->flags, session->user_data); 36411cb0ef41Sopenharmony_ci } 36421cb0ef41Sopenharmony_ci 36431cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_PAUSE || rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { 36441cb0ef41Sopenharmony_ci return rv; 36451cb0ef41Sopenharmony_ci } 36461cb0ef41Sopenharmony_ci if (rv != 0) { 36471cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 36481cb0ef41Sopenharmony_ci } 36491cb0ef41Sopenharmony_ci 36501cb0ef41Sopenharmony_ci return 0; 36511cb0ef41Sopenharmony_ci} 36521cb0ef41Sopenharmony_ci 36531cb0ef41Sopenharmony_cistatic int session_call_on_invalid_header(nghttp2_session *session, 36541cb0ef41Sopenharmony_ci const nghttp2_frame *frame, 36551cb0ef41Sopenharmony_ci const nghttp2_hd_nv *nv) { 36561cb0ef41Sopenharmony_ci int rv; 36571cb0ef41Sopenharmony_ci if (session->callbacks.on_invalid_header_callback2) { 36581cb0ef41Sopenharmony_ci rv = session->callbacks.on_invalid_header_callback2( 36591cb0ef41Sopenharmony_ci session, frame, nv->name, nv->value, nv->flags, session->user_data); 36601cb0ef41Sopenharmony_ci } else if (session->callbacks.on_invalid_header_callback) { 36611cb0ef41Sopenharmony_ci rv = session->callbacks.on_invalid_header_callback( 36621cb0ef41Sopenharmony_ci session, frame, nv->name->base, nv->name->len, nv->value->base, 36631cb0ef41Sopenharmony_ci nv->value->len, nv->flags, session->user_data); 36641cb0ef41Sopenharmony_ci } else { 36651cb0ef41Sopenharmony_ci return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 36661cb0ef41Sopenharmony_ci } 36671cb0ef41Sopenharmony_ci 36681cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_PAUSE || rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { 36691cb0ef41Sopenharmony_ci return rv; 36701cb0ef41Sopenharmony_ci } 36711cb0ef41Sopenharmony_ci if (rv != 0) { 36721cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 36731cb0ef41Sopenharmony_ci } 36741cb0ef41Sopenharmony_ci 36751cb0ef41Sopenharmony_ci return 0; 36761cb0ef41Sopenharmony_ci} 36771cb0ef41Sopenharmony_ci 36781cb0ef41Sopenharmony_cistatic int 36791cb0ef41Sopenharmony_cisession_call_on_extension_chunk_recv_callback(nghttp2_session *session, 36801cb0ef41Sopenharmony_ci const uint8_t *data, size_t len) { 36811cb0ef41Sopenharmony_ci int rv; 36821cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 36831cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 36841cb0ef41Sopenharmony_ci 36851cb0ef41Sopenharmony_ci if (session->callbacks.on_extension_chunk_recv_callback) { 36861cb0ef41Sopenharmony_ci rv = session->callbacks.on_extension_chunk_recv_callback( 36871cb0ef41Sopenharmony_ci session, &frame->hd, data, len, session->user_data); 36881cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_CANCEL) { 36891cb0ef41Sopenharmony_ci return rv; 36901cb0ef41Sopenharmony_ci } 36911cb0ef41Sopenharmony_ci if (rv != 0) { 36921cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 36931cb0ef41Sopenharmony_ci } 36941cb0ef41Sopenharmony_ci } 36951cb0ef41Sopenharmony_ci 36961cb0ef41Sopenharmony_ci return 0; 36971cb0ef41Sopenharmony_ci} 36981cb0ef41Sopenharmony_ci 36991cb0ef41Sopenharmony_cistatic int session_call_unpack_extension_callback(nghttp2_session *session) { 37001cb0ef41Sopenharmony_ci int rv; 37011cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 37021cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 37031cb0ef41Sopenharmony_ci void *payload = NULL; 37041cb0ef41Sopenharmony_ci 37051cb0ef41Sopenharmony_ci rv = session->callbacks.unpack_extension_callback( 37061cb0ef41Sopenharmony_ci session, &payload, &frame->hd, session->user_data); 37071cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_CANCEL) { 37081cb0ef41Sopenharmony_ci return rv; 37091cb0ef41Sopenharmony_ci } 37101cb0ef41Sopenharmony_ci if (rv != 0) { 37111cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 37121cb0ef41Sopenharmony_ci } 37131cb0ef41Sopenharmony_ci 37141cb0ef41Sopenharmony_ci frame->ext.payload = payload; 37151cb0ef41Sopenharmony_ci 37161cb0ef41Sopenharmony_ci return 0; 37171cb0ef41Sopenharmony_ci} 37181cb0ef41Sopenharmony_ci 37191cb0ef41Sopenharmony_ci/* 37201cb0ef41Sopenharmony_ci * Handles frame size error. 37211cb0ef41Sopenharmony_ci * 37221cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 37231cb0ef41Sopenharmony_ci * negative error codes: 37241cb0ef41Sopenharmony_ci * 37251cb0ef41Sopenharmony_ci * NGHTTP2_ERR_NOMEM 37261cb0ef41Sopenharmony_ci * Out of memory. 37271cb0ef41Sopenharmony_ci */ 37281cb0ef41Sopenharmony_cistatic int session_handle_frame_size_error(nghttp2_session *session) { 37291cb0ef41Sopenharmony_ci /* TODO Currently no callback is called for this error, because we 37301cb0ef41Sopenharmony_ci call this callback before reading any payload */ 37311cb0ef41Sopenharmony_ci return nghttp2_session_terminate_session(session, NGHTTP2_FRAME_SIZE_ERROR); 37321cb0ef41Sopenharmony_ci} 37331cb0ef41Sopenharmony_ci 37341cb0ef41Sopenharmony_cistatic uint32_t get_error_code_from_lib_error_code(int lib_error_code) { 37351cb0ef41Sopenharmony_ci switch (lib_error_code) { 37361cb0ef41Sopenharmony_ci case NGHTTP2_ERR_STREAM_CLOSED: 37371cb0ef41Sopenharmony_ci return NGHTTP2_STREAM_CLOSED; 37381cb0ef41Sopenharmony_ci case NGHTTP2_ERR_HEADER_COMP: 37391cb0ef41Sopenharmony_ci return NGHTTP2_COMPRESSION_ERROR; 37401cb0ef41Sopenharmony_ci case NGHTTP2_ERR_FRAME_SIZE_ERROR: 37411cb0ef41Sopenharmony_ci return NGHTTP2_FRAME_SIZE_ERROR; 37421cb0ef41Sopenharmony_ci case NGHTTP2_ERR_FLOW_CONTROL: 37431cb0ef41Sopenharmony_ci return NGHTTP2_FLOW_CONTROL_ERROR; 37441cb0ef41Sopenharmony_ci case NGHTTP2_ERR_REFUSED_STREAM: 37451cb0ef41Sopenharmony_ci return NGHTTP2_REFUSED_STREAM; 37461cb0ef41Sopenharmony_ci case NGHTTP2_ERR_PROTO: 37471cb0ef41Sopenharmony_ci case NGHTTP2_ERR_HTTP_HEADER: 37481cb0ef41Sopenharmony_ci case NGHTTP2_ERR_HTTP_MESSAGING: 37491cb0ef41Sopenharmony_ci return NGHTTP2_PROTOCOL_ERROR; 37501cb0ef41Sopenharmony_ci default: 37511cb0ef41Sopenharmony_ci return NGHTTP2_INTERNAL_ERROR; 37521cb0ef41Sopenharmony_ci } 37531cb0ef41Sopenharmony_ci} 37541cb0ef41Sopenharmony_ci 37551cb0ef41Sopenharmony_ci/* 37561cb0ef41Sopenharmony_ci * Calls on_invalid_frame_recv_callback if it is set to |session|. 37571cb0ef41Sopenharmony_ci * 37581cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 37591cb0ef41Sopenharmony_ci * negative error codes: 37601cb0ef41Sopenharmony_ci * 37611cb0ef41Sopenharmony_ci * NGHTTP2_ERR_CALLBACK_FAILURE 37621cb0ef41Sopenharmony_ci * User defined callback function fails. 37631cb0ef41Sopenharmony_ci */ 37641cb0ef41Sopenharmony_cistatic int session_call_on_invalid_frame_recv_callback(nghttp2_session *session, 37651cb0ef41Sopenharmony_ci nghttp2_frame *frame, 37661cb0ef41Sopenharmony_ci int lib_error_code) { 37671cb0ef41Sopenharmony_ci if (session->callbacks.on_invalid_frame_recv_callback) { 37681cb0ef41Sopenharmony_ci if (session->callbacks.on_invalid_frame_recv_callback( 37691cb0ef41Sopenharmony_ci session, frame, lib_error_code, session->user_data) != 0) { 37701cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 37711cb0ef41Sopenharmony_ci } 37721cb0ef41Sopenharmony_ci } 37731cb0ef41Sopenharmony_ci return 0; 37741cb0ef41Sopenharmony_ci} 37751cb0ef41Sopenharmony_ci 37761cb0ef41Sopenharmony_cistatic int session_handle_invalid_stream2(nghttp2_session *session, 37771cb0ef41Sopenharmony_ci int32_t stream_id, 37781cb0ef41Sopenharmony_ci nghttp2_frame *frame, 37791cb0ef41Sopenharmony_ci int lib_error_code) { 37801cb0ef41Sopenharmony_ci int rv; 37811cb0ef41Sopenharmony_ci rv = nghttp2_session_add_rst_stream( 37821cb0ef41Sopenharmony_ci session, stream_id, get_error_code_from_lib_error_code(lib_error_code)); 37831cb0ef41Sopenharmony_ci if (rv != 0) { 37841cb0ef41Sopenharmony_ci return rv; 37851cb0ef41Sopenharmony_ci } 37861cb0ef41Sopenharmony_ci if (session->callbacks.on_invalid_frame_recv_callback) { 37871cb0ef41Sopenharmony_ci if (session->callbacks.on_invalid_frame_recv_callback( 37881cb0ef41Sopenharmony_ci session, frame, lib_error_code, session->user_data) != 0) { 37891cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 37901cb0ef41Sopenharmony_ci } 37911cb0ef41Sopenharmony_ci } 37921cb0ef41Sopenharmony_ci return 0; 37931cb0ef41Sopenharmony_ci} 37941cb0ef41Sopenharmony_ci 37951cb0ef41Sopenharmony_cistatic int session_handle_invalid_stream(nghttp2_session *session, 37961cb0ef41Sopenharmony_ci nghttp2_frame *frame, 37971cb0ef41Sopenharmony_ci int lib_error_code) { 37981cb0ef41Sopenharmony_ci return session_handle_invalid_stream2(session, frame->hd.stream_id, frame, 37991cb0ef41Sopenharmony_ci lib_error_code); 38001cb0ef41Sopenharmony_ci} 38011cb0ef41Sopenharmony_ci 38021cb0ef41Sopenharmony_cistatic int session_inflate_handle_invalid_stream(nghttp2_session *session, 38031cb0ef41Sopenharmony_ci nghttp2_frame *frame, 38041cb0ef41Sopenharmony_ci int lib_error_code) { 38051cb0ef41Sopenharmony_ci int rv; 38061cb0ef41Sopenharmony_ci rv = session_handle_invalid_stream(session, frame, lib_error_code); 38071cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 38081cb0ef41Sopenharmony_ci return rv; 38091cb0ef41Sopenharmony_ci } 38101cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_HEADER_BLOCK; 38111cb0ef41Sopenharmony_ci} 38121cb0ef41Sopenharmony_ci 38131cb0ef41Sopenharmony_ci/* 38141cb0ef41Sopenharmony_ci * Handles invalid frame which causes connection error. 38151cb0ef41Sopenharmony_ci */ 38161cb0ef41Sopenharmony_cistatic int session_handle_invalid_connection(nghttp2_session *session, 38171cb0ef41Sopenharmony_ci nghttp2_frame *frame, 38181cb0ef41Sopenharmony_ci int lib_error_code, 38191cb0ef41Sopenharmony_ci const char *reason) { 38201cb0ef41Sopenharmony_ci if (session->callbacks.on_invalid_frame_recv_callback) { 38211cb0ef41Sopenharmony_ci if (session->callbacks.on_invalid_frame_recv_callback( 38221cb0ef41Sopenharmony_ci session, frame, lib_error_code, session->user_data) != 0) { 38231cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 38241cb0ef41Sopenharmony_ci } 38251cb0ef41Sopenharmony_ci } 38261cb0ef41Sopenharmony_ci return nghttp2_session_terminate_session_with_reason( 38271cb0ef41Sopenharmony_ci session, get_error_code_from_lib_error_code(lib_error_code), reason); 38281cb0ef41Sopenharmony_ci} 38291cb0ef41Sopenharmony_ci 38301cb0ef41Sopenharmony_cistatic int session_inflate_handle_invalid_connection(nghttp2_session *session, 38311cb0ef41Sopenharmony_ci nghttp2_frame *frame, 38321cb0ef41Sopenharmony_ci int lib_error_code, 38331cb0ef41Sopenharmony_ci const char *reason) { 38341cb0ef41Sopenharmony_ci int rv; 38351cb0ef41Sopenharmony_ci rv = 38361cb0ef41Sopenharmony_ci session_handle_invalid_connection(session, frame, lib_error_code, reason); 38371cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 38381cb0ef41Sopenharmony_ci return rv; 38391cb0ef41Sopenharmony_ci } 38401cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_HEADER_BLOCK; 38411cb0ef41Sopenharmony_ci} 38421cb0ef41Sopenharmony_ci 38431cb0ef41Sopenharmony_ci/* 38441cb0ef41Sopenharmony_ci * Inflates header block in the memory pointed by |in| with |inlen| 38451cb0ef41Sopenharmony_ci * bytes. If this function returns NGHTTP2_ERR_PAUSE, the caller must 38461cb0ef41Sopenharmony_ci * call this function again, until it returns 0 or one of negative 38471cb0ef41Sopenharmony_ci * error code. If |call_header_cb| is zero, the on_header_callback 38481cb0ef41Sopenharmony_ci * are not invoked and the function never return NGHTTP2_ERR_PAUSE. If 38491cb0ef41Sopenharmony_ci * the given |in| is the last chunk of header block, the |final| must 38501cb0ef41Sopenharmony_ci * be nonzero. If header block is successfully processed (which is 38511cb0ef41Sopenharmony_ci * indicated by the return value 0, NGHTTP2_ERR_PAUSE or 38521cb0ef41Sopenharmony_ci * NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE), the number of processed 38531cb0ef41Sopenharmony_ci * input bytes is assigned to the |*readlen_ptr|. 38541cb0ef41Sopenharmony_ci * 38551cb0ef41Sopenharmony_ci * This function return 0 if it succeeds, or one of the negative error 38561cb0ef41Sopenharmony_ci * codes: 38571cb0ef41Sopenharmony_ci * 38581cb0ef41Sopenharmony_ci * NGHTTP2_ERR_CALLBACK_FAILURE 38591cb0ef41Sopenharmony_ci * The callback function failed. 38601cb0ef41Sopenharmony_ci * NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE 38611cb0ef41Sopenharmony_ci * The callback returns this error code, indicating that this 38621cb0ef41Sopenharmony_ci * stream should be RST_STREAMed. 38631cb0ef41Sopenharmony_ci * NGHTTP2_ERR_NOMEM 38641cb0ef41Sopenharmony_ci * Out of memory. 38651cb0ef41Sopenharmony_ci * NGHTTP2_ERR_PAUSE 38661cb0ef41Sopenharmony_ci * The callback function returned NGHTTP2_ERR_PAUSE 38671cb0ef41Sopenharmony_ci * NGHTTP2_ERR_HEADER_COMP 38681cb0ef41Sopenharmony_ci * Header decompression failed 38691cb0ef41Sopenharmony_ci */ 38701cb0ef41Sopenharmony_cistatic int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, 38711cb0ef41Sopenharmony_ci size_t *readlen_ptr, uint8_t *in, size_t inlen, 38721cb0ef41Sopenharmony_ci int final, int call_header_cb) { 38731cb0ef41Sopenharmony_ci ssize_t proclen; 38741cb0ef41Sopenharmony_ci int rv; 38751cb0ef41Sopenharmony_ci int inflate_flags; 38761cb0ef41Sopenharmony_ci nghttp2_hd_nv nv; 38771cb0ef41Sopenharmony_ci nghttp2_stream *stream; 38781cb0ef41Sopenharmony_ci nghttp2_stream *subject_stream; 38791cb0ef41Sopenharmony_ci int trailer = 0; 38801cb0ef41Sopenharmony_ci 38811cb0ef41Sopenharmony_ci *readlen_ptr = 0; 38821cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 38831cb0ef41Sopenharmony_ci 38841cb0ef41Sopenharmony_ci if (frame->hd.type == NGHTTP2_PUSH_PROMISE) { 38851cb0ef41Sopenharmony_ci subject_stream = nghttp2_session_get_stream( 38861cb0ef41Sopenharmony_ci session, frame->push_promise.promised_stream_id); 38871cb0ef41Sopenharmony_ci } else { 38881cb0ef41Sopenharmony_ci subject_stream = stream; 38891cb0ef41Sopenharmony_ci trailer = session_trailer_headers(session, stream, frame); 38901cb0ef41Sopenharmony_ci } 38911cb0ef41Sopenharmony_ci 38921cb0ef41Sopenharmony_ci DEBUGF("recv: decoding header block %zu bytes\n", inlen); 38931cb0ef41Sopenharmony_ci for (;;) { 38941cb0ef41Sopenharmony_ci inflate_flags = 0; 38951cb0ef41Sopenharmony_ci proclen = nghttp2_hd_inflate_hd_nv(&session->hd_inflater, &nv, 38961cb0ef41Sopenharmony_ci &inflate_flags, in, inlen, final); 38971cb0ef41Sopenharmony_ci if (nghttp2_is_fatal((int)proclen)) { 38981cb0ef41Sopenharmony_ci return (int)proclen; 38991cb0ef41Sopenharmony_ci } 39001cb0ef41Sopenharmony_ci if (proclen < 0) { 39011cb0ef41Sopenharmony_ci if (session->iframe.state == NGHTTP2_IB_READ_HEADER_BLOCK) { 39021cb0ef41Sopenharmony_ci if (subject_stream && subject_stream->state != NGHTTP2_STREAM_CLOSING) { 39031cb0ef41Sopenharmony_ci /* Adding RST_STREAM here is very important. It prevents 39041cb0ef41Sopenharmony_ci from invoking subsequent callbacks for the same stream 39051cb0ef41Sopenharmony_ci ID. */ 39061cb0ef41Sopenharmony_ci rv = nghttp2_session_add_rst_stream( 39071cb0ef41Sopenharmony_ci session, subject_stream->stream_id, NGHTTP2_COMPRESSION_ERROR); 39081cb0ef41Sopenharmony_ci 39091cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 39101cb0ef41Sopenharmony_ci return rv; 39111cb0ef41Sopenharmony_ci } 39121cb0ef41Sopenharmony_ci } 39131cb0ef41Sopenharmony_ci } 39141cb0ef41Sopenharmony_ci rv = 39151cb0ef41Sopenharmony_ci nghttp2_session_terminate_session(session, NGHTTP2_COMPRESSION_ERROR); 39161cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 39171cb0ef41Sopenharmony_ci return rv; 39181cb0ef41Sopenharmony_ci } 39191cb0ef41Sopenharmony_ci 39201cb0ef41Sopenharmony_ci return NGHTTP2_ERR_HEADER_COMP; 39211cb0ef41Sopenharmony_ci } 39221cb0ef41Sopenharmony_ci in += proclen; 39231cb0ef41Sopenharmony_ci inlen -= (size_t)proclen; 39241cb0ef41Sopenharmony_ci *readlen_ptr += (size_t)proclen; 39251cb0ef41Sopenharmony_ci 39261cb0ef41Sopenharmony_ci DEBUGF("recv: proclen=%zd\n", proclen); 39271cb0ef41Sopenharmony_ci 39281cb0ef41Sopenharmony_ci if (call_header_cb && (inflate_flags & NGHTTP2_HD_INFLATE_EMIT)) { 39291cb0ef41Sopenharmony_ci rv = 0; 39301cb0ef41Sopenharmony_ci if (subject_stream) { 39311cb0ef41Sopenharmony_ci if (session_enforce_http_messaging(session)) { 39321cb0ef41Sopenharmony_ci rv = nghttp2_http_on_header(session, subject_stream, frame, &nv, 39331cb0ef41Sopenharmony_ci trailer); 39341cb0ef41Sopenharmony_ci 39351cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_IGN_HTTP_HEADER) { 39361cb0ef41Sopenharmony_ci /* Don't overwrite rv here */ 39371cb0ef41Sopenharmony_ci int rv2; 39381cb0ef41Sopenharmony_ci 39391cb0ef41Sopenharmony_ci rv2 = session_call_on_invalid_header(session, frame, &nv); 39401cb0ef41Sopenharmony_ci if (rv2 == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { 39411cb0ef41Sopenharmony_ci rv = NGHTTP2_ERR_HTTP_HEADER; 39421cb0ef41Sopenharmony_ci } else { 39431cb0ef41Sopenharmony_ci if (rv2 != 0) { 39441cb0ef41Sopenharmony_ci return rv2; 39451cb0ef41Sopenharmony_ci } 39461cb0ef41Sopenharmony_ci 39471cb0ef41Sopenharmony_ci /* header is ignored */ 39481cb0ef41Sopenharmony_ci DEBUGF("recv: HTTP ignored: type=%u, id=%d, header %.*s: %.*s\n", 39491cb0ef41Sopenharmony_ci frame->hd.type, frame->hd.stream_id, (int)nv.name->len, 39501cb0ef41Sopenharmony_ci nv.name->base, (int)nv.value->len, nv.value->base); 39511cb0ef41Sopenharmony_ci 39521cb0ef41Sopenharmony_ci rv2 = session_call_error_callback( 39531cb0ef41Sopenharmony_ci session, NGHTTP2_ERR_HTTP_HEADER, 39541cb0ef41Sopenharmony_ci "Ignoring received invalid HTTP header field: frame type: " 39551cb0ef41Sopenharmony_ci "%u, stream: %d, name: [%.*s], value: [%.*s]", 39561cb0ef41Sopenharmony_ci frame->hd.type, frame->hd.stream_id, (int)nv.name->len, 39571cb0ef41Sopenharmony_ci nv.name->base, (int)nv.value->len, nv.value->base); 39581cb0ef41Sopenharmony_ci 39591cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv2)) { 39601cb0ef41Sopenharmony_ci return rv2; 39611cb0ef41Sopenharmony_ci } 39621cb0ef41Sopenharmony_ci } 39631cb0ef41Sopenharmony_ci } 39641cb0ef41Sopenharmony_ci 39651cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_HTTP_HEADER) { 39661cb0ef41Sopenharmony_ci DEBUGF("recv: HTTP error: type=%u, id=%d, header %.*s: %.*s\n", 39671cb0ef41Sopenharmony_ci frame->hd.type, frame->hd.stream_id, (int)nv.name->len, 39681cb0ef41Sopenharmony_ci nv.name->base, (int)nv.value->len, nv.value->base); 39691cb0ef41Sopenharmony_ci 39701cb0ef41Sopenharmony_ci rv = session_call_error_callback( 39711cb0ef41Sopenharmony_ci session, NGHTTP2_ERR_HTTP_HEADER, 39721cb0ef41Sopenharmony_ci "Invalid HTTP header field was received: frame type: " 39731cb0ef41Sopenharmony_ci "%u, stream: %d, name: [%.*s], value: [%.*s]", 39741cb0ef41Sopenharmony_ci frame->hd.type, frame->hd.stream_id, (int)nv.name->len, 39751cb0ef41Sopenharmony_ci nv.name->base, (int)nv.value->len, nv.value->base); 39761cb0ef41Sopenharmony_ci 39771cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 39781cb0ef41Sopenharmony_ci return rv; 39791cb0ef41Sopenharmony_ci } 39801cb0ef41Sopenharmony_ci 39811cb0ef41Sopenharmony_ci rv = session_handle_invalid_stream2(session, 39821cb0ef41Sopenharmony_ci subject_stream->stream_id, 39831cb0ef41Sopenharmony_ci frame, NGHTTP2_ERR_HTTP_HEADER); 39841cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 39851cb0ef41Sopenharmony_ci return rv; 39861cb0ef41Sopenharmony_ci } 39871cb0ef41Sopenharmony_ci return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 39881cb0ef41Sopenharmony_ci } 39891cb0ef41Sopenharmony_ci } 39901cb0ef41Sopenharmony_ci if (rv == 0) { 39911cb0ef41Sopenharmony_ci rv = session_call_on_header(session, frame, &nv); 39921cb0ef41Sopenharmony_ci /* This handles NGHTTP2_ERR_PAUSE and 39931cb0ef41Sopenharmony_ci NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE as well */ 39941cb0ef41Sopenharmony_ci if (rv != 0) { 39951cb0ef41Sopenharmony_ci return rv; 39961cb0ef41Sopenharmony_ci } 39971cb0ef41Sopenharmony_ci } 39981cb0ef41Sopenharmony_ci } 39991cb0ef41Sopenharmony_ci } 40001cb0ef41Sopenharmony_ci if (inflate_flags & NGHTTP2_HD_INFLATE_FINAL) { 40011cb0ef41Sopenharmony_ci nghttp2_hd_inflate_end_headers(&session->hd_inflater); 40021cb0ef41Sopenharmony_ci break; 40031cb0ef41Sopenharmony_ci } 40041cb0ef41Sopenharmony_ci if ((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) { 40051cb0ef41Sopenharmony_ci break; 40061cb0ef41Sopenharmony_ci } 40071cb0ef41Sopenharmony_ci } 40081cb0ef41Sopenharmony_ci return 0; 40091cb0ef41Sopenharmony_ci} 40101cb0ef41Sopenharmony_ci 40111cb0ef41Sopenharmony_ci/* 40121cb0ef41Sopenharmony_ci * Call this function when HEADERS frame was completely received. 40131cb0ef41Sopenharmony_ci * 40141cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of negative error 40151cb0ef41Sopenharmony_ci * codes: 40161cb0ef41Sopenharmony_ci * 40171cb0ef41Sopenharmony_ci * NGHTTP2_ERR_CALLBACK_FAILURE 40181cb0ef41Sopenharmony_ci * The callback function failed. 40191cb0ef41Sopenharmony_ci * NGHTTP2_ERR_NOMEM 40201cb0ef41Sopenharmony_ci * Out of memory. 40211cb0ef41Sopenharmony_ci */ 40221cb0ef41Sopenharmony_cistatic int session_end_stream_headers_received(nghttp2_session *session, 40231cb0ef41Sopenharmony_ci nghttp2_frame *frame, 40241cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 40251cb0ef41Sopenharmony_ci int rv; 40261cb0ef41Sopenharmony_ci 40271cb0ef41Sopenharmony_ci assert(frame->hd.type == NGHTTP2_HEADERS); 40281cb0ef41Sopenharmony_ci 40291cb0ef41Sopenharmony_ci if (session->server && session_enforce_http_messaging(session) && 40301cb0ef41Sopenharmony_ci frame->headers.cat == NGHTTP2_HCAT_REQUEST && 40311cb0ef41Sopenharmony_ci (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) && 40321cb0ef41Sopenharmony_ci !(stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) && 40331cb0ef41Sopenharmony_ci (stream->http_flags & NGHTTP2_HTTP_FLAG_PRIORITY)) { 40341cb0ef41Sopenharmony_ci rv = session_update_stream_priority(session, stream, stream->http_extpri); 40351cb0ef41Sopenharmony_ci if (rv != 0) { 40361cb0ef41Sopenharmony_ci assert(nghttp2_is_fatal(rv)); 40371cb0ef41Sopenharmony_ci return rv; 40381cb0ef41Sopenharmony_ci } 40391cb0ef41Sopenharmony_ci } 40401cb0ef41Sopenharmony_ci 40411cb0ef41Sopenharmony_ci if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) { 40421cb0ef41Sopenharmony_ci return 0; 40431cb0ef41Sopenharmony_ci } 40441cb0ef41Sopenharmony_ci 40451cb0ef41Sopenharmony_ci nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); 40461cb0ef41Sopenharmony_ci rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); 40471cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 40481cb0ef41Sopenharmony_ci return rv; 40491cb0ef41Sopenharmony_ci } 40501cb0ef41Sopenharmony_ci 40511cb0ef41Sopenharmony_ci return 0; 40521cb0ef41Sopenharmony_ci} 40531cb0ef41Sopenharmony_ci 40541cb0ef41Sopenharmony_cistatic int session_after_header_block_received(nghttp2_session *session) { 40551cb0ef41Sopenharmony_ci int rv = 0; 40561cb0ef41Sopenharmony_ci nghttp2_frame *frame = &session->iframe.frame; 40571cb0ef41Sopenharmony_ci nghttp2_stream *stream; 40581cb0ef41Sopenharmony_ci 40591cb0ef41Sopenharmony_ci /* We don't call on_frame_recv_callback if stream has been closed 40601cb0ef41Sopenharmony_ci already or being closed. */ 40611cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 40621cb0ef41Sopenharmony_ci if (!stream || stream->state == NGHTTP2_STREAM_CLOSING) { 40631cb0ef41Sopenharmony_ci return 0; 40641cb0ef41Sopenharmony_ci } 40651cb0ef41Sopenharmony_ci 40661cb0ef41Sopenharmony_ci if (session_enforce_http_messaging(session)) { 40671cb0ef41Sopenharmony_ci if (frame->hd.type == NGHTTP2_PUSH_PROMISE) { 40681cb0ef41Sopenharmony_ci nghttp2_stream *subject_stream; 40691cb0ef41Sopenharmony_ci 40701cb0ef41Sopenharmony_ci subject_stream = nghttp2_session_get_stream( 40711cb0ef41Sopenharmony_ci session, frame->push_promise.promised_stream_id); 40721cb0ef41Sopenharmony_ci if (subject_stream) { 40731cb0ef41Sopenharmony_ci rv = nghttp2_http_on_request_headers(subject_stream, frame); 40741cb0ef41Sopenharmony_ci } 40751cb0ef41Sopenharmony_ci } else { 40761cb0ef41Sopenharmony_ci assert(frame->hd.type == NGHTTP2_HEADERS); 40771cb0ef41Sopenharmony_ci switch (frame->headers.cat) { 40781cb0ef41Sopenharmony_ci case NGHTTP2_HCAT_REQUEST: 40791cb0ef41Sopenharmony_ci rv = nghttp2_http_on_request_headers(stream, frame); 40801cb0ef41Sopenharmony_ci break; 40811cb0ef41Sopenharmony_ci case NGHTTP2_HCAT_RESPONSE: 40821cb0ef41Sopenharmony_ci case NGHTTP2_HCAT_PUSH_RESPONSE: 40831cb0ef41Sopenharmony_ci rv = nghttp2_http_on_response_headers(stream); 40841cb0ef41Sopenharmony_ci break; 40851cb0ef41Sopenharmony_ci case NGHTTP2_HCAT_HEADERS: 40861cb0ef41Sopenharmony_ci if (stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) { 40871cb0ef41Sopenharmony_ci assert(!session->server); 40881cb0ef41Sopenharmony_ci rv = nghttp2_http_on_response_headers(stream); 40891cb0ef41Sopenharmony_ci } else { 40901cb0ef41Sopenharmony_ci rv = nghttp2_http_on_trailer_headers(stream, frame); 40911cb0ef41Sopenharmony_ci } 40921cb0ef41Sopenharmony_ci break; 40931cb0ef41Sopenharmony_ci default: 40941cb0ef41Sopenharmony_ci assert(0); 40951cb0ef41Sopenharmony_ci } 40961cb0ef41Sopenharmony_ci if (rv == 0 && (frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { 40971cb0ef41Sopenharmony_ci rv = nghttp2_http_on_remote_end_stream(stream); 40981cb0ef41Sopenharmony_ci } 40991cb0ef41Sopenharmony_ci } 41001cb0ef41Sopenharmony_ci if (rv != 0) { 41011cb0ef41Sopenharmony_ci int32_t stream_id; 41021cb0ef41Sopenharmony_ci 41031cb0ef41Sopenharmony_ci if (frame->hd.type == NGHTTP2_PUSH_PROMISE) { 41041cb0ef41Sopenharmony_ci stream_id = frame->push_promise.promised_stream_id; 41051cb0ef41Sopenharmony_ci } else { 41061cb0ef41Sopenharmony_ci stream_id = frame->hd.stream_id; 41071cb0ef41Sopenharmony_ci } 41081cb0ef41Sopenharmony_ci 41091cb0ef41Sopenharmony_ci rv = session_handle_invalid_stream2(session, stream_id, frame, 41101cb0ef41Sopenharmony_ci NGHTTP2_ERR_HTTP_MESSAGING); 41111cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 41121cb0ef41Sopenharmony_ci return rv; 41131cb0ef41Sopenharmony_ci } 41141cb0ef41Sopenharmony_ci 41151cb0ef41Sopenharmony_ci if (frame->hd.type == NGHTTP2_HEADERS && 41161cb0ef41Sopenharmony_ci (frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { 41171cb0ef41Sopenharmony_ci nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); 41181cb0ef41Sopenharmony_ci /* Don't call nghttp2_session_close_stream_if_shut_rdwr 41191cb0ef41Sopenharmony_ci because RST_STREAM has been submitted. */ 41201cb0ef41Sopenharmony_ci } 41211cb0ef41Sopenharmony_ci return 0; 41221cb0ef41Sopenharmony_ci } 41231cb0ef41Sopenharmony_ci } 41241cb0ef41Sopenharmony_ci 41251cb0ef41Sopenharmony_ci rv = session_call_on_frame_received(session, frame); 41261cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 41271cb0ef41Sopenharmony_ci return rv; 41281cb0ef41Sopenharmony_ci } 41291cb0ef41Sopenharmony_ci 41301cb0ef41Sopenharmony_ci if (frame->hd.type != NGHTTP2_HEADERS) { 41311cb0ef41Sopenharmony_ci return 0; 41321cb0ef41Sopenharmony_ci } 41331cb0ef41Sopenharmony_ci 41341cb0ef41Sopenharmony_ci return session_end_stream_headers_received(session, frame, stream); 41351cb0ef41Sopenharmony_ci} 41361cb0ef41Sopenharmony_ci 41371cb0ef41Sopenharmony_ciint nghttp2_session_on_request_headers_received(nghttp2_session *session, 41381cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 41391cb0ef41Sopenharmony_ci int rv = 0; 41401cb0ef41Sopenharmony_ci nghttp2_stream *stream; 41411cb0ef41Sopenharmony_ci if (frame->hd.stream_id == 0) { 41421cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 41431cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: stream_id == 0"); 41441cb0ef41Sopenharmony_ci } 41451cb0ef41Sopenharmony_ci 41461cb0ef41Sopenharmony_ci /* If client receives idle stream from server, it is invalid 41471cb0ef41Sopenharmony_ci regardless stream ID is even or odd. This is because client is 41481cb0ef41Sopenharmony_ci not expected to receive request from server. */ 41491cb0ef41Sopenharmony_ci if (!session->server) { 41501cb0ef41Sopenharmony_ci if (session_detect_idle_stream(session, frame->hd.stream_id)) { 41511cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 41521cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 41531cb0ef41Sopenharmony_ci "request HEADERS: client received request"); 41541cb0ef41Sopenharmony_ci } 41551cb0ef41Sopenharmony_ci 41561cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_HEADER_BLOCK; 41571cb0ef41Sopenharmony_ci } 41581cb0ef41Sopenharmony_ci 41591cb0ef41Sopenharmony_ci assert(session->server); 41601cb0ef41Sopenharmony_ci 41611cb0ef41Sopenharmony_ci if (!session_is_new_peer_stream_id(session, frame->hd.stream_id)) { 41621cb0ef41Sopenharmony_ci if (frame->hd.stream_id == 0 || 41631cb0ef41Sopenharmony_ci nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { 41641cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 41651cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 41661cb0ef41Sopenharmony_ci "request HEADERS: invalid stream_id"); 41671cb0ef41Sopenharmony_ci } 41681cb0ef41Sopenharmony_ci 41691cb0ef41Sopenharmony_ci /* RFC 7540 says if an endpoint receives a HEADERS with invalid 41701cb0ef41Sopenharmony_ci * stream ID (e.g, numerically smaller than previous), it MUST 41711cb0ef41Sopenharmony_ci * issue connection error with error code PROTOCOL_ERROR. It is a 41721cb0ef41Sopenharmony_ci * bit hard to detect this, since we cannot remember all streams 41731cb0ef41Sopenharmony_ci * we observed so far. 41741cb0ef41Sopenharmony_ci * 41751cb0ef41Sopenharmony_ci * You might imagine this is really easy. But no. HTTP/2 is 41761cb0ef41Sopenharmony_ci * asynchronous protocol, and usually client and server do not 41771cb0ef41Sopenharmony_ci * share the complete picture of open/closed stream status. For 41781cb0ef41Sopenharmony_ci * example, after server sends RST_STREAM for a stream, client may 41791cb0ef41Sopenharmony_ci * send trailer HEADERS for that stream. If naive server detects 41801cb0ef41Sopenharmony_ci * that, and issued connection error, then it is a bug of server 41811cb0ef41Sopenharmony_ci * implementation since client is not wrong if it did not get 41821cb0ef41Sopenharmony_ci * RST_STREAM when it issued trailer HEADERS. 41831cb0ef41Sopenharmony_ci * 41841cb0ef41Sopenharmony_ci * At the moment, we are very conservative here. We only use 41851cb0ef41Sopenharmony_ci * connection error if stream ID refers idle stream, or we are 41861cb0ef41Sopenharmony_ci * sure that stream is half-closed(remote) or closed. Otherwise 41871cb0ef41Sopenharmony_ci * we just ignore HEADERS for now. 41881cb0ef41Sopenharmony_ci */ 41891cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); 41901cb0ef41Sopenharmony_ci if (stream && (stream->shut_flags & NGHTTP2_SHUT_RD)) { 41911cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 41921cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_STREAM_CLOSED, "HEADERS: stream closed"); 41931cb0ef41Sopenharmony_ci } 41941cb0ef41Sopenharmony_ci 41951cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_HEADER_BLOCK; 41961cb0ef41Sopenharmony_ci } 41971cb0ef41Sopenharmony_ci session->last_recv_stream_id = frame->hd.stream_id; 41981cb0ef41Sopenharmony_ci 41991cb0ef41Sopenharmony_ci if (session_is_incoming_concurrent_streams_max(session)) { 42001cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 42011cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 42021cb0ef41Sopenharmony_ci "request HEADERS: max concurrent streams exceeded"); 42031cb0ef41Sopenharmony_ci } 42041cb0ef41Sopenharmony_ci 42051cb0ef41Sopenharmony_ci if (!session_allow_incoming_new_stream(session)) { 42061cb0ef41Sopenharmony_ci /* We just ignore stream after GOAWAY was sent */ 42071cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_HEADER_BLOCK; 42081cb0ef41Sopenharmony_ci } 42091cb0ef41Sopenharmony_ci 42101cb0ef41Sopenharmony_ci if (frame->headers.pri_spec.stream_id == frame->hd.stream_id) { 42111cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 42121cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, "request HEADERS: depend on itself"); 42131cb0ef41Sopenharmony_ci } 42141cb0ef41Sopenharmony_ci 42151cb0ef41Sopenharmony_ci if (session_is_incoming_concurrent_streams_pending_max(session)) { 42161cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_stream(session, frame, 42171cb0ef41Sopenharmony_ci NGHTTP2_ERR_REFUSED_STREAM); 42181cb0ef41Sopenharmony_ci } 42191cb0ef41Sopenharmony_ci 42201cb0ef41Sopenharmony_ci stream = nghttp2_session_open_stream( 42211cb0ef41Sopenharmony_ci session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, 42221cb0ef41Sopenharmony_ci &frame->headers.pri_spec, NGHTTP2_STREAM_OPENING, NULL); 42231cb0ef41Sopenharmony_ci if (!stream) { 42241cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 42251cb0ef41Sopenharmony_ci } 42261cb0ef41Sopenharmony_ci 42271cb0ef41Sopenharmony_ci rv = nghttp2_session_adjust_closed_stream(session); 42281cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 42291cb0ef41Sopenharmony_ci return rv; 42301cb0ef41Sopenharmony_ci } 42311cb0ef41Sopenharmony_ci 42321cb0ef41Sopenharmony_ci session->last_proc_stream_id = session->last_recv_stream_id; 42331cb0ef41Sopenharmony_ci 42341cb0ef41Sopenharmony_ci rv = session_call_on_begin_headers(session, frame); 42351cb0ef41Sopenharmony_ci if (rv != 0) { 42361cb0ef41Sopenharmony_ci return rv; 42371cb0ef41Sopenharmony_ci } 42381cb0ef41Sopenharmony_ci return 0; 42391cb0ef41Sopenharmony_ci} 42401cb0ef41Sopenharmony_ci 42411cb0ef41Sopenharmony_ciint nghttp2_session_on_response_headers_received(nghttp2_session *session, 42421cb0ef41Sopenharmony_ci nghttp2_frame *frame, 42431cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 42441cb0ef41Sopenharmony_ci int rv; 42451cb0ef41Sopenharmony_ci /* This function is only called if stream->state == 42461cb0ef41Sopenharmony_ci NGHTTP2_STREAM_OPENING and stream_id is local side initiated. */ 42471cb0ef41Sopenharmony_ci assert(stream->state == NGHTTP2_STREAM_OPENING && 42481cb0ef41Sopenharmony_ci nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)); 42491cb0ef41Sopenharmony_ci if (frame->hd.stream_id == 0) { 42501cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 42511cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, "response HEADERS: stream_id == 0"); 42521cb0ef41Sopenharmony_ci } 42531cb0ef41Sopenharmony_ci if (stream->shut_flags & NGHTTP2_SHUT_RD) { 42541cb0ef41Sopenharmony_ci /* half closed (remote): from the spec: 42551cb0ef41Sopenharmony_ci 42561cb0ef41Sopenharmony_ci If an endpoint receives additional frames for a stream that is 42571cb0ef41Sopenharmony_ci in this state it MUST respond with a stream error (Section 42581cb0ef41Sopenharmony_ci 5.4.2) of type STREAM_CLOSED. 42591cb0ef41Sopenharmony_ci 42601cb0ef41Sopenharmony_ci We go further, and make it connection error. 42611cb0ef41Sopenharmony_ci */ 42621cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 42631cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_STREAM_CLOSED, "HEADERS: stream closed"); 42641cb0ef41Sopenharmony_ci } 42651cb0ef41Sopenharmony_ci stream->state = NGHTTP2_STREAM_OPENED; 42661cb0ef41Sopenharmony_ci rv = session_call_on_begin_headers(session, frame); 42671cb0ef41Sopenharmony_ci if (rv != 0) { 42681cb0ef41Sopenharmony_ci return rv; 42691cb0ef41Sopenharmony_ci } 42701cb0ef41Sopenharmony_ci return 0; 42711cb0ef41Sopenharmony_ci} 42721cb0ef41Sopenharmony_ci 42731cb0ef41Sopenharmony_ciint nghttp2_session_on_push_response_headers_received(nghttp2_session *session, 42741cb0ef41Sopenharmony_ci nghttp2_frame *frame, 42751cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 42761cb0ef41Sopenharmony_ci int rv = 0; 42771cb0ef41Sopenharmony_ci assert(stream->state == NGHTTP2_STREAM_RESERVED); 42781cb0ef41Sopenharmony_ci if (frame->hd.stream_id == 0) { 42791cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 42801cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 42811cb0ef41Sopenharmony_ci "push response HEADERS: stream_id == 0"); 42821cb0ef41Sopenharmony_ci } 42831cb0ef41Sopenharmony_ci 42841cb0ef41Sopenharmony_ci if (session->server) { 42851cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 42861cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 42871cb0ef41Sopenharmony_ci "HEADERS: no HEADERS allowed from client in reserved state"); 42881cb0ef41Sopenharmony_ci } 42891cb0ef41Sopenharmony_ci 42901cb0ef41Sopenharmony_ci if (session_is_incoming_concurrent_streams_max(session)) { 42911cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 42921cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 42931cb0ef41Sopenharmony_ci "push response HEADERS: max concurrent streams exceeded"); 42941cb0ef41Sopenharmony_ci } 42951cb0ef41Sopenharmony_ci 42961cb0ef41Sopenharmony_ci if (!session_allow_incoming_new_stream(session)) { 42971cb0ef41Sopenharmony_ci /* We don't accept new stream after GOAWAY was sent. */ 42981cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_HEADER_BLOCK; 42991cb0ef41Sopenharmony_ci } 43001cb0ef41Sopenharmony_ci 43011cb0ef41Sopenharmony_ci if (session_is_incoming_concurrent_streams_pending_max(session)) { 43021cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_stream(session, frame, 43031cb0ef41Sopenharmony_ci NGHTTP2_ERR_REFUSED_STREAM); 43041cb0ef41Sopenharmony_ci } 43051cb0ef41Sopenharmony_ci 43061cb0ef41Sopenharmony_ci nghttp2_stream_promise_fulfilled(stream); 43071cb0ef41Sopenharmony_ci if (!nghttp2_session_is_my_stream_id(session, stream->stream_id)) { 43081cb0ef41Sopenharmony_ci --session->num_incoming_reserved_streams; 43091cb0ef41Sopenharmony_ci } 43101cb0ef41Sopenharmony_ci ++session->num_incoming_streams; 43111cb0ef41Sopenharmony_ci rv = session_call_on_begin_headers(session, frame); 43121cb0ef41Sopenharmony_ci if (rv != 0) { 43131cb0ef41Sopenharmony_ci return rv; 43141cb0ef41Sopenharmony_ci } 43151cb0ef41Sopenharmony_ci return 0; 43161cb0ef41Sopenharmony_ci} 43171cb0ef41Sopenharmony_ci 43181cb0ef41Sopenharmony_ciint nghttp2_session_on_headers_received(nghttp2_session *session, 43191cb0ef41Sopenharmony_ci nghttp2_frame *frame, 43201cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 43211cb0ef41Sopenharmony_ci int rv = 0; 43221cb0ef41Sopenharmony_ci if (frame->hd.stream_id == 0) { 43231cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 43241cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, "HEADERS: stream_id == 0"); 43251cb0ef41Sopenharmony_ci } 43261cb0ef41Sopenharmony_ci if ((stream->shut_flags & NGHTTP2_SHUT_RD)) { 43271cb0ef41Sopenharmony_ci /* half closed (remote): from the spec: 43281cb0ef41Sopenharmony_ci 43291cb0ef41Sopenharmony_ci If an endpoint receives additional frames for a stream that is 43301cb0ef41Sopenharmony_ci in this state it MUST respond with a stream error (Section 43311cb0ef41Sopenharmony_ci 5.4.2) of type STREAM_CLOSED. 43321cb0ef41Sopenharmony_ci 43331cb0ef41Sopenharmony_ci we go further, and make it connection error. 43341cb0ef41Sopenharmony_ci */ 43351cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 43361cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_STREAM_CLOSED, "HEADERS: stream closed"); 43371cb0ef41Sopenharmony_ci } 43381cb0ef41Sopenharmony_ci if (nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { 43391cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_OPENED) { 43401cb0ef41Sopenharmony_ci rv = session_call_on_begin_headers(session, frame); 43411cb0ef41Sopenharmony_ci if (rv != 0) { 43421cb0ef41Sopenharmony_ci return rv; 43431cb0ef41Sopenharmony_ci } 43441cb0ef41Sopenharmony_ci return 0; 43451cb0ef41Sopenharmony_ci } 43461cb0ef41Sopenharmony_ci 43471cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_HEADER_BLOCK; 43481cb0ef41Sopenharmony_ci } 43491cb0ef41Sopenharmony_ci /* If this is remote peer initiated stream, it is OK unless it 43501cb0ef41Sopenharmony_ci has sent END_STREAM frame already. But if stream is in 43511cb0ef41Sopenharmony_ci NGHTTP2_STREAM_CLOSING, we discard the frame. This is a race 43521cb0ef41Sopenharmony_ci condition. */ 43531cb0ef41Sopenharmony_ci if (stream->state != NGHTTP2_STREAM_CLOSING) { 43541cb0ef41Sopenharmony_ci rv = session_call_on_begin_headers(session, frame); 43551cb0ef41Sopenharmony_ci if (rv != 0) { 43561cb0ef41Sopenharmony_ci return rv; 43571cb0ef41Sopenharmony_ci } 43581cb0ef41Sopenharmony_ci return 0; 43591cb0ef41Sopenharmony_ci } 43601cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_HEADER_BLOCK; 43611cb0ef41Sopenharmony_ci} 43621cb0ef41Sopenharmony_ci 43631cb0ef41Sopenharmony_cistatic int session_process_headers_frame(nghttp2_session *session) { 43641cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 43651cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 43661cb0ef41Sopenharmony_ci nghttp2_stream *stream; 43671cb0ef41Sopenharmony_ci 43681cb0ef41Sopenharmony_ci nghttp2_frame_unpack_headers_payload(&frame->headers, iframe->sbuf.pos); 43691cb0ef41Sopenharmony_ci 43701cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 43711cb0ef41Sopenharmony_ci if (!stream) { 43721cb0ef41Sopenharmony_ci frame->headers.cat = NGHTTP2_HCAT_REQUEST; 43731cb0ef41Sopenharmony_ci return nghttp2_session_on_request_headers_received(session, frame); 43741cb0ef41Sopenharmony_ci } 43751cb0ef41Sopenharmony_ci 43761cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_RESERVED) { 43771cb0ef41Sopenharmony_ci frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE; 43781cb0ef41Sopenharmony_ci return nghttp2_session_on_push_response_headers_received(session, frame, 43791cb0ef41Sopenharmony_ci stream); 43801cb0ef41Sopenharmony_ci } 43811cb0ef41Sopenharmony_ci 43821cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_OPENING && 43831cb0ef41Sopenharmony_ci nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { 43841cb0ef41Sopenharmony_ci frame->headers.cat = NGHTTP2_HCAT_RESPONSE; 43851cb0ef41Sopenharmony_ci return nghttp2_session_on_response_headers_received(session, frame, stream); 43861cb0ef41Sopenharmony_ci } 43871cb0ef41Sopenharmony_ci 43881cb0ef41Sopenharmony_ci frame->headers.cat = NGHTTP2_HCAT_HEADERS; 43891cb0ef41Sopenharmony_ci return nghttp2_session_on_headers_received(session, frame, stream); 43901cb0ef41Sopenharmony_ci} 43911cb0ef41Sopenharmony_ci 43921cb0ef41Sopenharmony_ciint nghttp2_session_on_priority_received(nghttp2_session *session, 43931cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 43941cb0ef41Sopenharmony_ci int rv; 43951cb0ef41Sopenharmony_ci nghttp2_stream *stream; 43961cb0ef41Sopenharmony_ci 43971cb0ef41Sopenharmony_ci assert(!session_no_rfc7540_pri_no_fallback(session)); 43981cb0ef41Sopenharmony_ci 43991cb0ef41Sopenharmony_ci if (frame->hd.stream_id == 0) { 44001cb0ef41Sopenharmony_ci return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, 44011cb0ef41Sopenharmony_ci "PRIORITY: stream_id == 0"); 44021cb0ef41Sopenharmony_ci } 44031cb0ef41Sopenharmony_ci 44041cb0ef41Sopenharmony_ci if (frame->priority.pri_spec.stream_id == frame->hd.stream_id) { 44051cb0ef41Sopenharmony_ci return nghttp2_session_terminate_session_with_reason( 44061cb0ef41Sopenharmony_ci session, NGHTTP2_PROTOCOL_ERROR, "depend on itself"); 44071cb0ef41Sopenharmony_ci } 44081cb0ef41Sopenharmony_ci 44091cb0ef41Sopenharmony_ci if (!session->server) { 44101cb0ef41Sopenharmony_ci /* Re-prioritization works only in server */ 44111cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 44121cb0ef41Sopenharmony_ci } 44131cb0ef41Sopenharmony_ci 44141cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); 44151cb0ef41Sopenharmony_ci 44161cb0ef41Sopenharmony_ci if (!stream) { 44171cb0ef41Sopenharmony_ci /* PRIORITY against idle stream can create anchor node in 44181cb0ef41Sopenharmony_ci dependency tree. */ 44191cb0ef41Sopenharmony_ci if (!session_detect_idle_stream(session, frame->hd.stream_id)) { 44201cb0ef41Sopenharmony_ci return 0; 44211cb0ef41Sopenharmony_ci } 44221cb0ef41Sopenharmony_ci 44231cb0ef41Sopenharmony_ci stream = nghttp2_session_open_stream( 44241cb0ef41Sopenharmony_ci session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, 44251cb0ef41Sopenharmony_ci &frame->priority.pri_spec, NGHTTP2_STREAM_IDLE, NULL); 44261cb0ef41Sopenharmony_ci 44271cb0ef41Sopenharmony_ci if (stream == NULL) { 44281cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 44291cb0ef41Sopenharmony_ci } 44301cb0ef41Sopenharmony_ci 44311cb0ef41Sopenharmony_ci rv = nghttp2_session_adjust_idle_stream(session); 44321cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 44331cb0ef41Sopenharmony_ci return rv; 44341cb0ef41Sopenharmony_ci } 44351cb0ef41Sopenharmony_ci } else { 44361cb0ef41Sopenharmony_ci rv = nghttp2_session_reprioritize_stream(session, stream, 44371cb0ef41Sopenharmony_ci &frame->priority.pri_spec); 44381cb0ef41Sopenharmony_ci 44391cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 44401cb0ef41Sopenharmony_ci return rv; 44411cb0ef41Sopenharmony_ci } 44421cb0ef41Sopenharmony_ci 44431cb0ef41Sopenharmony_ci rv = nghttp2_session_adjust_idle_stream(session); 44441cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 44451cb0ef41Sopenharmony_ci return rv; 44461cb0ef41Sopenharmony_ci } 44471cb0ef41Sopenharmony_ci } 44481cb0ef41Sopenharmony_ci 44491cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 44501cb0ef41Sopenharmony_ci} 44511cb0ef41Sopenharmony_ci 44521cb0ef41Sopenharmony_cistatic int session_process_priority_frame(nghttp2_session *session) { 44531cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 44541cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 44551cb0ef41Sopenharmony_ci 44561cb0ef41Sopenharmony_ci assert(!session_no_rfc7540_pri_no_fallback(session)); 44571cb0ef41Sopenharmony_ci 44581cb0ef41Sopenharmony_ci nghttp2_frame_unpack_priority_payload(&frame->priority, iframe->sbuf.pos); 44591cb0ef41Sopenharmony_ci 44601cb0ef41Sopenharmony_ci return nghttp2_session_on_priority_received(session, frame); 44611cb0ef41Sopenharmony_ci} 44621cb0ef41Sopenharmony_ci 44631cb0ef41Sopenharmony_cistatic int session_update_stream_reset_ratelim(nghttp2_session *session) { 44641cb0ef41Sopenharmony_ci if (!session->server || (session->goaway_flags & NGHTTP2_GOAWAY_SUBMITTED)) { 44651cb0ef41Sopenharmony_ci return 0; 44661cb0ef41Sopenharmony_ci } 44671cb0ef41Sopenharmony_ci 44681cb0ef41Sopenharmony_ci nghttp2_ratelim_update(&session->stream_reset_ratelim, 44691cb0ef41Sopenharmony_ci nghttp2_time_now_sec()); 44701cb0ef41Sopenharmony_ci 44711cb0ef41Sopenharmony_ci if (nghttp2_ratelim_drain(&session->stream_reset_ratelim, 1) == 0) { 44721cb0ef41Sopenharmony_ci return 0; 44731cb0ef41Sopenharmony_ci } 44741cb0ef41Sopenharmony_ci 44751cb0ef41Sopenharmony_ci return nghttp2_session_add_goaway(session, session->last_recv_stream_id, 44761cb0ef41Sopenharmony_ci NGHTTP2_INTERNAL_ERROR, NULL, 0, 44771cb0ef41Sopenharmony_ci NGHTTP2_GOAWAY_AUX_NONE); 44781cb0ef41Sopenharmony_ci} 44791cb0ef41Sopenharmony_ci 44801cb0ef41Sopenharmony_ciint nghttp2_session_on_rst_stream_received(nghttp2_session *session, 44811cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 44821cb0ef41Sopenharmony_ci int rv; 44831cb0ef41Sopenharmony_ci nghttp2_stream *stream; 44841cb0ef41Sopenharmony_ci if (frame->hd.stream_id == 0) { 44851cb0ef41Sopenharmony_ci return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, 44861cb0ef41Sopenharmony_ci "RST_STREAM: stream_id == 0"); 44871cb0ef41Sopenharmony_ci } 44881cb0ef41Sopenharmony_ci 44891cb0ef41Sopenharmony_ci if (session_detect_idle_stream(session, frame->hd.stream_id)) { 44901cb0ef41Sopenharmony_ci return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, 44911cb0ef41Sopenharmony_ci "RST_STREAM: stream in idle"); 44921cb0ef41Sopenharmony_ci } 44931cb0ef41Sopenharmony_ci 44941cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 44951cb0ef41Sopenharmony_ci if (stream) { 44961cb0ef41Sopenharmony_ci /* We may use stream->shut_flags for strict error checking. */ 44971cb0ef41Sopenharmony_ci nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); 44981cb0ef41Sopenharmony_ci } 44991cb0ef41Sopenharmony_ci 45001cb0ef41Sopenharmony_ci rv = session_call_on_frame_received(session, frame); 45011cb0ef41Sopenharmony_ci if (rv != 0) { 45021cb0ef41Sopenharmony_ci return rv; 45031cb0ef41Sopenharmony_ci } 45041cb0ef41Sopenharmony_ci rv = nghttp2_session_close_stream(session, frame->hd.stream_id, 45051cb0ef41Sopenharmony_ci frame->rst_stream.error_code); 45061cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 45071cb0ef41Sopenharmony_ci return rv; 45081cb0ef41Sopenharmony_ci } 45091cb0ef41Sopenharmony_ci 45101cb0ef41Sopenharmony_ci return session_update_stream_reset_ratelim(session); 45111cb0ef41Sopenharmony_ci} 45121cb0ef41Sopenharmony_ci 45131cb0ef41Sopenharmony_cistatic int session_process_rst_stream_frame(nghttp2_session *session) { 45141cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 45151cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 45161cb0ef41Sopenharmony_ci 45171cb0ef41Sopenharmony_ci nghttp2_frame_unpack_rst_stream_payload(&frame->rst_stream, iframe->sbuf.pos); 45181cb0ef41Sopenharmony_ci 45191cb0ef41Sopenharmony_ci return nghttp2_session_on_rst_stream_received(session, frame); 45201cb0ef41Sopenharmony_ci} 45211cb0ef41Sopenharmony_ci 45221cb0ef41Sopenharmony_cistatic int update_remote_initial_window_size_func(void *entry, void *ptr) { 45231cb0ef41Sopenharmony_ci int rv; 45241cb0ef41Sopenharmony_ci nghttp2_update_window_size_arg *arg; 45251cb0ef41Sopenharmony_ci nghttp2_stream *stream; 45261cb0ef41Sopenharmony_ci 45271cb0ef41Sopenharmony_ci arg = (nghttp2_update_window_size_arg *)ptr; 45281cb0ef41Sopenharmony_ci stream = (nghttp2_stream *)entry; 45291cb0ef41Sopenharmony_ci 45301cb0ef41Sopenharmony_ci rv = nghttp2_stream_update_remote_initial_window_size( 45311cb0ef41Sopenharmony_ci stream, arg->new_window_size, arg->old_window_size); 45321cb0ef41Sopenharmony_ci if (rv != 0) { 45331cb0ef41Sopenharmony_ci return nghttp2_session_add_rst_stream(arg->session, stream->stream_id, 45341cb0ef41Sopenharmony_ci NGHTTP2_FLOW_CONTROL_ERROR); 45351cb0ef41Sopenharmony_ci } 45361cb0ef41Sopenharmony_ci 45371cb0ef41Sopenharmony_ci /* If window size gets positive, push deferred DATA frame to 45381cb0ef41Sopenharmony_ci outbound queue. */ 45391cb0ef41Sopenharmony_ci if (stream->remote_window_size > 0 && 45401cb0ef41Sopenharmony_ci nghttp2_stream_check_deferred_by_flow_control(stream)) { 45411cb0ef41Sopenharmony_ci 45421cb0ef41Sopenharmony_ci rv = session_resume_deferred_stream_item( 45431cb0ef41Sopenharmony_ci arg->session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); 45441cb0ef41Sopenharmony_ci 45451cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 45461cb0ef41Sopenharmony_ci return rv; 45471cb0ef41Sopenharmony_ci } 45481cb0ef41Sopenharmony_ci } 45491cb0ef41Sopenharmony_ci return 0; 45501cb0ef41Sopenharmony_ci} 45511cb0ef41Sopenharmony_ci 45521cb0ef41Sopenharmony_ci/* 45531cb0ef41Sopenharmony_ci * Updates the remote initial window size of all active streams. If 45541cb0ef41Sopenharmony_ci * error occurs, all streams may not be updated. 45551cb0ef41Sopenharmony_ci * 45561cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 45571cb0ef41Sopenharmony_ci * negative error codes: 45581cb0ef41Sopenharmony_ci * 45591cb0ef41Sopenharmony_ci * NGHTTP2_ERR_NOMEM 45601cb0ef41Sopenharmony_ci * Out of memory. 45611cb0ef41Sopenharmony_ci */ 45621cb0ef41Sopenharmony_cistatic int 45631cb0ef41Sopenharmony_cisession_update_remote_initial_window_size(nghttp2_session *session, 45641cb0ef41Sopenharmony_ci int32_t new_initial_window_size) { 45651cb0ef41Sopenharmony_ci nghttp2_update_window_size_arg arg; 45661cb0ef41Sopenharmony_ci 45671cb0ef41Sopenharmony_ci arg.session = session; 45681cb0ef41Sopenharmony_ci arg.new_window_size = new_initial_window_size; 45691cb0ef41Sopenharmony_ci arg.old_window_size = (int32_t)session->remote_settings.initial_window_size; 45701cb0ef41Sopenharmony_ci 45711cb0ef41Sopenharmony_ci return nghttp2_map_each(&session->streams, 45721cb0ef41Sopenharmony_ci update_remote_initial_window_size_func, &arg); 45731cb0ef41Sopenharmony_ci} 45741cb0ef41Sopenharmony_ci 45751cb0ef41Sopenharmony_cistatic int update_local_initial_window_size_func(void *entry, void *ptr) { 45761cb0ef41Sopenharmony_ci int rv; 45771cb0ef41Sopenharmony_ci nghttp2_update_window_size_arg *arg; 45781cb0ef41Sopenharmony_ci nghttp2_stream *stream; 45791cb0ef41Sopenharmony_ci arg = (nghttp2_update_window_size_arg *)ptr; 45801cb0ef41Sopenharmony_ci stream = (nghttp2_stream *)entry; 45811cb0ef41Sopenharmony_ci rv = nghttp2_stream_update_local_initial_window_size( 45821cb0ef41Sopenharmony_ci stream, arg->new_window_size, arg->old_window_size); 45831cb0ef41Sopenharmony_ci if (rv != 0) { 45841cb0ef41Sopenharmony_ci return nghttp2_session_add_rst_stream(arg->session, stream->stream_id, 45851cb0ef41Sopenharmony_ci NGHTTP2_FLOW_CONTROL_ERROR); 45861cb0ef41Sopenharmony_ci } 45871cb0ef41Sopenharmony_ci 45881cb0ef41Sopenharmony_ci if (stream->window_update_queued) { 45891cb0ef41Sopenharmony_ci return 0; 45901cb0ef41Sopenharmony_ci } 45911cb0ef41Sopenharmony_ci 45921cb0ef41Sopenharmony_ci if (arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { 45931cb0ef41Sopenharmony_ci return session_update_stream_consumed_size(arg->session, stream, 0); 45941cb0ef41Sopenharmony_ci } 45951cb0ef41Sopenharmony_ci 45961cb0ef41Sopenharmony_ci if (nghttp2_should_send_window_update(stream->local_window_size, 45971cb0ef41Sopenharmony_ci stream->recv_window_size)) { 45981cb0ef41Sopenharmony_ci 45991cb0ef41Sopenharmony_ci rv = nghttp2_session_add_window_update(arg->session, NGHTTP2_FLAG_NONE, 46001cb0ef41Sopenharmony_ci stream->stream_id, 46011cb0ef41Sopenharmony_ci stream->recv_window_size); 46021cb0ef41Sopenharmony_ci if (rv != 0) { 46031cb0ef41Sopenharmony_ci return rv; 46041cb0ef41Sopenharmony_ci } 46051cb0ef41Sopenharmony_ci 46061cb0ef41Sopenharmony_ci stream->recv_window_size = 0; 46071cb0ef41Sopenharmony_ci } 46081cb0ef41Sopenharmony_ci return 0; 46091cb0ef41Sopenharmony_ci} 46101cb0ef41Sopenharmony_ci 46111cb0ef41Sopenharmony_ci/* 46121cb0ef41Sopenharmony_ci * Updates the local initial window size of all active streams. If 46131cb0ef41Sopenharmony_ci * error occurs, all streams may not be updated. 46141cb0ef41Sopenharmony_ci * 46151cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 46161cb0ef41Sopenharmony_ci * negative error codes: 46171cb0ef41Sopenharmony_ci * 46181cb0ef41Sopenharmony_ci * NGHTTP2_ERR_NOMEM 46191cb0ef41Sopenharmony_ci * Out of memory. 46201cb0ef41Sopenharmony_ci */ 46211cb0ef41Sopenharmony_cistatic int 46221cb0ef41Sopenharmony_cisession_update_local_initial_window_size(nghttp2_session *session, 46231cb0ef41Sopenharmony_ci int32_t new_initial_window_size, 46241cb0ef41Sopenharmony_ci int32_t old_initial_window_size) { 46251cb0ef41Sopenharmony_ci nghttp2_update_window_size_arg arg; 46261cb0ef41Sopenharmony_ci arg.session = session; 46271cb0ef41Sopenharmony_ci arg.new_window_size = new_initial_window_size; 46281cb0ef41Sopenharmony_ci arg.old_window_size = old_initial_window_size; 46291cb0ef41Sopenharmony_ci return nghttp2_map_each(&session->streams, 46301cb0ef41Sopenharmony_ci update_local_initial_window_size_func, &arg); 46311cb0ef41Sopenharmony_ci} 46321cb0ef41Sopenharmony_ci 46331cb0ef41Sopenharmony_ci/* 46341cb0ef41Sopenharmony_ci * Apply SETTINGS values |iv| having |niv| elements to the local 46351cb0ef41Sopenharmony_ci * settings. We assumes that all values in |iv| is correct, since we 46361cb0ef41Sopenharmony_ci * validated them in nghttp2_session_add_settings() already. 46371cb0ef41Sopenharmony_ci * 46381cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 46391cb0ef41Sopenharmony_ci * negative error codes: 46401cb0ef41Sopenharmony_ci * 46411cb0ef41Sopenharmony_ci * NGHTTP2_ERR_HEADER_COMP 46421cb0ef41Sopenharmony_ci * The header table size is out of range 46431cb0ef41Sopenharmony_ci * NGHTTP2_ERR_NOMEM 46441cb0ef41Sopenharmony_ci * Out of memory 46451cb0ef41Sopenharmony_ci */ 46461cb0ef41Sopenharmony_ciint nghttp2_session_update_local_settings(nghttp2_session *session, 46471cb0ef41Sopenharmony_ci nghttp2_settings_entry *iv, 46481cb0ef41Sopenharmony_ci size_t niv) { 46491cb0ef41Sopenharmony_ci int rv; 46501cb0ef41Sopenharmony_ci size_t i; 46511cb0ef41Sopenharmony_ci int32_t new_initial_window_size = -1; 46521cb0ef41Sopenharmony_ci uint32_t header_table_size = 0; 46531cb0ef41Sopenharmony_ci uint32_t min_header_table_size = UINT32_MAX; 46541cb0ef41Sopenharmony_ci uint8_t header_table_size_seen = 0; 46551cb0ef41Sopenharmony_ci /* For NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, use the value last 46561cb0ef41Sopenharmony_ci seen. For NGHTTP2_SETTINGS_HEADER_TABLE_SIZE, use both minimum 46571cb0ef41Sopenharmony_ci value and last seen value. */ 46581cb0ef41Sopenharmony_ci for (i = 0; i < niv; ++i) { 46591cb0ef41Sopenharmony_ci switch (iv[i].settings_id) { 46601cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: 46611cb0ef41Sopenharmony_ci header_table_size_seen = 1; 46621cb0ef41Sopenharmony_ci header_table_size = iv[i].value; 46631cb0ef41Sopenharmony_ci min_header_table_size = nghttp2_min(min_header_table_size, iv[i].value); 46641cb0ef41Sopenharmony_ci break; 46651cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: 46661cb0ef41Sopenharmony_ci new_initial_window_size = (int32_t)iv[i].value; 46671cb0ef41Sopenharmony_ci break; 46681cb0ef41Sopenharmony_ci } 46691cb0ef41Sopenharmony_ci } 46701cb0ef41Sopenharmony_ci if (header_table_size_seen) { 46711cb0ef41Sopenharmony_ci if (min_header_table_size < header_table_size) { 46721cb0ef41Sopenharmony_ci rv = nghttp2_hd_inflate_change_table_size(&session->hd_inflater, 46731cb0ef41Sopenharmony_ci min_header_table_size); 46741cb0ef41Sopenharmony_ci if (rv != 0) { 46751cb0ef41Sopenharmony_ci return rv; 46761cb0ef41Sopenharmony_ci } 46771cb0ef41Sopenharmony_ci } 46781cb0ef41Sopenharmony_ci 46791cb0ef41Sopenharmony_ci rv = nghttp2_hd_inflate_change_table_size(&session->hd_inflater, 46801cb0ef41Sopenharmony_ci header_table_size); 46811cb0ef41Sopenharmony_ci if (rv != 0) { 46821cb0ef41Sopenharmony_ci return rv; 46831cb0ef41Sopenharmony_ci } 46841cb0ef41Sopenharmony_ci } 46851cb0ef41Sopenharmony_ci if (new_initial_window_size != -1) { 46861cb0ef41Sopenharmony_ci rv = session_update_local_initial_window_size( 46871cb0ef41Sopenharmony_ci session, new_initial_window_size, 46881cb0ef41Sopenharmony_ci (int32_t)session->local_settings.initial_window_size); 46891cb0ef41Sopenharmony_ci if (rv != 0) { 46901cb0ef41Sopenharmony_ci return rv; 46911cb0ef41Sopenharmony_ci } 46921cb0ef41Sopenharmony_ci } 46931cb0ef41Sopenharmony_ci 46941cb0ef41Sopenharmony_ci for (i = 0; i < niv; ++i) { 46951cb0ef41Sopenharmony_ci switch (iv[i].settings_id) { 46961cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: 46971cb0ef41Sopenharmony_ci session->local_settings.header_table_size = iv[i].value; 46981cb0ef41Sopenharmony_ci break; 46991cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_ENABLE_PUSH: 47001cb0ef41Sopenharmony_ci session->local_settings.enable_push = iv[i].value; 47011cb0ef41Sopenharmony_ci break; 47021cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: 47031cb0ef41Sopenharmony_ci session->local_settings.max_concurrent_streams = iv[i].value; 47041cb0ef41Sopenharmony_ci break; 47051cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: 47061cb0ef41Sopenharmony_ci session->local_settings.initial_window_size = iv[i].value; 47071cb0ef41Sopenharmony_ci break; 47081cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: 47091cb0ef41Sopenharmony_ci session->local_settings.max_frame_size = iv[i].value; 47101cb0ef41Sopenharmony_ci break; 47111cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: 47121cb0ef41Sopenharmony_ci session->local_settings.max_header_list_size = iv[i].value; 47131cb0ef41Sopenharmony_ci break; 47141cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: 47151cb0ef41Sopenharmony_ci session->local_settings.enable_connect_protocol = iv[i].value; 47161cb0ef41Sopenharmony_ci break; 47171cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES: 47181cb0ef41Sopenharmony_ci session->local_settings.no_rfc7540_priorities = iv[i].value; 47191cb0ef41Sopenharmony_ci break; 47201cb0ef41Sopenharmony_ci } 47211cb0ef41Sopenharmony_ci } 47221cb0ef41Sopenharmony_ci 47231cb0ef41Sopenharmony_ci return 0; 47241cb0ef41Sopenharmony_ci} 47251cb0ef41Sopenharmony_ci 47261cb0ef41Sopenharmony_ciint nghttp2_session_on_settings_received(nghttp2_session *session, 47271cb0ef41Sopenharmony_ci nghttp2_frame *frame, int noack) { 47281cb0ef41Sopenharmony_ci int rv; 47291cb0ef41Sopenharmony_ci size_t i; 47301cb0ef41Sopenharmony_ci nghttp2_mem *mem; 47311cb0ef41Sopenharmony_ci nghttp2_inflight_settings *settings; 47321cb0ef41Sopenharmony_ci 47331cb0ef41Sopenharmony_ci mem = &session->mem; 47341cb0ef41Sopenharmony_ci 47351cb0ef41Sopenharmony_ci if (frame->hd.stream_id != 0) { 47361cb0ef41Sopenharmony_ci return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, 47371cb0ef41Sopenharmony_ci "SETTINGS: stream_id != 0"); 47381cb0ef41Sopenharmony_ci } 47391cb0ef41Sopenharmony_ci if (frame->hd.flags & NGHTTP2_FLAG_ACK) { 47401cb0ef41Sopenharmony_ci if (frame->settings.niv != 0) { 47411cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 47421cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_FRAME_SIZE_ERROR, 47431cb0ef41Sopenharmony_ci "SETTINGS: ACK and payload != 0"); 47441cb0ef41Sopenharmony_ci } 47451cb0ef41Sopenharmony_ci 47461cb0ef41Sopenharmony_ci settings = session->inflight_settings_head; 47471cb0ef41Sopenharmony_ci 47481cb0ef41Sopenharmony_ci if (!settings) { 47491cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 47501cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, "SETTINGS: unexpected ACK"); 47511cb0ef41Sopenharmony_ci } 47521cb0ef41Sopenharmony_ci 47531cb0ef41Sopenharmony_ci rv = nghttp2_session_update_local_settings(session, settings->iv, 47541cb0ef41Sopenharmony_ci settings->niv); 47551cb0ef41Sopenharmony_ci 47561cb0ef41Sopenharmony_ci session->inflight_settings_head = settings->next; 47571cb0ef41Sopenharmony_ci 47581cb0ef41Sopenharmony_ci inflight_settings_del(settings, mem); 47591cb0ef41Sopenharmony_ci 47601cb0ef41Sopenharmony_ci if (rv != 0) { 47611cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 47621cb0ef41Sopenharmony_ci return rv; 47631cb0ef41Sopenharmony_ci } 47641cb0ef41Sopenharmony_ci return session_handle_invalid_connection(session, frame, rv, NULL); 47651cb0ef41Sopenharmony_ci } 47661cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 47671cb0ef41Sopenharmony_ci } 47681cb0ef41Sopenharmony_ci 47691cb0ef41Sopenharmony_ci if (!session->remote_settings_received) { 47701cb0ef41Sopenharmony_ci session->remote_settings.max_concurrent_streams = 47711cb0ef41Sopenharmony_ci NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS; 47721cb0ef41Sopenharmony_ci session->remote_settings_received = 1; 47731cb0ef41Sopenharmony_ci } 47741cb0ef41Sopenharmony_ci 47751cb0ef41Sopenharmony_ci for (i = 0; i < frame->settings.niv; ++i) { 47761cb0ef41Sopenharmony_ci nghttp2_settings_entry *entry = &frame->settings.iv[i]; 47771cb0ef41Sopenharmony_ci 47781cb0ef41Sopenharmony_ci switch (entry->settings_id) { 47791cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: 47801cb0ef41Sopenharmony_ci 47811cb0ef41Sopenharmony_ci rv = nghttp2_hd_deflate_change_table_size(&session->hd_deflater, 47821cb0ef41Sopenharmony_ci entry->value); 47831cb0ef41Sopenharmony_ci if (rv != 0) { 47841cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 47851cb0ef41Sopenharmony_ci return rv; 47861cb0ef41Sopenharmony_ci } else { 47871cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 47881cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_HEADER_COMP, NULL); 47891cb0ef41Sopenharmony_ci } 47901cb0ef41Sopenharmony_ci } 47911cb0ef41Sopenharmony_ci 47921cb0ef41Sopenharmony_ci session->remote_settings.header_table_size = entry->value; 47931cb0ef41Sopenharmony_ci 47941cb0ef41Sopenharmony_ci break; 47951cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_ENABLE_PUSH: 47961cb0ef41Sopenharmony_ci 47971cb0ef41Sopenharmony_ci if (entry->value != 0 && entry->value != 1) { 47981cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 47991cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 48001cb0ef41Sopenharmony_ci "SETTINGS: invalid SETTINGS_ENBLE_PUSH"); 48011cb0ef41Sopenharmony_ci } 48021cb0ef41Sopenharmony_ci 48031cb0ef41Sopenharmony_ci if (!session->server && entry->value != 0) { 48041cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 48051cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 48061cb0ef41Sopenharmony_ci "SETTINGS: server attempted to enable push"); 48071cb0ef41Sopenharmony_ci } 48081cb0ef41Sopenharmony_ci 48091cb0ef41Sopenharmony_ci session->remote_settings.enable_push = entry->value; 48101cb0ef41Sopenharmony_ci 48111cb0ef41Sopenharmony_ci break; 48121cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: 48131cb0ef41Sopenharmony_ci 48141cb0ef41Sopenharmony_ci session->remote_settings.max_concurrent_streams = entry->value; 48151cb0ef41Sopenharmony_ci 48161cb0ef41Sopenharmony_ci break; 48171cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: 48181cb0ef41Sopenharmony_ci 48191cb0ef41Sopenharmony_ci /* Update the initial window size of the all active streams */ 48201cb0ef41Sopenharmony_ci /* Check that initial_window_size < (1u << 31) */ 48211cb0ef41Sopenharmony_ci if (entry->value > NGHTTP2_MAX_WINDOW_SIZE) { 48221cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 48231cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_FLOW_CONTROL, 48241cb0ef41Sopenharmony_ci "SETTINGS: too large SETTINGS_INITIAL_WINDOW_SIZE"); 48251cb0ef41Sopenharmony_ci } 48261cb0ef41Sopenharmony_ci 48271cb0ef41Sopenharmony_ci rv = session_update_remote_initial_window_size(session, 48281cb0ef41Sopenharmony_ci (int32_t)entry->value); 48291cb0ef41Sopenharmony_ci 48301cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 48311cb0ef41Sopenharmony_ci return rv; 48321cb0ef41Sopenharmony_ci } 48331cb0ef41Sopenharmony_ci 48341cb0ef41Sopenharmony_ci if (rv != 0) { 48351cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 48361cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_FLOW_CONTROL, NULL); 48371cb0ef41Sopenharmony_ci } 48381cb0ef41Sopenharmony_ci 48391cb0ef41Sopenharmony_ci session->remote_settings.initial_window_size = entry->value; 48401cb0ef41Sopenharmony_ci 48411cb0ef41Sopenharmony_ci break; 48421cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: 48431cb0ef41Sopenharmony_ci 48441cb0ef41Sopenharmony_ci if (entry->value < NGHTTP2_MAX_FRAME_SIZE_MIN || 48451cb0ef41Sopenharmony_ci entry->value > NGHTTP2_MAX_FRAME_SIZE_MAX) { 48461cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 48471cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 48481cb0ef41Sopenharmony_ci "SETTINGS: invalid SETTINGS_MAX_FRAME_SIZE"); 48491cb0ef41Sopenharmony_ci } 48501cb0ef41Sopenharmony_ci 48511cb0ef41Sopenharmony_ci session->remote_settings.max_frame_size = entry->value; 48521cb0ef41Sopenharmony_ci 48531cb0ef41Sopenharmony_ci break; 48541cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: 48551cb0ef41Sopenharmony_ci 48561cb0ef41Sopenharmony_ci session->remote_settings.max_header_list_size = entry->value; 48571cb0ef41Sopenharmony_ci 48581cb0ef41Sopenharmony_ci break; 48591cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: 48601cb0ef41Sopenharmony_ci 48611cb0ef41Sopenharmony_ci if (entry->value != 0 && entry->value != 1) { 48621cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 48631cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 48641cb0ef41Sopenharmony_ci "SETTINGS: invalid SETTINGS_ENABLE_CONNECT_PROTOCOL"); 48651cb0ef41Sopenharmony_ci } 48661cb0ef41Sopenharmony_ci 48671cb0ef41Sopenharmony_ci if (!session->server && 48681cb0ef41Sopenharmony_ci session->remote_settings.enable_connect_protocol && 48691cb0ef41Sopenharmony_ci entry->value == 0) { 48701cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 48711cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 48721cb0ef41Sopenharmony_ci "SETTINGS: server attempted to disable " 48731cb0ef41Sopenharmony_ci "SETTINGS_ENABLE_CONNECT_PROTOCOL"); 48741cb0ef41Sopenharmony_ci } 48751cb0ef41Sopenharmony_ci 48761cb0ef41Sopenharmony_ci session->remote_settings.enable_connect_protocol = entry->value; 48771cb0ef41Sopenharmony_ci 48781cb0ef41Sopenharmony_ci break; 48791cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES: 48801cb0ef41Sopenharmony_ci 48811cb0ef41Sopenharmony_ci if (entry->value != 0 && entry->value != 1) { 48821cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 48831cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 48841cb0ef41Sopenharmony_ci "SETTINGS: invalid SETTINGS_NO_RFC7540_PRIORITIES"); 48851cb0ef41Sopenharmony_ci } 48861cb0ef41Sopenharmony_ci 48871cb0ef41Sopenharmony_ci if (session->remote_settings.no_rfc7540_priorities != UINT32_MAX && 48881cb0ef41Sopenharmony_ci session->remote_settings.no_rfc7540_priorities != entry->value) { 48891cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 48901cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 48911cb0ef41Sopenharmony_ci "SETTINGS: SETTINGS_NO_RFC7540_PRIORITIES cannot be changed"); 48921cb0ef41Sopenharmony_ci } 48931cb0ef41Sopenharmony_ci 48941cb0ef41Sopenharmony_ci session->remote_settings.no_rfc7540_priorities = entry->value; 48951cb0ef41Sopenharmony_ci 48961cb0ef41Sopenharmony_ci break; 48971cb0ef41Sopenharmony_ci } 48981cb0ef41Sopenharmony_ci } 48991cb0ef41Sopenharmony_ci 49001cb0ef41Sopenharmony_ci if (session->remote_settings.no_rfc7540_priorities == UINT32_MAX) { 49011cb0ef41Sopenharmony_ci session->remote_settings.no_rfc7540_priorities = 0; 49021cb0ef41Sopenharmony_ci 49031cb0ef41Sopenharmony_ci if (session->server && session->pending_no_rfc7540_priorities && 49041cb0ef41Sopenharmony_ci (session->opt_flags & 49051cb0ef41Sopenharmony_ci NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES)) { 49061cb0ef41Sopenharmony_ci session->fallback_rfc7540_priorities = 1; 49071cb0ef41Sopenharmony_ci } 49081cb0ef41Sopenharmony_ci } 49091cb0ef41Sopenharmony_ci 49101cb0ef41Sopenharmony_ci if (!noack && !session_is_closing(session)) { 49111cb0ef41Sopenharmony_ci rv = nghttp2_session_add_settings(session, NGHTTP2_FLAG_ACK, NULL, 0); 49121cb0ef41Sopenharmony_ci 49131cb0ef41Sopenharmony_ci if (rv != 0) { 49141cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 49151cb0ef41Sopenharmony_ci return rv; 49161cb0ef41Sopenharmony_ci } 49171cb0ef41Sopenharmony_ci 49181cb0ef41Sopenharmony_ci return session_handle_invalid_connection(session, frame, 49191cb0ef41Sopenharmony_ci NGHTTP2_ERR_INTERNAL, NULL); 49201cb0ef41Sopenharmony_ci } 49211cb0ef41Sopenharmony_ci } 49221cb0ef41Sopenharmony_ci 49231cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 49241cb0ef41Sopenharmony_ci} 49251cb0ef41Sopenharmony_ci 49261cb0ef41Sopenharmony_cistatic int session_process_settings_frame(nghttp2_session *session) { 49271cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 49281cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 49291cb0ef41Sopenharmony_ci size_t i; 49301cb0ef41Sopenharmony_ci nghttp2_settings_entry min_header_size_entry; 49311cb0ef41Sopenharmony_ci 49321cb0ef41Sopenharmony_ci if (iframe->max_niv) { 49331cb0ef41Sopenharmony_ci min_header_size_entry = iframe->iv[iframe->max_niv - 1]; 49341cb0ef41Sopenharmony_ci 49351cb0ef41Sopenharmony_ci if (min_header_size_entry.value < UINT32_MAX) { 49361cb0ef41Sopenharmony_ci /* If we have less value, then we must have 49371cb0ef41Sopenharmony_ci SETTINGS_HEADER_TABLE_SIZE in i < iframe->niv */ 49381cb0ef41Sopenharmony_ci for (i = 0; i < iframe->niv; ++i) { 49391cb0ef41Sopenharmony_ci if (iframe->iv[i].settings_id == NGHTTP2_SETTINGS_HEADER_TABLE_SIZE) { 49401cb0ef41Sopenharmony_ci break; 49411cb0ef41Sopenharmony_ci } 49421cb0ef41Sopenharmony_ci } 49431cb0ef41Sopenharmony_ci 49441cb0ef41Sopenharmony_ci assert(i < iframe->niv); 49451cb0ef41Sopenharmony_ci 49461cb0ef41Sopenharmony_ci if (min_header_size_entry.value != iframe->iv[i].value) { 49471cb0ef41Sopenharmony_ci iframe->iv[iframe->niv++] = iframe->iv[i]; 49481cb0ef41Sopenharmony_ci iframe->iv[i] = min_header_size_entry; 49491cb0ef41Sopenharmony_ci } 49501cb0ef41Sopenharmony_ci } 49511cb0ef41Sopenharmony_ci } 49521cb0ef41Sopenharmony_ci 49531cb0ef41Sopenharmony_ci nghttp2_frame_unpack_settings_payload(&frame->settings, iframe->iv, 49541cb0ef41Sopenharmony_ci iframe->niv); 49551cb0ef41Sopenharmony_ci 49561cb0ef41Sopenharmony_ci iframe->iv = NULL; 49571cb0ef41Sopenharmony_ci iframe->niv = 0; 49581cb0ef41Sopenharmony_ci iframe->max_niv = 0; 49591cb0ef41Sopenharmony_ci 49601cb0ef41Sopenharmony_ci return nghttp2_session_on_settings_received(session, frame, 0 /* ACK */); 49611cb0ef41Sopenharmony_ci} 49621cb0ef41Sopenharmony_ci 49631cb0ef41Sopenharmony_ciint nghttp2_session_on_push_promise_received(nghttp2_session *session, 49641cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 49651cb0ef41Sopenharmony_ci int rv; 49661cb0ef41Sopenharmony_ci nghttp2_stream *stream; 49671cb0ef41Sopenharmony_ci nghttp2_stream *promised_stream; 49681cb0ef41Sopenharmony_ci nghttp2_priority_spec pri_spec; 49691cb0ef41Sopenharmony_ci 49701cb0ef41Sopenharmony_ci if (frame->hd.stream_id == 0) { 49711cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 49721cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: stream_id == 0"); 49731cb0ef41Sopenharmony_ci } 49741cb0ef41Sopenharmony_ci if (session->server || session->local_settings.enable_push == 0) { 49751cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 49761cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: push disabled"); 49771cb0ef41Sopenharmony_ci } 49781cb0ef41Sopenharmony_ci 49791cb0ef41Sopenharmony_ci if (!nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { 49801cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 49811cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: invalid stream_id"); 49821cb0ef41Sopenharmony_ci } 49831cb0ef41Sopenharmony_ci 49841cb0ef41Sopenharmony_ci if (!session_allow_incoming_new_stream(session)) { 49851cb0ef41Sopenharmony_ci /* We just discard PUSH_PROMISE after GOAWAY was sent */ 49861cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_HEADER_BLOCK; 49871cb0ef41Sopenharmony_ci } 49881cb0ef41Sopenharmony_ci 49891cb0ef41Sopenharmony_ci if (!session_is_new_peer_stream_id(session, 49901cb0ef41Sopenharmony_ci frame->push_promise.promised_stream_id)) { 49911cb0ef41Sopenharmony_ci /* The spec says if an endpoint receives a PUSH_PROMISE with 49921cb0ef41Sopenharmony_ci illegal stream ID is subject to a connection error of type 49931cb0ef41Sopenharmony_ci PROTOCOL_ERROR. */ 49941cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 49951cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 49961cb0ef41Sopenharmony_ci "PUSH_PROMISE: invalid promised_stream_id"); 49971cb0ef41Sopenharmony_ci } 49981cb0ef41Sopenharmony_ci 49991cb0ef41Sopenharmony_ci if (session_detect_idle_stream(session, frame->hd.stream_id)) { 50001cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 50011cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: stream in idle"); 50021cb0ef41Sopenharmony_ci } 50031cb0ef41Sopenharmony_ci 50041cb0ef41Sopenharmony_ci session->last_recv_stream_id = frame->push_promise.promised_stream_id; 50051cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 50061cb0ef41Sopenharmony_ci if (!stream || stream->state == NGHTTP2_STREAM_CLOSING || 50071cb0ef41Sopenharmony_ci !session->pending_enable_push || 50081cb0ef41Sopenharmony_ci session->num_incoming_reserved_streams >= 50091cb0ef41Sopenharmony_ci session->max_incoming_reserved_streams) { 50101cb0ef41Sopenharmony_ci /* Currently, client does not retain closed stream, so we don't 50111cb0ef41Sopenharmony_ci check NGHTTP2_SHUT_RD condition here. */ 50121cb0ef41Sopenharmony_ci 50131cb0ef41Sopenharmony_ci rv = nghttp2_session_add_rst_stream( 50141cb0ef41Sopenharmony_ci session, frame->push_promise.promised_stream_id, NGHTTP2_CANCEL); 50151cb0ef41Sopenharmony_ci if (rv != 0) { 50161cb0ef41Sopenharmony_ci return rv; 50171cb0ef41Sopenharmony_ci } 50181cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_HEADER_BLOCK; 50191cb0ef41Sopenharmony_ci } 50201cb0ef41Sopenharmony_ci 50211cb0ef41Sopenharmony_ci if (stream->shut_flags & NGHTTP2_SHUT_RD) { 50221cb0ef41Sopenharmony_ci return session_inflate_handle_invalid_connection( 50231cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_STREAM_CLOSED, 50241cb0ef41Sopenharmony_ci "PUSH_PROMISE: stream closed"); 50251cb0ef41Sopenharmony_ci } 50261cb0ef41Sopenharmony_ci 50271cb0ef41Sopenharmony_ci nghttp2_priority_spec_init(&pri_spec, stream->stream_id, 50281cb0ef41Sopenharmony_ci NGHTTP2_DEFAULT_WEIGHT, 0); 50291cb0ef41Sopenharmony_ci 50301cb0ef41Sopenharmony_ci promised_stream = nghttp2_session_open_stream( 50311cb0ef41Sopenharmony_ci session, frame->push_promise.promised_stream_id, NGHTTP2_STREAM_FLAG_NONE, 50321cb0ef41Sopenharmony_ci &pri_spec, NGHTTP2_STREAM_RESERVED, NULL); 50331cb0ef41Sopenharmony_ci 50341cb0ef41Sopenharmony_ci if (!promised_stream) { 50351cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 50361cb0ef41Sopenharmony_ci } 50371cb0ef41Sopenharmony_ci 50381cb0ef41Sopenharmony_ci /* We don't call nghttp2_session_adjust_closed_stream(), since we 50391cb0ef41Sopenharmony_ci don't keep closed stream in client side */ 50401cb0ef41Sopenharmony_ci 50411cb0ef41Sopenharmony_ci session->last_proc_stream_id = session->last_recv_stream_id; 50421cb0ef41Sopenharmony_ci rv = session_call_on_begin_headers(session, frame); 50431cb0ef41Sopenharmony_ci if (rv != 0) { 50441cb0ef41Sopenharmony_ci return rv; 50451cb0ef41Sopenharmony_ci } 50461cb0ef41Sopenharmony_ci return 0; 50471cb0ef41Sopenharmony_ci} 50481cb0ef41Sopenharmony_ci 50491cb0ef41Sopenharmony_cistatic int session_process_push_promise_frame(nghttp2_session *session) { 50501cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 50511cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 50521cb0ef41Sopenharmony_ci 50531cb0ef41Sopenharmony_ci nghttp2_frame_unpack_push_promise_payload(&frame->push_promise, 50541cb0ef41Sopenharmony_ci iframe->sbuf.pos); 50551cb0ef41Sopenharmony_ci 50561cb0ef41Sopenharmony_ci return nghttp2_session_on_push_promise_received(session, frame); 50571cb0ef41Sopenharmony_ci} 50581cb0ef41Sopenharmony_ci 50591cb0ef41Sopenharmony_ciint nghttp2_session_on_ping_received(nghttp2_session *session, 50601cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 50611cb0ef41Sopenharmony_ci int rv = 0; 50621cb0ef41Sopenharmony_ci if (frame->hd.stream_id != 0) { 50631cb0ef41Sopenharmony_ci return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, 50641cb0ef41Sopenharmony_ci "PING: stream_id != 0"); 50651cb0ef41Sopenharmony_ci } 50661cb0ef41Sopenharmony_ci if ((session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_PING_ACK) == 0 && 50671cb0ef41Sopenharmony_ci (frame->hd.flags & NGHTTP2_FLAG_ACK) == 0 && 50681cb0ef41Sopenharmony_ci !session_is_closing(session)) { 50691cb0ef41Sopenharmony_ci /* Peer sent ping, so ping it back */ 50701cb0ef41Sopenharmony_ci rv = nghttp2_session_add_ping(session, NGHTTP2_FLAG_ACK, 50711cb0ef41Sopenharmony_ci frame->ping.opaque_data); 50721cb0ef41Sopenharmony_ci if (rv != 0) { 50731cb0ef41Sopenharmony_ci return rv; 50741cb0ef41Sopenharmony_ci } 50751cb0ef41Sopenharmony_ci } 50761cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 50771cb0ef41Sopenharmony_ci} 50781cb0ef41Sopenharmony_ci 50791cb0ef41Sopenharmony_cistatic int session_process_ping_frame(nghttp2_session *session) { 50801cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 50811cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 50821cb0ef41Sopenharmony_ci 50831cb0ef41Sopenharmony_ci nghttp2_frame_unpack_ping_payload(&frame->ping, iframe->sbuf.pos); 50841cb0ef41Sopenharmony_ci 50851cb0ef41Sopenharmony_ci return nghttp2_session_on_ping_received(session, frame); 50861cb0ef41Sopenharmony_ci} 50871cb0ef41Sopenharmony_ci 50881cb0ef41Sopenharmony_ciint nghttp2_session_on_goaway_received(nghttp2_session *session, 50891cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 50901cb0ef41Sopenharmony_ci int rv; 50911cb0ef41Sopenharmony_ci 50921cb0ef41Sopenharmony_ci if (frame->hd.stream_id != 0) { 50931cb0ef41Sopenharmony_ci return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, 50941cb0ef41Sopenharmony_ci "GOAWAY: stream_id != 0"); 50951cb0ef41Sopenharmony_ci } 50961cb0ef41Sopenharmony_ci /* Spec says Endpoints MUST NOT increase the value they send in the 50971cb0ef41Sopenharmony_ci last stream identifier. */ 50981cb0ef41Sopenharmony_ci if ((frame->goaway.last_stream_id > 0 && 50991cb0ef41Sopenharmony_ci !nghttp2_session_is_my_stream_id(session, 51001cb0ef41Sopenharmony_ci frame->goaway.last_stream_id)) || 51011cb0ef41Sopenharmony_ci session->remote_last_stream_id < frame->goaway.last_stream_id) { 51021cb0ef41Sopenharmony_ci return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, 51031cb0ef41Sopenharmony_ci "GOAWAY: invalid last_stream_id"); 51041cb0ef41Sopenharmony_ci } 51051cb0ef41Sopenharmony_ci 51061cb0ef41Sopenharmony_ci session->goaway_flags |= NGHTTP2_GOAWAY_RECV; 51071cb0ef41Sopenharmony_ci 51081cb0ef41Sopenharmony_ci session->remote_last_stream_id = frame->goaway.last_stream_id; 51091cb0ef41Sopenharmony_ci 51101cb0ef41Sopenharmony_ci rv = session_call_on_frame_received(session, frame); 51111cb0ef41Sopenharmony_ci 51121cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 51131cb0ef41Sopenharmony_ci return rv; 51141cb0ef41Sopenharmony_ci } 51151cb0ef41Sopenharmony_ci 51161cb0ef41Sopenharmony_ci return session_close_stream_on_goaway(session, frame->goaway.last_stream_id, 51171cb0ef41Sopenharmony_ci 0); 51181cb0ef41Sopenharmony_ci} 51191cb0ef41Sopenharmony_ci 51201cb0ef41Sopenharmony_cistatic int session_process_goaway_frame(nghttp2_session *session) { 51211cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 51221cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 51231cb0ef41Sopenharmony_ci 51241cb0ef41Sopenharmony_ci nghttp2_frame_unpack_goaway_payload(&frame->goaway, iframe->sbuf.pos, 51251cb0ef41Sopenharmony_ci iframe->lbuf.pos, 51261cb0ef41Sopenharmony_ci nghttp2_buf_len(&iframe->lbuf)); 51271cb0ef41Sopenharmony_ci 51281cb0ef41Sopenharmony_ci nghttp2_buf_wrap_init(&iframe->lbuf, NULL, 0); 51291cb0ef41Sopenharmony_ci 51301cb0ef41Sopenharmony_ci return nghttp2_session_on_goaway_received(session, frame); 51311cb0ef41Sopenharmony_ci} 51321cb0ef41Sopenharmony_ci 51331cb0ef41Sopenharmony_cistatic int 51341cb0ef41Sopenharmony_cisession_on_connection_window_update_received(nghttp2_session *session, 51351cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 51361cb0ef41Sopenharmony_ci /* Handle connection-level flow control */ 51371cb0ef41Sopenharmony_ci if (frame->window_update.window_size_increment == 0) { 51381cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 51391cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 51401cb0ef41Sopenharmony_ci "WINDOW_UPDATE: window_size_increment == 0"); 51411cb0ef41Sopenharmony_ci } 51421cb0ef41Sopenharmony_ci 51431cb0ef41Sopenharmony_ci if (NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment < 51441cb0ef41Sopenharmony_ci session->remote_window_size) { 51451cb0ef41Sopenharmony_ci return session_handle_invalid_connection(session, frame, 51461cb0ef41Sopenharmony_ci NGHTTP2_ERR_FLOW_CONTROL, NULL); 51471cb0ef41Sopenharmony_ci } 51481cb0ef41Sopenharmony_ci session->remote_window_size += frame->window_update.window_size_increment; 51491cb0ef41Sopenharmony_ci 51501cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 51511cb0ef41Sopenharmony_ci} 51521cb0ef41Sopenharmony_ci 51531cb0ef41Sopenharmony_cistatic int session_on_stream_window_update_received(nghttp2_session *session, 51541cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 51551cb0ef41Sopenharmony_ci int rv; 51561cb0ef41Sopenharmony_ci nghttp2_stream *stream; 51571cb0ef41Sopenharmony_ci 51581cb0ef41Sopenharmony_ci if (session_detect_idle_stream(session, frame->hd.stream_id)) { 51591cb0ef41Sopenharmony_ci return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, 51601cb0ef41Sopenharmony_ci "WINDOW_UPDATE to idle stream"); 51611cb0ef41Sopenharmony_ci } 51621cb0ef41Sopenharmony_ci 51631cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 51641cb0ef41Sopenharmony_ci if (!stream) { 51651cb0ef41Sopenharmony_ci return 0; 51661cb0ef41Sopenharmony_ci } 51671cb0ef41Sopenharmony_ci if (state_reserved_remote(session, stream)) { 51681cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 51691cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, "WINDOW_UPADATE to reserved stream"); 51701cb0ef41Sopenharmony_ci } 51711cb0ef41Sopenharmony_ci if (frame->window_update.window_size_increment == 0) { 51721cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 51731cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 51741cb0ef41Sopenharmony_ci "WINDOW_UPDATE: window_size_increment == 0"); 51751cb0ef41Sopenharmony_ci } 51761cb0ef41Sopenharmony_ci if (NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment < 51771cb0ef41Sopenharmony_ci stream->remote_window_size) { 51781cb0ef41Sopenharmony_ci return session_handle_invalid_stream(session, frame, 51791cb0ef41Sopenharmony_ci NGHTTP2_ERR_FLOW_CONTROL); 51801cb0ef41Sopenharmony_ci } 51811cb0ef41Sopenharmony_ci stream->remote_window_size += frame->window_update.window_size_increment; 51821cb0ef41Sopenharmony_ci 51831cb0ef41Sopenharmony_ci if (stream->remote_window_size > 0 && 51841cb0ef41Sopenharmony_ci nghttp2_stream_check_deferred_by_flow_control(stream)) { 51851cb0ef41Sopenharmony_ci 51861cb0ef41Sopenharmony_ci rv = session_resume_deferred_stream_item( 51871cb0ef41Sopenharmony_ci session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); 51881cb0ef41Sopenharmony_ci 51891cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 51901cb0ef41Sopenharmony_ci return rv; 51911cb0ef41Sopenharmony_ci } 51921cb0ef41Sopenharmony_ci } 51931cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 51941cb0ef41Sopenharmony_ci} 51951cb0ef41Sopenharmony_ci 51961cb0ef41Sopenharmony_ciint nghttp2_session_on_window_update_received(nghttp2_session *session, 51971cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 51981cb0ef41Sopenharmony_ci if (frame->hd.stream_id == 0) { 51991cb0ef41Sopenharmony_ci return session_on_connection_window_update_received(session, frame); 52001cb0ef41Sopenharmony_ci } else { 52011cb0ef41Sopenharmony_ci return session_on_stream_window_update_received(session, frame); 52021cb0ef41Sopenharmony_ci } 52031cb0ef41Sopenharmony_ci} 52041cb0ef41Sopenharmony_ci 52051cb0ef41Sopenharmony_cistatic int session_process_window_update_frame(nghttp2_session *session) { 52061cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 52071cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 52081cb0ef41Sopenharmony_ci 52091cb0ef41Sopenharmony_ci nghttp2_frame_unpack_window_update_payload(&frame->window_update, 52101cb0ef41Sopenharmony_ci iframe->sbuf.pos); 52111cb0ef41Sopenharmony_ci 52121cb0ef41Sopenharmony_ci return nghttp2_session_on_window_update_received(session, frame); 52131cb0ef41Sopenharmony_ci} 52141cb0ef41Sopenharmony_ci 52151cb0ef41Sopenharmony_ciint nghttp2_session_on_altsvc_received(nghttp2_session *session, 52161cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 52171cb0ef41Sopenharmony_ci nghttp2_ext_altsvc *altsvc; 52181cb0ef41Sopenharmony_ci nghttp2_stream *stream; 52191cb0ef41Sopenharmony_ci 52201cb0ef41Sopenharmony_ci altsvc = frame->ext.payload; 52211cb0ef41Sopenharmony_ci 52221cb0ef41Sopenharmony_ci /* session->server case has been excluded */ 52231cb0ef41Sopenharmony_ci 52241cb0ef41Sopenharmony_ci if (frame->hd.stream_id == 0) { 52251cb0ef41Sopenharmony_ci if (altsvc->origin_len == 0) { 52261cb0ef41Sopenharmony_ci return session_call_on_invalid_frame_recv_callback(session, frame, 52271cb0ef41Sopenharmony_ci NGHTTP2_ERR_PROTO); 52281cb0ef41Sopenharmony_ci } 52291cb0ef41Sopenharmony_ci } else { 52301cb0ef41Sopenharmony_ci if (altsvc->origin_len > 0) { 52311cb0ef41Sopenharmony_ci return session_call_on_invalid_frame_recv_callback(session, frame, 52321cb0ef41Sopenharmony_ci NGHTTP2_ERR_PROTO); 52331cb0ef41Sopenharmony_ci } 52341cb0ef41Sopenharmony_ci 52351cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 52361cb0ef41Sopenharmony_ci if (!stream) { 52371cb0ef41Sopenharmony_ci return 0; 52381cb0ef41Sopenharmony_ci } 52391cb0ef41Sopenharmony_ci 52401cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_CLOSING) { 52411cb0ef41Sopenharmony_ci return 0; 52421cb0ef41Sopenharmony_ci } 52431cb0ef41Sopenharmony_ci } 52441cb0ef41Sopenharmony_ci 52451cb0ef41Sopenharmony_ci if (altsvc->field_value_len == 0) { 52461cb0ef41Sopenharmony_ci return session_call_on_invalid_frame_recv_callback(session, frame, 52471cb0ef41Sopenharmony_ci NGHTTP2_ERR_PROTO); 52481cb0ef41Sopenharmony_ci } 52491cb0ef41Sopenharmony_ci 52501cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 52511cb0ef41Sopenharmony_ci} 52521cb0ef41Sopenharmony_ci 52531cb0ef41Sopenharmony_ciint nghttp2_session_on_origin_received(nghttp2_session *session, 52541cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 52551cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 52561cb0ef41Sopenharmony_ci} 52571cb0ef41Sopenharmony_ci 52581cb0ef41Sopenharmony_ciint nghttp2_session_on_priority_update_received(nghttp2_session *session, 52591cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 52601cb0ef41Sopenharmony_ci nghttp2_ext_priority_update *priority_update; 52611cb0ef41Sopenharmony_ci nghttp2_stream *stream; 52621cb0ef41Sopenharmony_ci nghttp2_priority_spec pri_spec; 52631cb0ef41Sopenharmony_ci nghttp2_extpri extpri; 52641cb0ef41Sopenharmony_ci int rv; 52651cb0ef41Sopenharmony_ci 52661cb0ef41Sopenharmony_ci assert(session->server); 52671cb0ef41Sopenharmony_ci 52681cb0ef41Sopenharmony_ci priority_update = frame->ext.payload; 52691cb0ef41Sopenharmony_ci 52701cb0ef41Sopenharmony_ci if (frame->hd.stream_id != 0) { 52711cb0ef41Sopenharmony_ci return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO, 52721cb0ef41Sopenharmony_ci "PRIORITY_UPDATE: stream_id == 0"); 52731cb0ef41Sopenharmony_ci } 52741cb0ef41Sopenharmony_ci 52751cb0ef41Sopenharmony_ci if (nghttp2_session_is_my_stream_id(session, priority_update->stream_id)) { 52761cb0ef41Sopenharmony_ci if (session_detect_idle_stream(session, priority_update->stream_id)) { 52771cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 52781cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 52791cb0ef41Sopenharmony_ci "PRIORITY_UPDATE: prioritizing idle push is not allowed"); 52801cb0ef41Sopenharmony_ci } 52811cb0ef41Sopenharmony_ci 52821cb0ef41Sopenharmony_ci /* TODO Ignore priority signal to a push stream for now */ 52831cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 52841cb0ef41Sopenharmony_ci } 52851cb0ef41Sopenharmony_ci 52861cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream_raw(session, priority_update->stream_id); 52871cb0ef41Sopenharmony_ci if (stream) { 52881cb0ef41Sopenharmony_ci /* Stream already exists. */ 52891cb0ef41Sopenharmony_ci if (stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) { 52901cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 52911cb0ef41Sopenharmony_ci } 52921cb0ef41Sopenharmony_ci } else if (session_detect_idle_stream(session, priority_update->stream_id)) { 52931cb0ef41Sopenharmony_ci if (session->num_idle_streams + session->num_incoming_streams >= 52941cb0ef41Sopenharmony_ci session->local_settings.max_concurrent_streams) { 52951cb0ef41Sopenharmony_ci return session_handle_invalid_connection( 52961cb0ef41Sopenharmony_ci session, frame, NGHTTP2_ERR_PROTO, 52971cb0ef41Sopenharmony_ci "PRIORITY_UPDATE: max concurrent streams exceeded"); 52981cb0ef41Sopenharmony_ci } 52991cb0ef41Sopenharmony_ci 53001cb0ef41Sopenharmony_ci nghttp2_priority_spec_default_init(&pri_spec); 53011cb0ef41Sopenharmony_ci stream = nghttp2_session_open_stream(session, priority_update->stream_id, 53021cb0ef41Sopenharmony_ci NGHTTP2_FLAG_NONE, &pri_spec, 53031cb0ef41Sopenharmony_ci NGHTTP2_STREAM_IDLE, NULL); 53041cb0ef41Sopenharmony_ci if (!stream) { 53051cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 53061cb0ef41Sopenharmony_ci } 53071cb0ef41Sopenharmony_ci } else { 53081cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 53091cb0ef41Sopenharmony_ci } 53101cb0ef41Sopenharmony_ci 53111cb0ef41Sopenharmony_ci extpri.urgency = NGHTTP2_EXTPRI_DEFAULT_URGENCY; 53121cb0ef41Sopenharmony_ci extpri.inc = 0; 53131cb0ef41Sopenharmony_ci 53141cb0ef41Sopenharmony_ci rv = nghttp2_http_parse_priority(&extpri, priority_update->field_value, 53151cb0ef41Sopenharmony_ci priority_update->field_value_len); 53161cb0ef41Sopenharmony_ci if (rv != 0) { 53171cb0ef41Sopenharmony_ci /* Just ignore field_value if it cannot be parsed. */ 53181cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 53191cb0ef41Sopenharmony_ci } 53201cb0ef41Sopenharmony_ci 53211cb0ef41Sopenharmony_ci rv = session_update_stream_priority(session, stream, 53221cb0ef41Sopenharmony_ci nghttp2_extpri_to_uint8(&extpri)); 53231cb0ef41Sopenharmony_ci if (rv != 0) { 53241cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 53251cb0ef41Sopenharmony_ci return rv; 53261cb0ef41Sopenharmony_ci } 53271cb0ef41Sopenharmony_ci } 53281cb0ef41Sopenharmony_ci 53291cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 53301cb0ef41Sopenharmony_ci} 53311cb0ef41Sopenharmony_ci 53321cb0ef41Sopenharmony_cistatic int session_process_altsvc_frame(nghttp2_session *session) { 53331cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 53341cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 53351cb0ef41Sopenharmony_ci 53361cb0ef41Sopenharmony_ci nghttp2_frame_unpack_altsvc_payload( 53371cb0ef41Sopenharmony_ci &frame->ext, nghttp2_get_uint16(iframe->sbuf.pos), iframe->lbuf.pos, 53381cb0ef41Sopenharmony_ci nghttp2_buf_len(&iframe->lbuf)); 53391cb0ef41Sopenharmony_ci 53401cb0ef41Sopenharmony_ci /* nghttp2_frame_unpack_altsvc_payload steals buffer from 53411cb0ef41Sopenharmony_ci iframe->lbuf */ 53421cb0ef41Sopenharmony_ci nghttp2_buf_wrap_init(&iframe->lbuf, NULL, 0); 53431cb0ef41Sopenharmony_ci 53441cb0ef41Sopenharmony_ci return nghttp2_session_on_altsvc_received(session, frame); 53451cb0ef41Sopenharmony_ci} 53461cb0ef41Sopenharmony_ci 53471cb0ef41Sopenharmony_cistatic int session_process_origin_frame(nghttp2_session *session) { 53481cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 53491cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 53501cb0ef41Sopenharmony_ci nghttp2_mem *mem = &session->mem; 53511cb0ef41Sopenharmony_ci int rv; 53521cb0ef41Sopenharmony_ci 53531cb0ef41Sopenharmony_ci rv = nghttp2_frame_unpack_origin_payload(&frame->ext, iframe->lbuf.pos, 53541cb0ef41Sopenharmony_ci nghttp2_buf_len(&iframe->lbuf), mem); 53551cb0ef41Sopenharmony_ci if (rv != 0) { 53561cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 53571cb0ef41Sopenharmony_ci return rv; 53581cb0ef41Sopenharmony_ci } 53591cb0ef41Sopenharmony_ci /* Ignore ORIGIN frame which cannot be parsed. */ 53601cb0ef41Sopenharmony_ci return 0; 53611cb0ef41Sopenharmony_ci } 53621cb0ef41Sopenharmony_ci 53631cb0ef41Sopenharmony_ci return nghttp2_session_on_origin_received(session, frame); 53641cb0ef41Sopenharmony_ci} 53651cb0ef41Sopenharmony_ci 53661cb0ef41Sopenharmony_cistatic int session_process_priority_update_frame(nghttp2_session *session) { 53671cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 53681cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 53691cb0ef41Sopenharmony_ci 53701cb0ef41Sopenharmony_ci nghttp2_frame_unpack_priority_update_payload(&frame->ext, iframe->sbuf.pos, 53711cb0ef41Sopenharmony_ci nghttp2_buf_len(&iframe->sbuf)); 53721cb0ef41Sopenharmony_ci 53731cb0ef41Sopenharmony_ci return nghttp2_session_on_priority_update_received(session, frame); 53741cb0ef41Sopenharmony_ci} 53751cb0ef41Sopenharmony_ci 53761cb0ef41Sopenharmony_cistatic int session_process_extension_frame(nghttp2_session *session) { 53771cb0ef41Sopenharmony_ci int rv; 53781cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 53791cb0ef41Sopenharmony_ci nghttp2_frame *frame = &iframe->frame; 53801cb0ef41Sopenharmony_ci 53811cb0ef41Sopenharmony_ci rv = session_call_unpack_extension_callback(session); 53821cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 53831cb0ef41Sopenharmony_ci return rv; 53841cb0ef41Sopenharmony_ci } 53851cb0ef41Sopenharmony_ci 53861cb0ef41Sopenharmony_ci /* This handles the case where rv == NGHTTP2_ERR_CANCEL as well */ 53871cb0ef41Sopenharmony_ci if (rv != 0) { 53881cb0ef41Sopenharmony_ci return 0; 53891cb0ef41Sopenharmony_ci } 53901cb0ef41Sopenharmony_ci 53911cb0ef41Sopenharmony_ci return session_call_on_frame_received(session, frame); 53921cb0ef41Sopenharmony_ci} 53931cb0ef41Sopenharmony_ci 53941cb0ef41Sopenharmony_ciint nghttp2_session_on_data_received(nghttp2_session *session, 53951cb0ef41Sopenharmony_ci nghttp2_frame *frame) { 53961cb0ef41Sopenharmony_ci int rv = 0; 53971cb0ef41Sopenharmony_ci nghttp2_stream *stream; 53981cb0ef41Sopenharmony_ci 53991cb0ef41Sopenharmony_ci /* We don't call on_frame_recv_callback if stream has been closed 54001cb0ef41Sopenharmony_ci already or being closed. */ 54011cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, frame->hd.stream_id); 54021cb0ef41Sopenharmony_ci if (!stream || stream->state == NGHTTP2_STREAM_CLOSING) { 54031cb0ef41Sopenharmony_ci /* This should be treated as stream error, but it results in lots 54041cb0ef41Sopenharmony_ci of RST_STREAM. So just ignore frame against nonexistent stream 54051cb0ef41Sopenharmony_ci for now. */ 54061cb0ef41Sopenharmony_ci return 0; 54071cb0ef41Sopenharmony_ci } 54081cb0ef41Sopenharmony_ci 54091cb0ef41Sopenharmony_ci if (session_enforce_http_messaging(session) && 54101cb0ef41Sopenharmony_ci (frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { 54111cb0ef41Sopenharmony_ci if (nghttp2_http_on_remote_end_stream(stream) != 0) { 54121cb0ef41Sopenharmony_ci rv = nghttp2_session_add_rst_stream(session, stream->stream_id, 54131cb0ef41Sopenharmony_ci NGHTTP2_PROTOCOL_ERROR); 54141cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 54151cb0ef41Sopenharmony_ci return rv; 54161cb0ef41Sopenharmony_ci } 54171cb0ef41Sopenharmony_ci 54181cb0ef41Sopenharmony_ci nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); 54191cb0ef41Sopenharmony_ci /* Don't call nghttp2_session_close_stream_if_shut_rdwr because 54201cb0ef41Sopenharmony_ci RST_STREAM has been submitted. */ 54211cb0ef41Sopenharmony_ci return 0; 54221cb0ef41Sopenharmony_ci } 54231cb0ef41Sopenharmony_ci } 54241cb0ef41Sopenharmony_ci 54251cb0ef41Sopenharmony_ci rv = session_call_on_frame_received(session, frame); 54261cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 54271cb0ef41Sopenharmony_ci return rv; 54281cb0ef41Sopenharmony_ci } 54291cb0ef41Sopenharmony_ci 54301cb0ef41Sopenharmony_ci if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { 54311cb0ef41Sopenharmony_ci nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); 54321cb0ef41Sopenharmony_ci rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); 54331cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 54341cb0ef41Sopenharmony_ci return rv; 54351cb0ef41Sopenharmony_ci } 54361cb0ef41Sopenharmony_ci } 54371cb0ef41Sopenharmony_ci return 0; 54381cb0ef41Sopenharmony_ci} 54391cb0ef41Sopenharmony_ci 54401cb0ef41Sopenharmony_ci/* For errors, this function only returns FATAL error. */ 54411cb0ef41Sopenharmony_cistatic int session_process_data_frame(nghttp2_session *session) { 54421cb0ef41Sopenharmony_ci int rv; 54431cb0ef41Sopenharmony_ci nghttp2_frame *public_data_frame = &session->iframe.frame; 54441cb0ef41Sopenharmony_ci rv = nghttp2_session_on_data_received(session, public_data_frame); 54451cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 54461cb0ef41Sopenharmony_ci return rv; 54471cb0ef41Sopenharmony_ci } 54481cb0ef41Sopenharmony_ci return 0; 54491cb0ef41Sopenharmony_ci} 54501cb0ef41Sopenharmony_ci 54511cb0ef41Sopenharmony_ci/* 54521cb0ef41Sopenharmony_ci * Now we have SETTINGS synchronization, flow control error can be 54531cb0ef41Sopenharmony_ci * detected strictly. If DATA frame is received with length > 0 and 54541cb0ef41Sopenharmony_ci * current received window size + delta length is strictly larger than 54551cb0ef41Sopenharmony_ci * local window size, it is subject to FLOW_CONTROL_ERROR, so return 54561cb0ef41Sopenharmony_ci * -1. Note that local_window_size is calculated after SETTINGS ACK is 54571cb0ef41Sopenharmony_ci * received from peer, so peer must honor this limit. If the resulting 54581cb0ef41Sopenharmony_ci * recv_window_size is strictly larger than NGHTTP2_MAX_WINDOW_SIZE, 54591cb0ef41Sopenharmony_ci * return -1 too. 54601cb0ef41Sopenharmony_ci */ 54611cb0ef41Sopenharmony_cistatic int adjust_recv_window_size(int32_t *recv_window_size_ptr, size_t delta, 54621cb0ef41Sopenharmony_ci int32_t local_window_size) { 54631cb0ef41Sopenharmony_ci if (*recv_window_size_ptr > local_window_size - (int32_t)delta || 54641cb0ef41Sopenharmony_ci *recv_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - (int32_t)delta) { 54651cb0ef41Sopenharmony_ci return -1; 54661cb0ef41Sopenharmony_ci } 54671cb0ef41Sopenharmony_ci *recv_window_size_ptr += (int32_t)delta; 54681cb0ef41Sopenharmony_ci return 0; 54691cb0ef41Sopenharmony_ci} 54701cb0ef41Sopenharmony_ci 54711cb0ef41Sopenharmony_ciint nghttp2_session_update_recv_stream_window_size(nghttp2_session *session, 54721cb0ef41Sopenharmony_ci nghttp2_stream *stream, 54731cb0ef41Sopenharmony_ci size_t delta_size, 54741cb0ef41Sopenharmony_ci int send_window_update) { 54751cb0ef41Sopenharmony_ci int rv; 54761cb0ef41Sopenharmony_ci rv = adjust_recv_window_size(&stream->recv_window_size, delta_size, 54771cb0ef41Sopenharmony_ci stream->local_window_size); 54781cb0ef41Sopenharmony_ci if (rv != 0) { 54791cb0ef41Sopenharmony_ci return nghttp2_session_add_rst_stream(session, stream->stream_id, 54801cb0ef41Sopenharmony_ci NGHTTP2_FLOW_CONTROL_ERROR); 54811cb0ef41Sopenharmony_ci } 54821cb0ef41Sopenharmony_ci /* We don't have to send WINDOW_UPDATE if the data received is the 54831cb0ef41Sopenharmony_ci last chunk in the incoming stream. */ 54841cb0ef41Sopenharmony_ci /* We have to use local_settings here because it is the constraint 54851cb0ef41Sopenharmony_ci the remote endpoint should honor. */ 54861cb0ef41Sopenharmony_ci if (send_window_update && 54871cb0ef41Sopenharmony_ci !(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) && 54881cb0ef41Sopenharmony_ci stream->window_update_queued == 0 && 54891cb0ef41Sopenharmony_ci nghttp2_should_send_window_update(stream->local_window_size, 54901cb0ef41Sopenharmony_ci stream->recv_window_size)) { 54911cb0ef41Sopenharmony_ci rv = nghttp2_session_add_window_update(session, NGHTTP2_FLAG_NONE, 54921cb0ef41Sopenharmony_ci stream->stream_id, 54931cb0ef41Sopenharmony_ci stream->recv_window_size); 54941cb0ef41Sopenharmony_ci if (rv != 0) { 54951cb0ef41Sopenharmony_ci return rv; 54961cb0ef41Sopenharmony_ci } 54971cb0ef41Sopenharmony_ci 54981cb0ef41Sopenharmony_ci stream->recv_window_size = 0; 54991cb0ef41Sopenharmony_ci } 55001cb0ef41Sopenharmony_ci return 0; 55011cb0ef41Sopenharmony_ci} 55021cb0ef41Sopenharmony_ci 55031cb0ef41Sopenharmony_ciint nghttp2_session_update_recv_connection_window_size(nghttp2_session *session, 55041cb0ef41Sopenharmony_ci size_t delta_size) { 55051cb0ef41Sopenharmony_ci int rv; 55061cb0ef41Sopenharmony_ci rv = adjust_recv_window_size(&session->recv_window_size, delta_size, 55071cb0ef41Sopenharmony_ci session->local_window_size); 55081cb0ef41Sopenharmony_ci if (rv != 0) { 55091cb0ef41Sopenharmony_ci return nghttp2_session_terminate_session(session, 55101cb0ef41Sopenharmony_ci NGHTTP2_FLOW_CONTROL_ERROR); 55111cb0ef41Sopenharmony_ci } 55121cb0ef41Sopenharmony_ci if (!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) && 55131cb0ef41Sopenharmony_ci session->window_update_queued == 0 && 55141cb0ef41Sopenharmony_ci nghttp2_should_send_window_update(session->local_window_size, 55151cb0ef41Sopenharmony_ci session->recv_window_size)) { 55161cb0ef41Sopenharmony_ci /* Use stream ID 0 to update connection-level flow control 55171cb0ef41Sopenharmony_ci window */ 55181cb0ef41Sopenharmony_ci rv = nghttp2_session_add_window_update(session, NGHTTP2_FLAG_NONE, 0, 55191cb0ef41Sopenharmony_ci session->recv_window_size); 55201cb0ef41Sopenharmony_ci if (rv != 0) { 55211cb0ef41Sopenharmony_ci return rv; 55221cb0ef41Sopenharmony_ci } 55231cb0ef41Sopenharmony_ci 55241cb0ef41Sopenharmony_ci session->recv_window_size = 0; 55251cb0ef41Sopenharmony_ci } 55261cb0ef41Sopenharmony_ci return 0; 55271cb0ef41Sopenharmony_ci} 55281cb0ef41Sopenharmony_ci 55291cb0ef41Sopenharmony_cistatic int session_update_consumed_size(nghttp2_session *session, 55301cb0ef41Sopenharmony_ci int32_t *consumed_size_ptr, 55311cb0ef41Sopenharmony_ci int32_t *recv_window_size_ptr, 55321cb0ef41Sopenharmony_ci uint8_t window_update_queued, 55331cb0ef41Sopenharmony_ci int32_t stream_id, size_t delta_size, 55341cb0ef41Sopenharmony_ci int32_t local_window_size) { 55351cb0ef41Sopenharmony_ci int32_t recv_size; 55361cb0ef41Sopenharmony_ci int rv; 55371cb0ef41Sopenharmony_ci 55381cb0ef41Sopenharmony_ci if ((size_t)*consumed_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta_size) { 55391cb0ef41Sopenharmony_ci return nghttp2_session_terminate_session(session, 55401cb0ef41Sopenharmony_ci NGHTTP2_FLOW_CONTROL_ERROR); 55411cb0ef41Sopenharmony_ci } 55421cb0ef41Sopenharmony_ci 55431cb0ef41Sopenharmony_ci *consumed_size_ptr += (int32_t)delta_size; 55441cb0ef41Sopenharmony_ci 55451cb0ef41Sopenharmony_ci if (window_update_queued == 0) { 55461cb0ef41Sopenharmony_ci /* recv_window_size may be smaller than consumed_size, because it 55471cb0ef41Sopenharmony_ci may be decreased by negative value with 55481cb0ef41Sopenharmony_ci nghttp2_submit_window_update(). */ 55491cb0ef41Sopenharmony_ci recv_size = nghttp2_min(*consumed_size_ptr, *recv_window_size_ptr); 55501cb0ef41Sopenharmony_ci 55511cb0ef41Sopenharmony_ci if (nghttp2_should_send_window_update(local_window_size, recv_size)) { 55521cb0ef41Sopenharmony_ci rv = nghttp2_session_add_window_update(session, NGHTTP2_FLAG_NONE, 55531cb0ef41Sopenharmony_ci stream_id, recv_size); 55541cb0ef41Sopenharmony_ci 55551cb0ef41Sopenharmony_ci if (rv != 0) { 55561cb0ef41Sopenharmony_ci return rv; 55571cb0ef41Sopenharmony_ci } 55581cb0ef41Sopenharmony_ci 55591cb0ef41Sopenharmony_ci *recv_window_size_ptr -= recv_size; 55601cb0ef41Sopenharmony_ci *consumed_size_ptr -= recv_size; 55611cb0ef41Sopenharmony_ci } 55621cb0ef41Sopenharmony_ci } 55631cb0ef41Sopenharmony_ci 55641cb0ef41Sopenharmony_ci return 0; 55651cb0ef41Sopenharmony_ci} 55661cb0ef41Sopenharmony_ci 55671cb0ef41Sopenharmony_cistatic int session_update_stream_consumed_size(nghttp2_session *session, 55681cb0ef41Sopenharmony_ci nghttp2_stream *stream, 55691cb0ef41Sopenharmony_ci size_t delta_size) { 55701cb0ef41Sopenharmony_ci return session_update_consumed_size( 55711cb0ef41Sopenharmony_ci session, &stream->consumed_size, &stream->recv_window_size, 55721cb0ef41Sopenharmony_ci stream->window_update_queued, stream->stream_id, delta_size, 55731cb0ef41Sopenharmony_ci stream->local_window_size); 55741cb0ef41Sopenharmony_ci} 55751cb0ef41Sopenharmony_ci 55761cb0ef41Sopenharmony_cistatic int session_update_connection_consumed_size(nghttp2_session *session, 55771cb0ef41Sopenharmony_ci size_t delta_size) { 55781cb0ef41Sopenharmony_ci return session_update_consumed_size( 55791cb0ef41Sopenharmony_ci session, &session->consumed_size, &session->recv_window_size, 55801cb0ef41Sopenharmony_ci session->window_update_queued, 0, delta_size, session->local_window_size); 55811cb0ef41Sopenharmony_ci} 55821cb0ef41Sopenharmony_ci 55831cb0ef41Sopenharmony_ci/* 55841cb0ef41Sopenharmony_ci * Checks that we can receive the DATA frame for stream, which is 55851cb0ef41Sopenharmony_ci * indicated by |session->iframe.frame.hd.stream_id|. If it is a 55861cb0ef41Sopenharmony_ci * connection error situation, GOAWAY frame will be issued by this 55871cb0ef41Sopenharmony_ci * function. 55881cb0ef41Sopenharmony_ci * 55891cb0ef41Sopenharmony_ci * If the DATA frame is allowed, returns 0. 55901cb0ef41Sopenharmony_ci * 55911cb0ef41Sopenharmony_ci * This function returns 0 if it succeeds, or one of the following 55921cb0ef41Sopenharmony_ci * negative error codes: 55931cb0ef41Sopenharmony_ci * 55941cb0ef41Sopenharmony_ci * NGHTTP2_ERR_IGN_PAYLOAD 55951cb0ef41Sopenharmony_ci * The reception of DATA frame is connection error; or should be 55961cb0ef41Sopenharmony_ci * ignored. 55971cb0ef41Sopenharmony_ci * NGHTTP2_ERR_NOMEM 55981cb0ef41Sopenharmony_ci * Out of memory. 55991cb0ef41Sopenharmony_ci */ 56001cb0ef41Sopenharmony_cistatic int session_on_data_received_fail_fast(nghttp2_session *session) { 56011cb0ef41Sopenharmony_ci int rv; 56021cb0ef41Sopenharmony_ci nghttp2_stream *stream; 56031cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe; 56041cb0ef41Sopenharmony_ci int32_t stream_id; 56051cb0ef41Sopenharmony_ci const char *failure_reason; 56061cb0ef41Sopenharmony_ci uint32_t error_code = NGHTTP2_PROTOCOL_ERROR; 56071cb0ef41Sopenharmony_ci 56081cb0ef41Sopenharmony_ci iframe = &session->iframe; 56091cb0ef41Sopenharmony_ci stream_id = iframe->frame.hd.stream_id; 56101cb0ef41Sopenharmony_ci 56111cb0ef41Sopenharmony_ci if (stream_id == 0) { 56121cb0ef41Sopenharmony_ci /* The spec says that if a DATA frame is received whose stream ID 56131cb0ef41Sopenharmony_ci is 0, the recipient MUST respond with a connection error of 56141cb0ef41Sopenharmony_ci type PROTOCOL_ERROR. */ 56151cb0ef41Sopenharmony_ci failure_reason = "DATA: stream_id == 0"; 56161cb0ef41Sopenharmony_ci goto fail; 56171cb0ef41Sopenharmony_ci } 56181cb0ef41Sopenharmony_ci 56191cb0ef41Sopenharmony_ci if (session_detect_idle_stream(session, stream_id)) { 56201cb0ef41Sopenharmony_ci failure_reason = "DATA: stream in idle"; 56211cb0ef41Sopenharmony_ci error_code = NGHTTP2_PROTOCOL_ERROR; 56221cb0ef41Sopenharmony_ci goto fail; 56231cb0ef41Sopenharmony_ci } 56241cb0ef41Sopenharmony_ci 56251cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 56261cb0ef41Sopenharmony_ci if (!stream) { 56271cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream_raw(session, stream_id); 56281cb0ef41Sopenharmony_ci if (stream && (stream->shut_flags & NGHTTP2_SHUT_RD)) { 56291cb0ef41Sopenharmony_ci failure_reason = "DATA: stream closed"; 56301cb0ef41Sopenharmony_ci error_code = NGHTTP2_STREAM_CLOSED; 56311cb0ef41Sopenharmony_ci goto fail; 56321cb0ef41Sopenharmony_ci } 56331cb0ef41Sopenharmony_ci 56341cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_PAYLOAD; 56351cb0ef41Sopenharmony_ci } 56361cb0ef41Sopenharmony_ci if (stream->shut_flags & NGHTTP2_SHUT_RD) { 56371cb0ef41Sopenharmony_ci failure_reason = "DATA: stream in half-closed(remote)"; 56381cb0ef41Sopenharmony_ci error_code = NGHTTP2_STREAM_CLOSED; 56391cb0ef41Sopenharmony_ci goto fail; 56401cb0ef41Sopenharmony_ci } 56411cb0ef41Sopenharmony_ci 56421cb0ef41Sopenharmony_ci if (nghttp2_session_is_my_stream_id(session, stream_id)) { 56431cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_CLOSING) { 56441cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_PAYLOAD; 56451cb0ef41Sopenharmony_ci } 56461cb0ef41Sopenharmony_ci if (stream->state != NGHTTP2_STREAM_OPENED) { 56471cb0ef41Sopenharmony_ci failure_reason = "DATA: stream not opened"; 56481cb0ef41Sopenharmony_ci goto fail; 56491cb0ef41Sopenharmony_ci } 56501cb0ef41Sopenharmony_ci return 0; 56511cb0ef41Sopenharmony_ci } 56521cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_RESERVED) { 56531cb0ef41Sopenharmony_ci failure_reason = "DATA: stream in reserved"; 56541cb0ef41Sopenharmony_ci goto fail; 56551cb0ef41Sopenharmony_ci } 56561cb0ef41Sopenharmony_ci if (stream->state == NGHTTP2_STREAM_CLOSING) { 56571cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_PAYLOAD; 56581cb0ef41Sopenharmony_ci } 56591cb0ef41Sopenharmony_ci return 0; 56601cb0ef41Sopenharmony_cifail: 56611cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session_with_reason(session, error_code, 56621cb0ef41Sopenharmony_ci failure_reason); 56631cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 56641cb0ef41Sopenharmony_ci return rv; 56651cb0ef41Sopenharmony_ci } 56661cb0ef41Sopenharmony_ci return NGHTTP2_ERR_IGN_PAYLOAD; 56671cb0ef41Sopenharmony_ci} 56681cb0ef41Sopenharmony_ci 56691cb0ef41Sopenharmony_cistatic size_t inbound_frame_payload_readlen(nghttp2_inbound_frame *iframe, 56701cb0ef41Sopenharmony_ci const uint8_t *in, 56711cb0ef41Sopenharmony_ci const uint8_t *last) { 56721cb0ef41Sopenharmony_ci return nghttp2_min((size_t)(last - in), iframe->payloadleft); 56731cb0ef41Sopenharmony_ci} 56741cb0ef41Sopenharmony_ci 56751cb0ef41Sopenharmony_ci/* 56761cb0ef41Sopenharmony_ci * Resets iframe->sbuf and advance its mark pointer by |left| bytes. 56771cb0ef41Sopenharmony_ci */ 56781cb0ef41Sopenharmony_cistatic void inbound_frame_set_mark(nghttp2_inbound_frame *iframe, size_t left) { 56791cb0ef41Sopenharmony_ci nghttp2_buf_reset(&iframe->sbuf); 56801cb0ef41Sopenharmony_ci iframe->sbuf.mark += left; 56811cb0ef41Sopenharmony_ci} 56821cb0ef41Sopenharmony_ci 56831cb0ef41Sopenharmony_cistatic size_t inbound_frame_buf_read(nghttp2_inbound_frame *iframe, 56841cb0ef41Sopenharmony_ci const uint8_t *in, const uint8_t *last) { 56851cb0ef41Sopenharmony_ci size_t readlen; 56861cb0ef41Sopenharmony_ci 56871cb0ef41Sopenharmony_ci readlen = 56881cb0ef41Sopenharmony_ci nghttp2_min((size_t)(last - in), nghttp2_buf_mark_avail(&iframe->sbuf)); 56891cb0ef41Sopenharmony_ci 56901cb0ef41Sopenharmony_ci iframe->sbuf.last = nghttp2_cpymem(iframe->sbuf.last, in, readlen); 56911cb0ef41Sopenharmony_ci 56921cb0ef41Sopenharmony_ci return readlen; 56931cb0ef41Sopenharmony_ci} 56941cb0ef41Sopenharmony_ci 56951cb0ef41Sopenharmony_ci/* 56961cb0ef41Sopenharmony_ci * Unpacks SETTINGS entry in iframe->sbuf. 56971cb0ef41Sopenharmony_ci */ 56981cb0ef41Sopenharmony_cistatic void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) { 56991cb0ef41Sopenharmony_ci nghttp2_settings_entry iv; 57001cb0ef41Sopenharmony_ci nghttp2_settings_entry *min_header_table_size_entry; 57011cb0ef41Sopenharmony_ci size_t i; 57021cb0ef41Sopenharmony_ci 57031cb0ef41Sopenharmony_ci nghttp2_frame_unpack_settings_entry(&iv, iframe->sbuf.pos); 57041cb0ef41Sopenharmony_ci 57051cb0ef41Sopenharmony_ci switch (iv.settings_id) { 57061cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: 57071cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_ENABLE_PUSH: 57081cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: 57091cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: 57101cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: 57111cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: 57121cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: 57131cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES: 57141cb0ef41Sopenharmony_ci break; 57151cb0ef41Sopenharmony_ci default: 57161cb0ef41Sopenharmony_ci DEBUGF("recv: unknown settings id=0x%02x\n", iv.settings_id); 57171cb0ef41Sopenharmony_ci 57181cb0ef41Sopenharmony_ci iframe->iv[iframe->niv++] = iv; 57191cb0ef41Sopenharmony_ci 57201cb0ef41Sopenharmony_ci return; 57211cb0ef41Sopenharmony_ci } 57221cb0ef41Sopenharmony_ci 57231cb0ef41Sopenharmony_ci for (i = 0; i < iframe->niv; ++i) { 57241cb0ef41Sopenharmony_ci if (iframe->iv[i].settings_id == iv.settings_id) { 57251cb0ef41Sopenharmony_ci iframe->iv[i] = iv; 57261cb0ef41Sopenharmony_ci break; 57271cb0ef41Sopenharmony_ci } 57281cb0ef41Sopenharmony_ci } 57291cb0ef41Sopenharmony_ci 57301cb0ef41Sopenharmony_ci if (i == iframe->niv) { 57311cb0ef41Sopenharmony_ci iframe->iv[iframe->niv++] = iv; 57321cb0ef41Sopenharmony_ci } 57331cb0ef41Sopenharmony_ci 57341cb0ef41Sopenharmony_ci if (iv.settings_id == NGHTTP2_SETTINGS_HEADER_TABLE_SIZE) { 57351cb0ef41Sopenharmony_ci /* Keep track of minimum value of SETTINGS_HEADER_TABLE_SIZE */ 57361cb0ef41Sopenharmony_ci min_header_table_size_entry = &iframe->iv[iframe->max_niv - 1]; 57371cb0ef41Sopenharmony_ci 57381cb0ef41Sopenharmony_ci if (iv.value < min_header_table_size_entry->value) { 57391cb0ef41Sopenharmony_ci min_header_table_size_entry->value = iv.value; 57401cb0ef41Sopenharmony_ci } 57411cb0ef41Sopenharmony_ci } 57421cb0ef41Sopenharmony_ci} 57431cb0ef41Sopenharmony_ci 57441cb0ef41Sopenharmony_ci/* 57451cb0ef41Sopenharmony_ci * Checks PADDED flags and set iframe->sbuf to read them accordingly. 57461cb0ef41Sopenharmony_ci * If padding is set, this function returns 1. If no padding is set, 57471cb0ef41Sopenharmony_ci * this function returns 0. On error, returns -1. 57481cb0ef41Sopenharmony_ci */ 57491cb0ef41Sopenharmony_cistatic int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe, 57501cb0ef41Sopenharmony_ci nghttp2_frame_hd *hd) { 57511cb0ef41Sopenharmony_ci if (hd->flags & NGHTTP2_FLAG_PADDED) { 57521cb0ef41Sopenharmony_ci if (hd->length < 1) { 57531cb0ef41Sopenharmony_ci return -1; 57541cb0ef41Sopenharmony_ci } 57551cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, 1); 57561cb0ef41Sopenharmony_ci return 1; 57571cb0ef41Sopenharmony_ci } 57581cb0ef41Sopenharmony_ci DEBUGF("recv: no padding in payload\n"); 57591cb0ef41Sopenharmony_ci return 0; 57601cb0ef41Sopenharmony_ci} 57611cb0ef41Sopenharmony_ci 57621cb0ef41Sopenharmony_ci/* 57631cb0ef41Sopenharmony_ci * Computes number of padding based on flags. This function returns 57641cb0ef41Sopenharmony_ci * the calculated length if it succeeds, or -1. 57651cb0ef41Sopenharmony_ci */ 57661cb0ef41Sopenharmony_cistatic ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) { 57671cb0ef41Sopenharmony_ci size_t padlen; 57681cb0ef41Sopenharmony_ci 57691cb0ef41Sopenharmony_ci /* 1 for Pad Length field */ 57701cb0ef41Sopenharmony_ci padlen = (size_t)(iframe->sbuf.pos[0] + 1); 57711cb0ef41Sopenharmony_ci 57721cb0ef41Sopenharmony_ci DEBUGF("recv: padlen=%zu\n", padlen); 57731cb0ef41Sopenharmony_ci 57741cb0ef41Sopenharmony_ci /* We cannot use iframe->frame.hd.length because of CONTINUATION */ 57751cb0ef41Sopenharmony_ci if (padlen - 1 > iframe->payloadleft) { 57761cb0ef41Sopenharmony_ci return -1; 57771cb0ef41Sopenharmony_ci } 57781cb0ef41Sopenharmony_ci 57791cb0ef41Sopenharmony_ci iframe->padlen = padlen; 57801cb0ef41Sopenharmony_ci 57811cb0ef41Sopenharmony_ci return (ssize_t)padlen; 57821cb0ef41Sopenharmony_ci} 57831cb0ef41Sopenharmony_ci 57841cb0ef41Sopenharmony_ci/* 57851cb0ef41Sopenharmony_ci * This function returns the effective payload length in the data of 57861cb0ef41Sopenharmony_ci * length |readlen| when the remaining payload is |payloadleft|. The 57871cb0ef41Sopenharmony_ci * |payloadleft| does not include |readlen|. If padding was started 57881cb0ef41Sopenharmony_ci * strictly before this data chunk, this function returns -1. 57891cb0ef41Sopenharmony_ci */ 57901cb0ef41Sopenharmony_cistatic ssize_t inbound_frame_effective_readlen(nghttp2_inbound_frame *iframe, 57911cb0ef41Sopenharmony_ci size_t payloadleft, 57921cb0ef41Sopenharmony_ci size_t readlen) { 57931cb0ef41Sopenharmony_ci size_t trail_padlen = 57941cb0ef41Sopenharmony_ci nghttp2_frame_trail_padlen(&iframe->frame, iframe->padlen); 57951cb0ef41Sopenharmony_ci 57961cb0ef41Sopenharmony_ci if (trail_padlen > payloadleft) { 57971cb0ef41Sopenharmony_ci size_t padlen; 57981cb0ef41Sopenharmony_ci padlen = trail_padlen - payloadleft; 57991cb0ef41Sopenharmony_ci if (readlen < padlen) { 58001cb0ef41Sopenharmony_ci return -1; 58011cb0ef41Sopenharmony_ci } 58021cb0ef41Sopenharmony_ci return (ssize_t)(readlen - padlen); 58031cb0ef41Sopenharmony_ci } 58041cb0ef41Sopenharmony_ci return (ssize_t)(readlen); 58051cb0ef41Sopenharmony_ci} 58061cb0ef41Sopenharmony_ci 58071cb0ef41Sopenharmony_cistatic const uint8_t static_in[] = {0}; 58081cb0ef41Sopenharmony_ci 58091cb0ef41Sopenharmony_cissize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, 58101cb0ef41Sopenharmony_ci size_t inlen) { 58111cb0ef41Sopenharmony_ci const uint8_t *first, *last; 58121cb0ef41Sopenharmony_ci nghttp2_inbound_frame *iframe = &session->iframe; 58131cb0ef41Sopenharmony_ci size_t readlen; 58141cb0ef41Sopenharmony_ci ssize_t padlen; 58151cb0ef41Sopenharmony_ci int rv; 58161cb0ef41Sopenharmony_ci int busy = 0; 58171cb0ef41Sopenharmony_ci nghttp2_frame_hd cont_hd; 58181cb0ef41Sopenharmony_ci nghttp2_stream *stream; 58191cb0ef41Sopenharmony_ci size_t pri_fieldlen; 58201cb0ef41Sopenharmony_ci nghttp2_mem *mem; 58211cb0ef41Sopenharmony_ci 58221cb0ef41Sopenharmony_ci if (in == NULL) { 58231cb0ef41Sopenharmony_ci assert(inlen == 0); 58241cb0ef41Sopenharmony_ci in = static_in; 58251cb0ef41Sopenharmony_ci } 58261cb0ef41Sopenharmony_ci 58271cb0ef41Sopenharmony_ci first = in; 58281cb0ef41Sopenharmony_ci last = in + inlen; 58291cb0ef41Sopenharmony_ci 58301cb0ef41Sopenharmony_ci DEBUGF("recv: connection recv_window_size=%d, local_window=%d\n", 58311cb0ef41Sopenharmony_ci session->recv_window_size, session->local_window_size); 58321cb0ef41Sopenharmony_ci 58331cb0ef41Sopenharmony_ci mem = &session->mem; 58341cb0ef41Sopenharmony_ci 58351cb0ef41Sopenharmony_ci /* We may have idle streams more than we expect (e.g., 58361cb0ef41Sopenharmony_ci nghttp2_session_change_stream_priority() or 58371cb0ef41Sopenharmony_ci nghttp2_session_create_idle_stream()). Adjust them here. */ 58381cb0ef41Sopenharmony_ci rv = nghttp2_session_adjust_idle_stream(session); 58391cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 58401cb0ef41Sopenharmony_ci return rv; 58411cb0ef41Sopenharmony_ci } 58421cb0ef41Sopenharmony_ci 58431cb0ef41Sopenharmony_ci if (!nghttp2_session_want_read(session)) { 58441cb0ef41Sopenharmony_ci return (ssize_t)inlen; 58451cb0ef41Sopenharmony_ci } 58461cb0ef41Sopenharmony_ci 58471cb0ef41Sopenharmony_ci for (;;) { 58481cb0ef41Sopenharmony_ci switch (iframe->state) { 58491cb0ef41Sopenharmony_ci case NGHTTP2_IB_READ_CLIENT_MAGIC: 58501cb0ef41Sopenharmony_ci readlen = nghttp2_min(inlen, iframe->payloadleft); 58511cb0ef41Sopenharmony_ci 58521cb0ef41Sopenharmony_ci if (memcmp(&NGHTTP2_CLIENT_MAGIC[NGHTTP2_CLIENT_MAGIC_LEN - 58531cb0ef41Sopenharmony_ci iframe->payloadleft], 58541cb0ef41Sopenharmony_ci in, readlen) != 0) { 58551cb0ef41Sopenharmony_ci return NGHTTP2_ERR_BAD_CLIENT_MAGIC; 58561cb0ef41Sopenharmony_ci } 58571cb0ef41Sopenharmony_ci 58581cb0ef41Sopenharmony_ci iframe->payloadleft -= readlen; 58591cb0ef41Sopenharmony_ci in += readlen; 58601cb0ef41Sopenharmony_ci 58611cb0ef41Sopenharmony_ci if (iframe->payloadleft == 0) { 58621cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 58631cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_FIRST_SETTINGS; 58641cb0ef41Sopenharmony_ci } 58651cb0ef41Sopenharmony_ci 58661cb0ef41Sopenharmony_ci break; 58671cb0ef41Sopenharmony_ci case NGHTTP2_IB_READ_FIRST_SETTINGS: 58681cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_READ_FIRST_SETTINGS]\n"); 58691cb0ef41Sopenharmony_ci 58701cb0ef41Sopenharmony_ci readlen = inbound_frame_buf_read(iframe, in, last); 58711cb0ef41Sopenharmony_ci in += readlen; 58721cb0ef41Sopenharmony_ci 58731cb0ef41Sopenharmony_ci if (nghttp2_buf_mark_avail(&iframe->sbuf)) { 58741cb0ef41Sopenharmony_ci return (ssize_t)(in - first); 58751cb0ef41Sopenharmony_ci } 58761cb0ef41Sopenharmony_ci 58771cb0ef41Sopenharmony_ci if (iframe->sbuf.pos[3] != NGHTTP2_SETTINGS || 58781cb0ef41Sopenharmony_ci (iframe->sbuf.pos[4] & NGHTTP2_FLAG_ACK)) { 58791cb0ef41Sopenharmony_ci rv = session_call_error_callback( 58801cb0ef41Sopenharmony_ci session, NGHTTP2_ERR_SETTINGS_EXPECTED, 58811cb0ef41Sopenharmony_ci "Remote peer returned unexpected data while we expected " 58821cb0ef41Sopenharmony_ci "SETTINGS frame. Perhaps, peer does not support HTTP/2 " 58831cb0ef41Sopenharmony_ci "properly."); 58841cb0ef41Sopenharmony_ci 58851cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 58861cb0ef41Sopenharmony_ci return rv; 58871cb0ef41Sopenharmony_ci } 58881cb0ef41Sopenharmony_ci 58891cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session_with_reason( 58901cb0ef41Sopenharmony_ci session, NGHTTP2_PROTOCOL_ERROR, "SETTINGS expected"); 58911cb0ef41Sopenharmony_ci 58921cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 58931cb0ef41Sopenharmony_ci return rv; 58941cb0ef41Sopenharmony_ci } 58951cb0ef41Sopenharmony_ci 58961cb0ef41Sopenharmony_ci return (ssize_t)inlen; 58971cb0ef41Sopenharmony_ci } 58981cb0ef41Sopenharmony_ci 58991cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_HEAD; 59001cb0ef41Sopenharmony_ci 59011cb0ef41Sopenharmony_ci /* Fall through */ 59021cb0ef41Sopenharmony_ci case NGHTTP2_IB_READ_HEAD: { 59031cb0ef41Sopenharmony_ci int on_begin_frame_called = 0; 59041cb0ef41Sopenharmony_ci 59051cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_READ_HEAD]\n"); 59061cb0ef41Sopenharmony_ci 59071cb0ef41Sopenharmony_ci readlen = inbound_frame_buf_read(iframe, in, last); 59081cb0ef41Sopenharmony_ci in += readlen; 59091cb0ef41Sopenharmony_ci 59101cb0ef41Sopenharmony_ci if (nghttp2_buf_mark_avail(&iframe->sbuf)) { 59111cb0ef41Sopenharmony_ci return (ssize_t)(in - first); 59121cb0ef41Sopenharmony_ci } 59131cb0ef41Sopenharmony_ci 59141cb0ef41Sopenharmony_ci nghttp2_frame_unpack_frame_hd(&iframe->frame.hd, iframe->sbuf.pos); 59151cb0ef41Sopenharmony_ci iframe->payloadleft = iframe->frame.hd.length; 59161cb0ef41Sopenharmony_ci 59171cb0ef41Sopenharmony_ci DEBUGF("recv: payloadlen=%zu, type=%u, flags=0x%02x, stream_id=%d\n", 59181cb0ef41Sopenharmony_ci iframe->frame.hd.length, iframe->frame.hd.type, 59191cb0ef41Sopenharmony_ci iframe->frame.hd.flags, iframe->frame.hd.stream_id); 59201cb0ef41Sopenharmony_ci 59211cb0ef41Sopenharmony_ci if (iframe->frame.hd.length > session->local_settings.max_frame_size) { 59221cb0ef41Sopenharmony_ci DEBUGF("recv: length is too large %zu > %u\n", iframe->frame.hd.length, 59231cb0ef41Sopenharmony_ci session->local_settings.max_frame_size); 59241cb0ef41Sopenharmony_ci 59251cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session_with_reason( 59261cb0ef41Sopenharmony_ci session, NGHTTP2_FRAME_SIZE_ERROR, "too large frame size"); 59271cb0ef41Sopenharmony_ci 59281cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 59291cb0ef41Sopenharmony_ci return rv; 59301cb0ef41Sopenharmony_ci } 59311cb0ef41Sopenharmony_ci 59321cb0ef41Sopenharmony_ci return (ssize_t)inlen; 59331cb0ef41Sopenharmony_ci } 59341cb0ef41Sopenharmony_ci 59351cb0ef41Sopenharmony_ci switch (iframe->frame.hd.type) { 59361cb0ef41Sopenharmony_ci case NGHTTP2_DATA: { 59371cb0ef41Sopenharmony_ci DEBUGF("recv: DATA\n"); 59381cb0ef41Sopenharmony_ci 59391cb0ef41Sopenharmony_ci iframe->frame.hd.flags &= 59401cb0ef41Sopenharmony_ci (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PADDED); 59411cb0ef41Sopenharmony_ci /* Check stream is open. If it is not open or closing, 59421cb0ef41Sopenharmony_ci ignore payload. */ 59431cb0ef41Sopenharmony_ci busy = 1; 59441cb0ef41Sopenharmony_ci 59451cb0ef41Sopenharmony_ci rv = session_on_data_received_fail_fast(session); 59461cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 59471cb0ef41Sopenharmony_ci return (ssize_t)inlen; 59481cb0ef41Sopenharmony_ci } 59491cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_IGN_PAYLOAD) { 59501cb0ef41Sopenharmony_ci DEBUGF("recv: DATA not allowed stream_id=%d\n", 59511cb0ef41Sopenharmony_ci iframe->frame.hd.stream_id); 59521cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_DATA; 59531cb0ef41Sopenharmony_ci break; 59541cb0ef41Sopenharmony_ci } 59551cb0ef41Sopenharmony_ci 59561cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 59571cb0ef41Sopenharmony_ci return rv; 59581cb0ef41Sopenharmony_ci } 59591cb0ef41Sopenharmony_ci 59601cb0ef41Sopenharmony_ci rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); 59611cb0ef41Sopenharmony_ci if (rv < 0) { 59621cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session_with_reason( 59631cb0ef41Sopenharmony_ci session, NGHTTP2_PROTOCOL_ERROR, 59641cb0ef41Sopenharmony_ci "DATA: insufficient padding space"); 59651cb0ef41Sopenharmony_ci 59661cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 59671cb0ef41Sopenharmony_ci return rv; 59681cb0ef41Sopenharmony_ci } 59691cb0ef41Sopenharmony_ci return (ssize_t)inlen; 59701cb0ef41Sopenharmony_ci } 59711cb0ef41Sopenharmony_ci 59721cb0ef41Sopenharmony_ci if (rv == 1) { 59731cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_PAD_DATA; 59741cb0ef41Sopenharmony_ci break; 59751cb0ef41Sopenharmony_ci } 59761cb0ef41Sopenharmony_ci 59771cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_DATA; 59781cb0ef41Sopenharmony_ci break; 59791cb0ef41Sopenharmony_ci } 59801cb0ef41Sopenharmony_ci case NGHTTP2_HEADERS: 59811cb0ef41Sopenharmony_ci 59821cb0ef41Sopenharmony_ci DEBUGF("recv: HEADERS\n"); 59831cb0ef41Sopenharmony_ci 59841cb0ef41Sopenharmony_ci iframe->frame.hd.flags &= 59851cb0ef41Sopenharmony_ci (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | 59861cb0ef41Sopenharmony_ci NGHTTP2_FLAG_PADDED | NGHTTP2_FLAG_PRIORITY); 59871cb0ef41Sopenharmony_ci 59881cb0ef41Sopenharmony_ci rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); 59891cb0ef41Sopenharmony_ci if (rv < 0) { 59901cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session_with_reason( 59911cb0ef41Sopenharmony_ci session, NGHTTP2_PROTOCOL_ERROR, 59921cb0ef41Sopenharmony_ci "HEADERS: insufficient padding space"); 59931cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 59941cb0ef41Sopenharmony_ci return rv; 59951cb0ef41Sopenharmony_ci } 59961cb0ef41Sopenharmony_ci return (ssize_t)inlen; 59971cb0ef41Sopenharmony_ci } 59981cb0ef41Sopenharmony_ci 59991cb0ef41Sopenharmony_ci if (rv == 1) { 60001cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_NBYTE; 60011cb0ef41Sopenharmony_ci break; 60021cb0ef41Sopenharmony_ci } 60031cb0ef41Sopenharmony_ci 60041cb0ef41Sopenharmony_ci pri_fieldlen = nghttp2_frame_priority_len(iframe->frame.hd.flags); 60051cb0ef41Sopenharmony_ci 60061cb0ef41Sopenharmony_ci if (pri_fieldlen > 0) { 60071cb0ef41Sopenharmony_ci if (iframe->payloadleft < pri_fieldlen) { 60081cb0ef41Sopenharmony_ci busy = 1; 60091cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; 60101cb0ef41Sopenharmony_ci break; 60111cb0ef41Sopenharmony_ci } 60121cb0ef41Sopenharmony_ci 60131cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_NBYTE; 60141cb0ef41Sopenharmony_ci 60151cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, pri_fieldlen); 60161cb0ef41Sopenharmony_ci 60171cb0ef41Sopenharmony_ci break; 60181cb0ef41Sopenharmony_ci } 60191cb0ef41Sopenharmony_ci 60201cb0ef41Sopenharmony_ci /* Call on_begin_frame_callback here because 60211cb0ef41Sopenharmony_ci session_process_headers_frame() may call 60221cb0ef41Sopenharmony_ci on_begin_headers_callback */ 60231cb0ef41Sopenharmony_ci rv = session_call_on_begin_frame(session, &iframe->frame.hd); 60241cb0ef41Sopenharmony_ci 60251cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 60261cb0ef41Sopenharmony_ci return rv; 60271cb0ef41Sopenharmony_ci } 60281cb0ef41Sopenharmony_ci 60291cb0ef41Sopenharmony_ci on_begin_frame_called = 1; 60301cb0ef41Sopenharmony_ci 60311cb0ef41Sopenharmony_ci rv = session_process_headers_frame(session); 60321cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 60331cb0ef41Sopenharmony_ci return rv; 60341cb0ef41Sopenharmony_ci } 60351cb0ef41Sopenharmony_ci 60361cb0ef41Sopenharmony_ci busy = 1; 60371cb0ef41Sopenharmony_ci 60381cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 60391cb0ef41Sopenharmony_ci return (ssize_t)inlen; 60401cb0ef41Sopenharmony_ci } 60411cb0ef41Sopenharmony_ci 60421cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { 60431cb0ef41Sopenharmony_ci rv = nghttp2_session_add_rst_stream( 60441cb0ef41Sopenharmony_ci session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR); 60451cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 60461cb0ef41Sopenharmony_ci return rv; 60471cb0ef41Sopenharmony_ci } 60481cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; 60491cb0ef41Sopenharmony_ci break; 60501cb0ef41Sopenharmony_ci } 60511cb0ef41Sopenharmony_ci 60521cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { 60531cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; 60541cb0ef41Sopenharmony_ci break; 60551cb0ef41Sopenharmony_ci } 60561cb0ef41Sopenharmony_ci 60571cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; 60581cb0ef41Sopenharmony_ci 60591cb0ef41Sopenharmony_ci break; 60601cb0ef41Sopenharmony_ci case NGHTTP2_PRIORITY: 60611cb0ef41Sopenharmony_ci DEBUGF("recv: PRIORITY\n"); 60621cb0ef41Sopenharmony_ci 60631cb0ef41Sopenharmony_ci iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; 60641cb0ef41Sopenharmony_ci 60651cb0ef41Sopenharmony_ci if (iframe->payloadleft != NGHTTP2_PRIORITY_SPECLEN) { 60661cb0ef41Sopenharmony_ci busy = 1; 60671cb0ef41Sopenharmony_ci 60681cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; 60691cb0ef41Sopenharmony_ci 60701cb0ef41Sopenharmony_ci break; 60711cb0ef41Sopenharmony_ci } 60721cb0ef41Sopenharmony_ci 60731cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_NBYTE; 60741cb0ef41Sopenharmony_ci 60751cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, NGHTTP2_PRIORITY_SPECLEN); 60761cb0ef41Sopenharmony_ci 60771cb0ef41Sopenharmony_ci break; 60781cb0ef41Sopenharmony_ci case NGHTTP2_RST_STREAM: 60791cb0ef41Sopenharmony_ci case NGHTTP2_WINDOW_UPDATE: 60801cb0ef41Sopenharmony_ci#ifdef DEBUGBUILD 60811cb0ef41Sopenharmony_ci switch (iframe->frame.hd.type) { 60821cb0ef41Sopenharmony_ci case NGHTTP2_RST_STREAM: 60831cb0ef41Sopenharmony_ci DEBUGF("recv: RST_STREAM\n"); 60841cb0ef41Sopenharmony_ci break; 60851cb0ef41Sopenharmony_ci case NGHTTP2_WINDOW_UPDATE: 60861cb0ef41Sopenharmony_ci DEBUGF("recv: WINDOW_UPDATE\n"); 60871cb0ef41Sopenharmony_ci break; 60881cb0ef41Sopenharmony_ci } 60891cb0ef41Sopenharmony_ci#endif /* DEBUGBUILD */ 60901cb0ef41Sopenharmony_ci 60911cb0ef41Sopenharmony_ci iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; 60921cb0ef41Sopenharmony_ci 60931cb0ef41Sopenharmony_ci if (iframe->payloadleft != 4) { 60941cb0ef41Sopenharmony_ci busy = 1; 60951cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; 60961cb0ef41Sopenharmony_ci break; 60971cb0ef41Sopenharmony_ci } 60981cb0ef41Sopenharmony_ci 60991cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_NBYTE; 61001cb0ef41Sopenharmony_ci 61011cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, 4); 61021cb0ef41Sopenharmony_ci 61031cb0ef41Sopenharmony_ci break; 61041cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS: 61051cb0ef41Sopenharmony_ci DEBUGF("recv: SETTINGS\n"); 61061cb0ef41Sopenharmony_ci 61071cb0ef41Sopenharmony_ci iframe->frame.hd.flags &= NGHTTP2_FLAG_ACK; 61081cb0ef41Sopenharmony_ci 61091cb0ef41Sopenharmony_ci if ((iframe->frame.hd.length % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) || 61101cb0ef41Sopenharmony_ci ((iframe->frame.hd.flags & NGHTTP2_FLAG_ACK) && 61111cb0ef41Sopenharmony_ci iframe->payloadleft > 0)) { 61121cb0ef41Sopenharmony_ci busy = 1; 61131cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; 61141cb0ef41Sopenharmony_ci break; 61151cb0ef41Sopenharmony_ci } 61161cb0ef41Sopenharmony_ci 61171cb0ef41Sopenharmony_ci /* Check the settings flood counter early to be safe */ 61181cb0ef41Sopenharmony_ci if (session->obq_flood_counter_ >= session->max_outbound_ack && 61191cb0ef41Sopenharmony_ci !(iframe->frame.hd.flags & NGHTTP2_FLAG_ACK)) { 61201cb0ef41Sopenharmony_ci return NGHTTP2_ERR_FLOODED; 61211cb0ef41Sopenharmony_ci } 61221cb0ef41Sopenharmony_ci 61231cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_SETTINGS; 61241cb0ef41Sopenharmony_ci 61251cb0ef41Sopenharmony_ci if (iframe->payloadleft) { 61261cb0ef41Sopenharmony_ci nghttp2_settings_entry *min_header_table_size_entry; 61271cb0ef41Sopenharmony_ci 61281cb0ef41Sopenharmony_ci /* We allocate iv with additional one entry, to store the 61291cb0ef41Sopenharmony_ci minimum header table size. */ 61301cb0ef41Sopenharmony_ci iframe->max_niv = 61311cb0ef41Sopenharmony_ci iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1; 61321cb0ef41Sopenharmony_ci 61331cb0ef41Sopenharmony_ci if (iframe->max_niv - 1 > session->max_settings) { 61341cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session_with_reason( 61351cb0ef41Sopenharmony_ci session, NGHTTP2_ENHANCE_YOUR_CALM, 61361cb0ef41Sopenharmony_ci "SETTINGS: too many setting entries"); 61371cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 61381cb0ef41Sopenharmony_ci return rv; 61391cb0ef41Sopenharmony_ci } 61401cb0ef41Sopenharmony_ci return (ssize_t)inlen; 61411cb0ef41Sopenharmony_ci } 61421cb0ef41Sopenharmony_ci 61431cb0ef41Sopenharmony_ci iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) * 61441cb0ef41Sopenharmony_ci iframe->max_niv); 61451cb0ef41Sopenharmony_ci 61461cb0ef41Sopenharmony_ci if (!iframe->iv) { 61471cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 61481cb0ef41Sopenharmony_ci } 61491cb0ef41Sopenharmony_ci 61501cb0ef41Sopenharmony_ci min_header_table_size_entry = &iframe->iv[iframe->max_niv - 1]; 61511cb0ef41Sopenharmony_ci min_header_table_size_entry->settings_id = 61521cb0ef41Sopenharmony_ci NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; 61531cb0ef41Sopenharmony_ci min_header_table_size_entry->value = UINT32_MAX; 61541cb0ef41Sopenharmony_ci 61551cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH); 61561cb0ef41Sopenharmony_ci break; 61571cb0ef41Sopenharmony_ci } 61581cb0ef41Sopenharmony_ci 61591cb0ef41Sopenharmony_ci busy = 1; 61601cb0ef41Sopenharmony_ci 61611cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, 0); 61621cb0ef41Sopenharmony_ci 61631cb0ef41Sopenharmony_ci break; 61641cb0ef41Sopenharmony_ci case NGHTTP2_PUSH_PROMISE: 61651cb0ef41Sopenharmony_ci DEBUGF("recv: PUSH_PROMISE\n"); 61661cb0ef41Sopenharmony_ci 61671cb0ef41Sopenharmony_ci iframe->frame.hd.flags &= 61681cb0ef41Sopenharmony_ci (NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PADDED); 61691cb0ef41Sopenharmony_ci 61701cb0ef41Sopenharmony_ci rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); 61711cb0ef41Sopenharmony_ci if (rv < 0) { 61721cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session_with_reason( 61731cb0ef41Sopenharmony_ci session, NGHTTP2_PROTOCOL_ERROR, 61741cb0ef41Sopenharmony_ci "PUSH_PROMISE: insufficient padding space"); 61751cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 61761cb0ef41Sopenharmony_ci return rv; 61771cb0ef41Sopenharmony_ci } 61781cb0ef41Sopenharmony_ci return (ssize_t)inlen; 61791cb0ef41Sopenharmony_ci } 61801cb0ef41Sopenharmony_ci 61811cb0ef41Sopenharmony_ci if (rv == 1) { 61821cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_NBYTE; 61831cb0ef41Sopenharmony_ci break; 61841cb0ef41Sopenharmony_ci } 61851cb0ef41Sopenharmony_ci 61861cb0ef41Sopenharmony_ci if (iframe->payloadleft < 4) { 61871cb0ef41Sopenharmony_ci busy = 1; 61881cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; 61891cb0ef41Sopenharmony_ci break; 61901cb0ef41Sopenharmony_ci } 61911cb0ef41Sopenharmony_ci 61921cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_NBYTE; 61931cb0ef41Sopenharmony_ci 61941cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, 4); 61951cb0ef41Sopenharmony_ci 61961cb0ef41Sopenharmony_ci break; 61971cb0ef41Sopenharmony_ci case NGHTTP2_PING: 61981cb0ef41Sopenharmony_ci DEBUGF("recv: PING\n"); 61991cb0ef41Sopenharmony_ci 62001cb0ef41Sopenharmony_ci iframe->frame.hd.flags &= NGHTTP2_FLAG_ACK; 62011cb0ef41Sopenharmony_ci 62021cb0ef41Sopenharmony_ci if (iframe->payloadleft != 8) { 62031cb0ef41Sopenharmony_ci busy = 1; 62041cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; 62051cb0ef41Sopenharmony_ci break; 62061cb0ef41Sopenharmony_ci } 62071cb0ef41Sopenharmony_ci 62081cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_NBYTE; 62091cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, 8); 62101cb0ef41Sopenharmony_ci 62111cb0ef41Sopenharmony_ci break; 62121cb0ef41Sopenharmony_ci case NGHTTP2_GOAWAY: 62131cb0ef41Sopenharmony_ci DEBUGF("recv: GOAWAY\n"); 62141cb0ef41Sopenharmony_ci 62151cb0ef41Sopenharmony_ci iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; 62161cb0ef41Sopenharmony_ci 62171cb0ef41Sopenharmony_ci if (iframe->payloadleft < 8) { 62181cb0ef41Sopenharmony_ci busy = 1; 62191cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; 62201cb0ef41Sopenharmony_ci break; 62211cb0ef41Sopenharmony_ci } 62221cb0ef41Sopenharmony_ci 62231cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_NBYTE; 62241cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, 8); 62251cb0ef41Sopenharmony_ci 62261cb0ef41Sopenharmony_ci break; 62271cb0ef41Sopenharmony_ci case NGHTTP2_CONTINUATION: 62281cb0ef41Sopenharmony_ci DEBUGF("recv: unexpected CONTINUATION\n"); 62291cb0ef41Sopenharmony_ci 62301cb0ef41Sopenharmony_ci /* Receiving CONTINUATION in this state are subject to 62311cb0ef41Sopenharmony_ci connection error of type PROTOCOL_ERROR */ 62321cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session_with_reason( 62331cb0ef41Sopenharmony_ci session, NGHTTP2_PROTOCOL_ERROR, "CONTINUATION: unexpected"); 62341cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 62351cb0ef41Sopenharmony_ci return rv; 62361cb0ef41Sopenharmony_ci } 62371cb0ef41Sopenharmony_ci 62381cb0ef41Sopenharmony_ci return (ssize_t)inlen; 62391cb0ef41Sopenharmony_ci default: 62401cb0ef41Sopenharmony_ci DEBUGF("recv: extension frame\n"); 62411cb0ef41Sopenharmony_ci 62421cb0ef41Sopenharmony_ci if (check_ext_type_set(session->user_recv_ext_types, 62431cb0ef41Sopenharmony_ci iframe->frame.hd.type)) { 62441cb0ef41Sopenharmony_ci if (!session->callbacks.unpack_extension_callback) { 62451cb0ef41Sopenharmony_ci /* Silently ignore unknown frame type. */ 62461cb0ef41Sopenharmony_ci 62471cb0ef41Sopenharmony_ci busy = 1; 62481cb0ef41Sopenharmony_ci 62491cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_PAYLOAD; 62501cb0ef41Sopenharmony_ci 62511cb0ef41Sopenharmony_ci break; 62521cb0ef41Sopenharmony_ci } 62531cb0ef41Sopenharmony_ci 62541cb0ef41Sopenharmony_ci busy = 1; 62551cb0ef41Sopenharmony_ci 62561cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_EXTENSION_PAYLOAD; 62571cb0ef41Sopenharmony_ci 62581cb0ef41Sopenharmony_ci break; 62591cb0ef41Sopenharmony_ci } else { 62601cb0ef41Sopenharmony_ci switch (iframe->frame.hd.type) { 62611cb0ef41Sopenharmony_ci case NGHTTP2_ALTSVC: 62621cb0ef41Sopenharmony_ci if ((session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ALTSVC) == 62631cb0ef41Sopenharmony_ci 0) { 62641cb0ef41Sopenharmony_ci busy = 1; 62651cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_PAYLOAD; 62661cb0ef41Sopenharmony_ci break; 62671cb0ef41Sopenharmony_ci } 62681cb0ef41Sopenharmony_ci 62691cb0ef41Sopenharmony_ci DEBUGF("recv: ALTSVC\n"); 62701cb0ef41Sopenharmony_ci 62711cb0ef41Sopenharmony_ci iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; 62721cb0ef41Sopenharmony_ci iframe->frame.ext.payload = &iframe->ext_frame_payload.altsvc; 62731cb0ef41Sopenharmony_ci 62741cb0ef41Sopenharmony_ci if (session->server) { 62751cb0ef41Sopenharmony_ci busy = 1; 62761cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_PAYLOAD; 62771cb0ef41Sopenharmony_ci break; 62781cb0ef41Sopenharmony_ci } 62791cb0ef41Sopenharmony_ci 62801cb0ef41Sopenharmony_ci if (iframe->payloadleft < 2) { 62811cb0ef41Sopenharmony_ci busy = 1; 62821cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; 62831cb0ef41Sopenharmony_ci break; 62841cb0ef41Sopenharmony_ci } 62851cb0ef41Sopenharmony_ci 62861cb0ef41Sopenharmony_ci busy = 1; 62871cb0ef41Sopenharmony_ci 62881cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_NBYTE; 62891cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, 2); 62901cb0ef41Sopenharmony_ci 62911cb0ef41Sopenharmony_ci break; 62921cb0ef41Sopenharmony_ci case NGHTTP2_ORIGIN: 62931cb0ef41Sopenharmony_ci if (!(session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ORIGIN)) { 62941cb0ef41Sopenharmony_ci busy = 1; 62951cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_PAYLOAD; 62961cb0ef41Sopenharmony_ci break; 62971cb0ef41Sopenharmony_ci } 62981cb0ef41Sopenharmony_ci 62991cb0ef41Sopenharmony_ci DEBUGF("recv: ORIGIN\n"); 63001cb0ef41Sopenharmony_ci 63011cb0ef41Sopenharmony_ci iframe->frame.ext.payload = &iframe->ext_frame_payload.origin; 63021cb0ef41Sopenharmony_ci 63031cb0ef41Sopenharmony_ci if (session->server || iframe->frame.hd.stream_id || 63041cb0ef41Sopenharmony_ci (iframe->frame.hd.flags & 0xf0)) { 63051cb0ef41Sopenharmony_ci busy = 1; 63061cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_PAYLOAD; 63071cb0ef41Sopenharmony_ci break; 63081cb0ef41Sopenharmony_ci } 63091cb0ef41Sopenharmony_ci 63101cb0ef41Sopenharmony_ci iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; 63111cb0ef41Sopenharmony_ci 63121cb0ef41Sopenharmony_ci if (iframe->payloadleft) { 63131cb0ef41Sopenharmony_ci iframe->raw_lbuf = nghttp2_mem_malloc(mem, iframe->payloadleft); 63141cb0ef41Sopenharmony_ci 63151cb0ef41Sopenharmony_ci if (iframe->raw_lbuf == NULL) { 63161cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 63171cb0ef41Sopenharmony_ci } 63181cb0ef41Sopenharmony_ci 63191cb0ef41Sopenharmony_ci nghttp2_buf_wrap_init(&iframe->lbuf, iframe->raw_lbuf, 63201cb0ef41Sopenharmony_ci iframe->payloadleft); 63211cb0ef41Sopenharmony_ci } else { 63221cb0ef41Sopenharmony_ci busy = 1; 63231cb0ef41Sopenharmony_ci } 63241cb0ef41Sopenharmony_ci 63251cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_ORIGIN_PAYLOAD; 63261cb0ef41Sopenharmony_ci 63271cb0ef41Sopenharmony_ci break; 63281cb0ef41Sopenharmony_ci case NGHTTP2_PRIORITY_UPDATE: 63291cb0ef41Sopenharmony_ci if ((session->builtin_recv_ext_types & 63301cb0ef41Sopenharmony_ci NGHTTP2_TYPEMASK_PRIORITY_UPDATE) == 0) { 63311cb0ef41Sopenharmony_ci busy = 1; 63321cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_PAYLOAD; 63331cb0ef41Sopenharmony_ci break; 63341cb0ef41Sopenharmony_ci } 63351cb0ef41Sopenharmony_ci 63361cb0ef41Sopenharmony_ci DEBUGF("recv: PRIORITY_UPDATE\n"); 63371cb0ef41Sopenharmony_ci 63381cb0ef41Sopenharmony_ci iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; 63391cb0ef41Sopenharmony_ci iframe->frame.ext.payload = 63401cb0ef41Sopenharmony_ci &iframe->ext_frame_payload.priority_update; 63411cb0ef41Sopenharmony_ci 63421cb0ef41Sopenharmony_ci if (!session->server) { 63431cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session_with_reason( 63441cb0ef41Sopenharmony_ci session, NGHTTP2_PROTOCOL_ERROR, 63451cb0ef41Sopenharmony_ci "PRIORITY_UPDATE is received from server"); 63461cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 63471cb0ef41Sopenharmony_ci return rv; 63481cb0ef41Sopenharmony_ci } 63491cb0ef41Sopenharmony_ci return (ssize_t)inlen; 63501cb0ef41Sopenharmony_ci } 63511cb0ef41Sopenharmony_ci 63521cb0ef41Sopenharmony_ci if (iframe->payloadleft < 4) { 63531cb0ef41Sopenharmony_ci busy = 1; 63541cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; 63551cb0ef41Sopenharmony_ci break; 63561cb0ef41Sopenharmony_ci } 63571cb0ef41Sopenharmony_ci 63581cb0ef41Sopenharmony_ci if (!session_no_rfc7540_pri_no_fallback(session) || 63591cb0ef41Sopenharmony_ci iframe->payloadleft > sizeof(iframe->raw_sbuf)) { 63601cb0ef41Sopenharmony_ci busy = 1; 63611cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_PAYLOAD; 63621cb0ef41Sopenharmony_ci break; 63631cb0ef41Sopenharmony_ci } 63641cb0ef41Sopenharmony_ci 63651cb0ef41Sopenharmony_ci busy = 1; 63661cb0ef41Sopenharmony_ci 63671cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_NBYTE; 63681cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, iframe->payloadleft); 63691cb0ef41Sopenharmony_ci 63701cb0ef41Sopenharmony_ci break; 63711cb0ef41Sopenharmony_ci default: 63721cb0ef41Sopenharmony_ci busy = 1; 63731cb0ef41Sopenharmony_ci 63741cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_PAYLOAD; 63751cb0ef41Sopenharmony_ci 63761cb0ef41Sopenharmony_ci break; 63771cb0ef41Sopenharmony_ci } 63781cb0ef41Sopenharmony_ci } 63791cb0ef41Sopenharmony_ci } 63801cb0ef41Sopenharmony_ci 63811cb0ef41Sopenharmony_ci if (!on_begin_frame_called) { 63821cb0ef41Sopenharmony_ci switch (iframe->state) { 63831cb0ef41Sopenharmony_ci case NGHTTP2_IB_IGN_HEADER_BLOCK: 63841cb0ef41Sopenharmony_ci case NGHTTP2_IB_IGN_PAYLOAD: 63851cb0ef41Sopenharmony_ci case NGHTTP2_IB_FRAME_SIZE_ERROR: 63861cb0ef41Sopenharmony_ci case NGHTTP2_IB_IGN_DATA: 63871cb0ef41Sopenharmony_ci case NGHTTP2_IB_IGN_ALL: 63881cb0ef41Sopenharmony_ci break; 63891cb0ef41Sopenharmony_ci default: 63901cb0ef41Sopenharmony_ci rv = session_call_on_begin_frame(session, &iframe->frame.hd); 63911cb0ef41Sopenharmony_ci 63921cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 63931cb0ef41Sopenharmony_ci return rv; 63941cb0ef41Sopenharmony_ci } 63951cb0ef41Sopenharmony_ci } 63961cb0ef41Sopenharmony_ci } 63971cb0ef41Sopenharmony_ci 63981cb0ef41Sopenharmony_ci break; 63991cb0ef41Sopenharmony_ci } 64001cb0ef41Sopenharmony_ci case NGHTTP2_IB_READ_NBYTE: 64011cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_READ_NBYTE]\n"); 64021cb0ef41Sopenharmony_ci 64031cb0ef41Sopenharmony_ci readlen = inbound_frame_buf_read(iframe, in, last); 64041cb0ef41Sopenharmony_ci in += readlen; 64051cb0ef41Sopenharmony_ci iframe->payloadleft -= readlen; 64061cb0ef41Sopenharmony_ci 64071cb0ef41Sopenharmony_ci DEBUGF("recv: readlen=%zu, payloadleft=%zu, left=%zd\n", readlen, 64081cb0ef41Sopenharmony_ci iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf)); 64091cb0ef41Sopenharmony_ci 64101cb0ef41Sopenharmony_ci if (nghttp2_buf_mark_avail(&iframe->sbuf)) { 64111cb0ef41Sopenharmony_ci return (ssize_t)(in - first); 64121cb0ef41Sopenharmony_ci } 64131cb0ef41Sopenharmony_ci 64141cb0ef41Sopenharmony_ci switch (iframe->frame.hd.type) { 64151cb0ef41Sopenharmony_ci case NGHTTP2_HEADERS: 64161cb0ef41Sopenharmony_ci if (iframe->padlen == 0 && 64171cb0ef41Sopenharmony_ci (iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) { 64181cb0ef41Sopenharmony_ci pri_fieldlen = nghttp2_frame_priority_len(iframe->frame.hd.flags); 64191cb0ef41Sopenharmony_ci padlen = inbound_frame_compute_pad(iframe); 64201cb0ef41Sopenharmony_ci if (padlen < 0 || 64211cb0ef41Sopenharmony_ci (size_t)padlen + pri_fieldlen > 1 + iframe->payloadleft) { 64221cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session_with_reason( 64231cb0ef41Sopenharmony_ci session, NGHTTP2_PROTOCOL_ERROR, "HEADERS: invalid padding"); 64241cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 64251cb0ef41Sopenharmony_ci return rv; 64261cb0ef41Sopenharmony_ci } 64271cb0ef41Sopenharmony_ci return (ssize_t)inlen; 64281cb0ef41Sopenharmony_ci } 64291cb0ef41Sopenharmony_ci iframe->frame.headers.padlen = (size_t)padlen; 64301cb0ef41Sopenharmony_ci 64311cb0ef41Sopenharmony_ci if (pri_fieldlen > 0) { 64321cb0ef41Sopenharmony_ci if (iframe->payloadleft < pri_fieldlen) { 64331cb0ef41Sopenharmony_ci busy = 1; 64341cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; 64351cb0ef41Sopenharmony_ci break; 64361cb0ef41Sopenharmony_ci } 64371cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_NBYTE; 64381cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, pri_fieldlen); 64391cb0ef41Sopenharmony_ci break; 64401cb0ef41Sopenharmony_ci } else { 64411cb0ef41Sopenharmony_ci /* Truncate buffers used for padding spec */ 64421cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, 0); 64431cb0ef41Sopenharmony_ci } 64441cb0ef41Sopenharmony_ci } 64451cb0ef41Sopenharmony_ci 64461cb0ef41Sopenharmony_ci rv = session_process_headers_frame(session); 64471cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 64481cb0ef41Sopenharmony_ci return rv; 64491cb0ef41Sopenharmony_ci } 64501cb0ef41Sopenharmony_ci 64511cb0ef41Sopenharmony_ci busy = 1; 64521cb0ef41Sopenharmony_ci 64531cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 64541cb0ef41Sopenharmony_ci return (ssize_t)inlen; 64551cb0ef41Sopenharmony_ci } 64561cb0ef41Sopenharmony_ci 64571cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { 64581cb0ef41Sopenharmony_ci rv = nghttp2_session_add_rst_stream( 64591cb0ef41Sopenharmony_ci session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR); 64601cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 64611cb0ef41Sopenharmony_ci return rv; 64621cb0ef41Sopenharmony_ci } 64631cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; 64641cb0ef41Sopenharmony_ci break; 64651cb0ef41Sopenharmony_ci } 64661cb0ef41Sopenharmony_ci 64671cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { 64681cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; 64691cb0ef41Sopenharmony_ci break; 64701cb0ef41Sopenharmony_ci } 64711cb0ef41Sopenharmony_ci 64721cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; 64731cb0ef41Sopenharmony_ci 64741cb0ef41Sopenharmony_ci break; 64751cb0ef41Sopenharmony_ci case NGHTTP2_PRIORITY: 64761cb0ef41Sopenharmony_ci if (!session_no_rfc7540_pri_no_fallback(session) && 64771cb0ef41Sopenharmony_ci session->remote_settings.no_rfc7540_priorities != 1) { 64781cb0ef41Sopenharmony_ci rv = session_process_priority_frame(session); 64791cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 64801cb0ef41Sopenharmony_ci return rv; 64811cb0ef41Sopenharmony_ci } 64821cb0ef41Sopenharmony_ci 64831cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 64841cb0ef41Sopenharmony_ci return (ssize_t)inlen; 64851cb0ef41Sopenharmony_ci } 64861cb0ef41Sopenharmony_ci } 64871cb0ef41Sopenharmony_ci 64881cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 64891cb0ef41Sopenharmony_ci 64901cb0ef41Sopenharmony_ci break; 64911cb0ef41Sopenharmony_ci case NGHTTP2_RST_STREAM: 64921cb0ef41Sopenharmony_ci rv = session_process_rst_stream_frame(session); 64931cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 64941cb0ef41Sopenharmony_ci return rv; 64951cb0ef41Sopenharmony_ci } 64961cb0ef41Sopenharmony_ci 64971cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 64981cb0ef41Sopenharmony_ci return (ssize_t)inlen; 64991cb0ef41Sopenharmony_ci } 65001cb0ef41Sopenharmony_ci 65011cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 65021cb0ef41Sopenharmony_ci 65031cb0ef41Sopenharmony_ci break; 65041cb0ef41Sopenharmony_ci case NGHTTP2_PUSH_PROMISE: 65051cb0ef41Sopenharmony_ci if (iframe->padlen == 0 && 65061cb0ef41Sopenharmony_ci (iframe->frame.hd.flags & NGHTTP2_FLAG_PADDED)) { 65071cb0ef41Sopenharmony_ci padlen = inbound_frame_compute_pad(iframe); 65081cb0ef41Sopenharmony_ci if (padlen < 0 || (size_t)padlen + 4 /* promised stream id */ 65091cb0ef41Sopenharmony_ci > 1 + iframe->payloadleft) { 65101cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session_with_reason( 65111cb0ef41Sopenharmony_ci session, NGHTTP2_PROTOCOL_ERROR, 65121cb0ef41Sopenharmony_ci "PUSH_PROMISE: invalid padding"); 65131cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 65141cb0ef41Sopenharmony_ci return rv; 65151cb0ef41Sopenharmony_ci } 65161cb0ef41Sopenharmony_ci return (ssize_t)inlen; 65171cb0ef41Sopenharmony_ci } 65181cb0ef41Sopenharmony_ci 65191cb0ef41Sopenharmony_ci iframe->frame.push_promise.padlen = (size_t)padlen; 65201cb0ef41Sopenharmony_ci 65211cb0ef41Sopenharmony_ci if (iframe->payloadleft < 4) { 65221cb0ef41Sopenharmony_ci busy = 1; 65231cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; 65241cb0ef41Sopenharmony_ci break; 65251cb0ef41Sopenharmony_ci } 65261cb0ef41Sopenharmony_ci 65271cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_NBYTE; 65281cb0ef41Sopenharmony_ci 65291cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, 4); 65301cb0ef41Sopenharmony_ci 65311cb0ef41Sopenharmony_ci break; 65321cb0ef41Sopenharmony_ci } 65331cb0ef41Sopenharmony_ci 65341cb0ef41Sopenharmony_ci rv = session_process_push_promise_frame(session); 65351cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 65361cb0ef41Sopenharmony_ci return rv; 65371cb0ef41Sopenharmony_ci } 65381cb0ef41Sopenharmony_ci 65391cb0ef41Sopenharmony_ci busy = 1; 65401cb0ef41Sopenharmony_ci 65411cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 65421cb0ef41Sopenharmony_ci return (ssize_t)inlen; 65431cb0ef41Sopenharmony_ci } 65441cb0ef41Sopenharmony_ci 65451cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { 65461cb0ef41Sopenharmony_ci rv = nghttp2_session_add_rst_stream( 65471cb0ef41Sopenharmony_ci session, iframe->frame.push_promise.promised_stream_id, 65481cb0ef41Sopenharmony_ci NGHTTP2_INTERNAL_ERROR); 65491cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 65501cb0ef41Sopenharmony_ci return rv; 65511cb0ef41Sopenharmony_ci } 65521cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; 65531cb0ef41Sopenharmony_ci break; 65541cb0ef41Sopenharmony_ci } 65551cb0ef41Sopenharmony_ci 65561cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { 65571cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; 65581cb0ef41Sopenharmony_ci break; 65591cb0ef41Sopenharmony_ci } 65601cb0ef41Sopenharmony_ci 65611cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; 65621cb0ef41Sopenharmony_ci 65631cb0ef41Sopenharmony_ci break; 65641cb0ef41Sopenharmony_ci case NGHTTP2_PING: 65651cb0ef41Sopenharmony_ci rv = session_process_ping_frame(session); 65661cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 65671cb0ef41Sopenharmony_ci return rv; 65681cb0ef41Sopenharmony_ci } 65691cb0ef41Sopenharmony_ci 65701cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 65711cb0ef41Sopenharmony_ci return (ssize_t)inlen; 65721cb0ef41Sopenharmony_ci } 65731cb0ef41Sopenharmony_ci 65741cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 65751cb0ef41Sopenharmony_ci 65761cb0ef41Sopenharmony_ci break; 65771cb0ef41Sopenharmony_ci case NGHTTP2_GOAWAY: { 65781cb0ef41Sopenharmony_ci size_t debuglen; 65791cb0ef41Sopenharmony_ci 65801cb0ef41Sopenharmony_ci /* 8 is Last-stream-ID + Error Code */ 65811cb0ef41Sopenharmony_ci debuglen = iframe->frame.hd.length - 8; 65821cb0ef41Sopenharmony_ci 65831cb0ef41Sopenharmony_ci if (debuglen > 0) { 65841cb0ef41Sopenharmony_ci iframe->raw_lbuf = nghttp2_mem_malloc(mem, debuglen); 65851cb0ef41Sopenharmony_ci 65861cb0ef41Sopenharmony_ci if (iframe->raw_lbuf == NULL) { 65871cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 65881cb0ef41Sopenharmony_ci } 65891cb0ef41Sopenharmony_ci 65901cb0ef41Sopenharmony_ci nghttp2_buf_wrap_init(&iframe->lbuf, iframe->raw_lbuf, debuglen); 65911cb0ef41Sopenharmony_ci } 65921cb0ef41Sopenharmony_ci 65931cb0ef41Sopenharmony_ci busy = 1; 65941cb0ef41Sopenharmony_ci 65951cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_GOAWAY_DEBUG; 65961cb0ef41Sopenharmony_ci 65971cb0ef41Sopenharmony_ci break; 65981cb0ef41Sopenharmony_ci } 65991cb0ef41Sopenharmony_ci case NGHTTP2_WINDOW_UPDATE: 66001cb0ef41Sopenharmony_ci rv = session_process_window_update_frame(session); 66011cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 66021cb0ef41Sopenharmony_ci return rv; 66031cb0ef41Sopenharmony_ci } 66041cb0ef41Sopenharmony_ci 66051cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 66061cb0ef41Sopenharmony_ci return (ssize_t)inlen; 66071cb0ef41Sopenharmony_ci } 66081cb0ef41Sopenharmony_ci 66091cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 66101cb0ef41Sopenharmony_ci 66111cb0ef41Sopenharmony_ci break; 66121cb0ef41Sopenharmony_ci case NGHTTP2_ALTSVC: { 66131cb0ef41Sopenharmony_ci size_t origin_len; 66141cb0ef41Sopenharmony_ci 66151cb0ef41Sopenharmony_ci origin_len = nghttp2_get_uint16(iframe->sbuf.pos); 66161cb0ef41Sopenharmony_ci 66171cb0ef41Sopenharmony_ci DEBUGF("recv: origin_len=%zu\n", origin_len); 66181cb0ef41Sopenharmony_ci 66191cb0ef41Sopenharmony_ci if (origin_len > iframe->payloadleft) { 66201cb0ef41Sopenharmony_ci busy = 1; 66211cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; 66221cb0ef41Sopenharmony_ci break; 66231cb0ef41Sopenharmony_ci } 66241cb0ef41Sopenharmony_ci 66251cb0ef41Sopenharmony_ci if (iframe->frame.hd.length > 2) { 66261cb0ef41Sopenharmony_ci iframe->raw_lbuf = 66271cb0ef41Sopenharmony_ci nghttp2_mem_malloc(mem, iframe->frame.hd.length - 2); 66281cb0ef41Sopenharmony_ci 66291cb0ef41Sopenharmony_ci if (iframe->raw_lbuf == NULL) { 66301cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 66311cb0ef41Sopenharmony_ci } 66321cb0ef41Sopenharmony_ci 66331cb0ef41Sopenharmony_ci nghttp2_buf_wrap_init(&iframe->lbuf, iframe->raw_lbuf, 66341cb0ef41Sopenharmony_ci iframe->frame.hd.length); 66351cb0ef41Sopenharmony_ci } 66361cb0ef41Sopenharmony_ci 66371cb0ef41Sopenharmony_ci busy = 1; 66381cb0ef41Sopenharmony_ci 66391cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_ALTSVC_PAYLOAD; 66401cb0ef41Sopenharmony_ci 66411cb0ef41Sopenharmony_ci break; 66421cb0ef41Sopenharmony_ci case NGHTTP2_PRIORITY_UPDATE: 66431cb0ef41Sopenharmony_ci DEBUGF("recv: prioritized_stream_id=%d\n", 66441cb0ef41Sopenharmony_ci nghttp2_get_uint32(iframe->sbuf.pos) & NGHTTP2_STREAM_ID_MASK); 66451cb0ef41Sopenharmony_ci 66461cb0ef41Sopenharmony_ci rv = session_process_priority_update_frame(session); 66471cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 66481cb0ef41Sopenharmony_ci return rv; 66491cb0ef41Sopenharmony_ci } 66501cb0ef41Sopenharmony_ci 66511cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 66521cb0ef41Sopenharmony_ci 66531cb0ef41Sopenharmony_ci break; 66541cb0ef41Sopenharmony_ci } 66551cb0ef41Sopenharmony_ci default: 66561cb0ef41Sopenharmony_ci /* This is unknown frame */ 66571cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 66581cb0ef41Sopenharmony_ci 66591cb0ef41Sopenharmony_ci break; 66601cb0ef41Sopenharmony_ci } 66611cb0ef41Sopenharmony_ci break; 66621cb0ef41Sopenharmony_ci case NGHTTP2_IB_READ_HEADER_BLOCK: 66631cb0ef41Sopenharmony_ci case NGHTTP2_IB_IGN_HEADER_BLOCK: { 66641cb0ef41Sopenharmony_ci ssize_t data_readlen; 66651cb0ef41Sopenharmony_ci size_t trail_padlen; 66661cb0ef41Sopenharmony_ci int final; 66671cb0ef41Sopenharmony_ci#ifdef DEBUGBUILD 66681cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { 66691cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_READ_HEADER_BLOCK]\n"); 66701cb0ef41Sopenharmony_ci } else { 66711cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_IGN_HEADER_BLOCK]\n"); 66721cb0ef41Sopenharmony_ci } 66731cb0ef41Sopenharmony_ci#endif /* DEBUGBUILD */ 66741cb0ef41Sopenharmony_ci 66751cb0ef41Sopenharmony_ci readlen = inbound_frame_payload_readlen(iframe, in, last); 66761cb0ef41Sopenharmony_ci 66771cb0ef41Sopenharmony_ci DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, 66781cb0ef41Sopenharmony_ci iframe->payloadleft - readlen); 66791cb0ef41Sopenharmony_ci 66801cb0ef41Sopenharmony_ci data_readlen = inbound_frame_effective_readlen( 66811cb0ef41Sopenharmony_ci iframe, iframe->payloadleft - readlen, readlen); 66821cb0ef41Sopenharmony_ci 66831cb0ef41Sopenharmony_ci if (data_readlen == -1) { 66841cb0ef41Sopenharmony_ci /* everything is padding */ 66851cb0ef41Sopenharmony_ci data_readlen = 0; 66861cb0ef41Sopenharmony_ci } 66871cb0ef41Sopenharmony_ci 66881cb0ef41Sopenharmony_ci trail_padlen = nghttp2_frame_trail_padlen(&iframe->frame, iframe->padlen); 66891cb0ef41Sopenharmony_ci 66901cb0ef41Sopenharmony_ci final = (iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) && 66911cb0ef41Sopenharmony_ci iframe->payloadleft - (size_t)data_readlen == trail_padlen; 66921cb0ef41Sopenharmony_ci 66931cb0ef41Sopenharmony_ci if (data_readlen > 0 || (data_readlen == 0 && final)) { 66941cb0ef41Sopenharmony_ci size_t hd_proclen = 0; 66951cb0ef41Sopenharmony_ci 66961cb0ef41Sopenharmony_ci DEBUGF("recv: block final=%d\n", final); 66971cb0ef41Sopenharmony_ci 66981cb0ef41Sopenharmony_ci rv = 66991cb0ef41Sopenharmony_ci inflate_header_block(session, &iframe->frame, &hd_proclen, 67001cb0ef41Sopenharmony_ci (uint8_t *)in, (size_t)data_readlen, final, 67011cb0ef41Sopenharmony_ci iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK); 67021cb0ef41Sopenharmony_ci 67031cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 67041cb0ef41Sopenharmony_ci return rv; 67051cb0ef41Sopenharmony_ci } 67061cb0ef41Sopenharmony_ci 67071cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 67081cb0ef41Sopenharmony_ci return (ssize_t)inlen; 67091cb0ef41Sopenharmony_ci } 67101cb0ef41Sopenharmony_ci 67111cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_PAUSE) { 67121cb0ef41Sopenharmony_ci in += hd_proclen; 67131cb0ef41Sopenharmony_ci iframe->payloadleft -= hd_proclen; 67141cb0ef41Sopenharmony_ci 67151cb0ef41Sopenharmony_ci return (ssize_t)(in - first); 67161cb0ef41Sopenharmony_ci } 67171cb0ef41Sopenharmony_ci 67181cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { 67191cb0ef41Sopenharmony_ci /* The application says no more headers. We decompress the 67201cb0ef41Sopenharmony_ci rest of the header block but not invoke on_header_callback 67211cb0ef41Sopenharmony_ci and on_frame_recv_callback. */ 67221cb0ef41Sopenharmony_ci in += hd_proclen; 67231cb0ef41Sopenharmony_ci iframe->payloadleft -= hd_proclen; 67241cb0ef41Sopenharmony_ci 67251cb0ef41Sopenharmony_ci /* Use promised stream ID for PUSH_PROMISE */ 67261cb0ef41Sopenharmony_ci rv = nghttp2_session_add_rst_stream( 67271cb0ef41Sopenharmony_ci session, 67281cb0ef41Sopenharmony_ci iframe->frame.hd.type == NGHTTP2_PUSH_PROMISE 67291cb0ef41Sopenharmony_ci ? iframe->frame.push_promise.promised_stream_id 67301cb0ef41Sopenharmony_ci : iframe->frame.hd.stream_id, 67311cb0ef41Sopenharmony_ci NGHTTP2_INTERNAL_ERROR); 67321cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 67331cb0ef41Sopenharmony_ci return rv; 67341cb0ef41Sopenharmony_ci } 67351cb0ef41Sopenharmony_ci busy = 1; 67361cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; 67371cb0ef41Sopenharmony_ci break; 67381cb0ef41Sopenharmony_ci } 67391cb0ef41Sopenharmony_ci 67401cb0ef41Sopenharmony_ci in += readlen; 67411cb0ef41Sopenharmony_ci iframe->payloadleft -= readlen; 67421cb0ef41Sopenharmony_ci 67431cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_HEADER_COMP) { 67441cb0ef41Sopenharmony_ci /* GOAWAY is already issued */ 67451cb0ef41Sopenharmony_ci if (iframe->payloadleft == 0) { 67461cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 67471cb0ef41Sopenharmony_ci } else { 67481cb0ef41Sopenharmony_ci busy = 1; 67491cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_PAYLOAD; 67501cb0ef41Sopenharmony_ci } 67511cb0ef41Sopenharmony_ci break; 67521cb0ef41Sopenharmony_ci } 67531cb0ef41Sopenharmony_ci } else { 67541cb0ef41Sopenharmony_ci in += readlen; 67551cb0ef41Sopenharmony_ci iframe->payloadleft -= readlen; 67561cb0ef41Sopenharmony_ci } 67571cb0ef41Sopenharmony_ci 67581cb0ef41Sopenharmony_ci if (iframe->payloadleft) { 67591cb0ef41Sopenharmony_ci break; 67601cb0ef41Sopenharmony_ci } 67611cb0ef41Sopenharmony_ci 67621cb0ef41Sopenharmony_ci if ((iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) { 67631cb0ef41Sopenharmony_ci 67641cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, NGHTTP2_FRAME_HDLEN); 67651cb0ef41Sopenharmony_ci 67661cb0ef41Sopenharmony_ci iframe->padlen = 0; 67671cb0ef41Sopenharmony_ci 67681cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { 67691cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_EXPECT_CONTINUATION; 67701cb0ef41Sopenharmony_ci } else { 67711cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_CONTINUATION; 67721cb0ef41Sopenharmony_ci } 67731cb0ef41Sopenharmony_ci } else { 67741cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { 67751cb0ef41Sopenharmony_ci rv = session_after_header_block_received(session); 67761cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 67771cb0ef41Sopenharmony_ci return rv; 67781cb0ef41Sopenharmony_ci } 67791cb0ef41Sopenharmony_ci } 67801cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 67811cb0ef41Sopenharmony_ci } 67821cb0ef41Sopenharmony_ci break; 67831cb0ef41Sopenharmony_ci } 67841cb0ef41Sopenharmony_ci case NGHTTP2_IB_IGN_PAYLOAD: 67851cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_IGN_PAYLOAD]\n"); 67861cb0ef41Sopenharmony_ci 67871cb0ef41Sopenharmony_ci readlen = inbound_frame_payload_readlen(iframe, in, last); 67881cb0ef41Sopenharmony_ci iframe->payloadleft -= readlen; 67891cb0ef41Sopenharmony_ci in += readlen; 67901cb0ef41Sopenharmony_ci 67911cb0ef41Sopenharmony_ci DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, 67921cb0ef41Sopenharmony_ci iframe->payloadleft); 67931cb0ef41Sopenharmony_ci 67941cb0ef41Sopenharmony_ci if (iframe->payloadleft) { 67951cb0ef41Sopenharmony_ci break; 67961cb0ef41Sopenharmony_ci } 67971cb0ef41Sopenharmony_ci 67981cb0ef41Sopenharmony_ci switch (iframe->frame.hd.type) { 67991cb0ef41Sopenharmony_ci case NGHTTP2_HEADERS: 68001cb0ef41Sopenharmony_ci case NGHTTP2_PUSH_PROMISE: 68011cb0ef41Sopenharmony_ci case NGHTTP2_CONTINUATION: 68021cb0ef41Sopenharmony_ci /* Mark inflater bad so that we won't perform further decoding */ 68031cb0ef41Sopenharmony_ci session->hd_inflater.ctx.bad = 1; 68041cb0ef41Sopenharmony_ci break; 68051cb0ef41Sopenharmony_ci default: 68061cb0ef41Sopenharmony_ci break; 68071cb0ef41Sopenharmony_ci } 68081cb0ef41Sopenharmony_ci 68091cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 68101cb0ef41Sopenharmony_ci 68111cb0ef41Sopenharmony_ci break; 68121cb0ef41Sopenharmony_ci case NGHTTP2_IB_FRAME_SIZE_ERROR: 68131cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_FRAME_SIZE_ERROR]\n"); 68141cb0ef41Sopenharmony_ci 68151cb0ef41Sopenharmony_ci rv = session_handle_frame_size_error(session); 68161cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 68171cb0ef41Sopenharmony_ci return rv; 68181cb0ef41Sopenharmony_ci } 68191cb0ef41Sopenharmony_ci 68201cb0ef41Sopenharmony_ci assert(iframe->state == NGHTTP2_IB_IGN_ALL); 68211cb0ef41Sopenharmony_ci 68221cb0ef41Sopenharmony_ci return (ssize_t)inlen; 68231cb0ef41Sopenharmony_ci case NGHTTP2_IB_READ_SETTINGS: 68241cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_READ_SETTINGS]\n"); 68251cb0ef41Sopenharmony_ci 68261cb0ef41Sopenharmony_ci readlen = inbound_frame_buf_read(iframe, in, last); 68271cb0ef41Sopenharmony_ci iframe->payloadleft -= readlen; 68281cb0ef41Sopenharmony_ci in += readlen; 68291cb0ef41Sopenharmony_ci 68301cb0ef41Sopenharmony_ci DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, 68311cb0ef41Sopenharmony_ci iframe->payloadleft); 68321cb0ef41Sopenharmony_ci 68331cb0ef41Sopenharmony_ci if (nghttp2_buf_mark_avail(&iframe->sbuf)) { 68341cb0ef41Sopenharmony_ci break; 68351cb0ef41Sopenharmony_ci } 68361cb0ef41Sopenharmony_ci 68371cb0ef41Sopenharmony_ci if (readlen > 0) { 68381cb0ef41Sopenharmony_ci inbound_frame_set_settings_entry(iframe); 68391cb0ef41Sopenharmony_ci } 68401cb0ef41Sopenharmony_ci if (iframe->payloadleft) { 68411cb0ef41Sopenharmony_ci inbound_frame_set_mark(iframe, NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH); 68421cb0ef41Sopenharmony_ci break; 68431cb0ef41Sopenharmony_ci } 68441cb0ef41Sopenharmony_ci 68451cb0ef41Sopenharmony_ci rv = session_process_settings_frame(session); 68461cb0ef41Sopenharmony_ci 68471cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 68481cb0ef41Sopenharmony_ci return rv; 68491cb0ef41Sopenharmony_ci } 68501cb0ef41Sopenharmony_ci 68511cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 68521cb0ef41Sopenharmony_ci return (ssize_t)inlen; 68531cb0ef41Sopenharmony_ci } 68541cb0ef41Sopenharmony_ci 68551cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 68561cb0ef41Sopenharmony_ci 68571cb0ef41Sopenharmony_ci break; 68581cb0ef41Sopenharmony_ci case NGHTTP2_IB_READ_GOAWAY_DEBUG: 68591cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_READ_GOAWAY_DEBUG]\n"); 68601cb0ef41Sopenharmony_ci 68611cb0ef41Sopenharmony_ci readlen = inbound_frame_payload_readlen(iframe, in, last); 68621cb0ef41Sopenharmony_ci 68631cb0ef41Sopenharmony_ci if (readlen > 0) { 68641cb0ef41Sopenharmony_ci iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen); 68651cb0ef41Sopenharmony_ci 68661cb0ef41Sopenharmony_ci iframe->payloadleft -= readlen; 68671cb0ef41Sopenharmony_ci in += readlen; 68681cb0ef41Sopenharmony_ci } 68691cb0ef41Sopenharmony_ci 68701cb0ef41Sopenharmony_ci DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, 68711cb0ef41Sopenharmony_ci iframe->payloadleft); 68721cb0ef41Sopenharmony_ci 68731cb0ef41Sopenharmony_ci if (iframe->payloadleft) { 68741cb0ef41Sopenharmony_ci assert(nghttp2_buf_avail(&iframe->lbuf) > 0); 68751cb0ef41Sopenharmony_ci 68761cb0ef41Sopenharmony_ci break; 68771cb0ef41Sopenharmony_ci } 68781cb0ef41Sopenharmony_ci 68791cb0ef41Sopenharmony_ci rv = session_process_goaway_frame(session); 68801cb0ef41Sopenharmony_ci 68811cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 68821cb0ef41Sopenharmony_ci return rv; 68831cb0ef41Sopenharmony_ci } 68841cb0ef41Sopenharmony_ci 68851cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 68861cb0ef41Sopenharmony_ci return (ssize_t)inlen; 68871cb0ef41Sopenharmony_ci } 68881cb0ef41Sopenharmony_ci 68891cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 68901cb0ef41Sopenharmony_ci 68911cb0ef41Sopenharmony_ci break; 68921cb0ef41Sopenharmony_ci case NGHTTP2_IB_EXPECT_CONTINUATION: 68931cb0ef41Sopenharmony_ci case NGHTTP2_IB_IGN_CONTINUATION: 68941cb0ef41Sopenharmony_ci#ifdef DEBUGBUILD 68951cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { 68961cb0ef41Sopenharmony_ci fprintf(stderr, "recv: [IB_EXPECT_CONTINUATION]\n"); 68971cb0ef41Sopenharmony_ci } else { 68981cb0ef41Sopenharmony_ci fprintf(stderr, "recv: [IB_IGN_CONTINUATION]\n"); 68991cb0ef41Sopenharmony_ci } 69001cb0ef41Sopenharmony_ci#endif /* DEBUGBUILD */ 69011cb0ef41Sopenharmony_ci 69021cb0ef41Sopenharmony_ci readlen = inbound_frame_buf_read(iframe, in, last); 69031cb0ef41Sopenharmony_ci in += readlen; 69041cb0ef41Sopenharmony_ci 69051cb0ef41Sopenharmony_ci if (nghttp2_buf_mark_avail(&iframe->sbuf)) { 69061cb0ef41Sopenharmony_ci return (ssize_t)(in - first); 69071cb0ef41Sopenharmony_ci } 69081cb0ef41Sopenharmony_ci 69091cb0ef41Sopenharmony_ci nghttp2_frame_unpack_frame_hd(&cont_hd, iframe->sbuf.pos); 69101cb0ef41Sopenharmony_ci iframe->payloadleft = cont_hd.length; 69111cb0ef41Sopenharmony_ci 69121cb0ef41Sopenharmony_ci DEBUGF("recv: payloadlen=%zu, type=%u, flags=0x%02x, stream_id=%d\n", 69131cb0ef41Sopenharmony_ci cont_hd.length, cont_hd.type, cont_hd.flags, cont_hd.stream_id); 69141cb0ef41Sopenharmony_ci 69151cb0ef41Sopenharmony_ci if (cont_hd.type != NGHTTP2_CONTINUATION || 69161cb0ef41Sopenharmony_ci cont_hd.stream_id != iframe->frame.hd.stream_id) { 69171cb0ef41Sopenharmony_ci DEBUGF("recv: expected stream_id=%d, type=%d, but got stream_id=%d, " 69181cb0ef41Sopenharmony_ci "type=%u\n", 69191cb0ef41Sopenharmony_ci iframe->frame.hd.stream_id, NGHTTP2_CONTINUATION, 69201cb0ef41Sopenharmony_ci cont_hd.stream_id, cont_hd.type); 69211cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session_with_reason( 69221cb0ef41Sopenharmony_ci session, NGHTTP2_PROTOCOL_ERROR, 69231cb0ef41Sopenharmony_ci "unexpected non-CONTINUATION frame or stream_id is invalid"); 69241cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 69251cb0ef41Sopenharmony_ci return rv; 69261cb0ef41Sopenharmony_ci } 69271cb0ef41Sopenharmony_ci 69281cb0ef41Sopenharmony_ci return (ssize_t)inlen; 69291cb0ef41Sopenharmony_ci } 69301cb0ef41Sopenharmony_ci 69311cb0ef41Sopenharmony_ci /* CONTINUATION won't bear NGHTTP2_PADDED flag */ 69321cb0ef41Sopenharmony_ci 69331cb0ef41Sopenharmony_ci iframe->frame.hd.flags = 69341cb0ef41Sopenharmony_ci (uint8_t)(iframe->frame.hd.flags | 69351cb0ef41Sopenharmony_ci (cont_hd.flags & NGHTTP2_FLAG_END_HEADERS)); 69361cb0ef41Sopenharmony_ci iframe->frame.hd.length += cont_hd.length; 69371cb0ef41Sopenharmony_ci 69381cb0ef41Sopenharmony_ci busy = 1; 69391cb0ef41Sopenharmony_ci 69401cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { 69411cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; 69421cb0ef41Sopenharmony_ci 69431cb0ef41Sopenharmony_ci rv = session_call_on_begin_frame(session, &cont_hd); 69441cb0ef41Sopenharmony_ci 69451cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 69461cb0ef41Sopenharmony_ci return rv; 69471cb0ef41Sopenharmony_ci } 69481cb0ef41Sopenharmony_ci } else { 69491cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; 69501cb0ef41Sopenharmony_ci } 69511cb0ef41Sopenharmony_ci 69521cb0ef41Sopenharmony_ci break; 69531cb0ef41Sopenharmony_ci case NGHTTP2_IB_READ_PAD_DATA: 69541cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_READ_PAD_DATA]\n"); 69551cb0ef41Sopenharmony_ci 69561cb0ef41Sopenharmony_ci readlen = inbound_frame_buf_read(iframe, in, last); 69571cb0ef41Sopenharmony_ci in += readlen; 69581cb0ef41Sopenharmony_ci iframe->payloadleft -= readlen; 69591cb0ef41Sopenharmony_ci 69601cb0ef41Sopenharmony_ci DEBUGF("recv: readlen=%zu, payloadleft=%zu, left=%zu\n", readlen, 69611cb0ef41Sopenharmony_ci iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf)); 69621cb0ef41Sopenharmony_ci 69631cb0ef41Sopenharmony_ci if (nghttp2_buf_mark_avail(&iframe->sbuf)) { 69641cb0ef41Sopenharmony_ci return (ssize_t)(in - first); 69651cb0ef41Sopenharmony_ci } 69661cb0ef41Sopenharmony_ci 69671cb0ef41Sopenharmony_ci /* Pad Length field is subject to flow control */ 69681cb0ef41Sopenharmony_ci rv = nghttp2_session_update_recv_connection_window_size(session, readlen); 69691cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 69701cb0ef41Sopenharmony_ci return rv; 69711cb0ef41Sopenharmony_ci } 69721cb0ef41Sopenharmony_ci 69731cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 69741cb0ef41Sopenharmony_ci return (ssize_t)inlen; 69751cb0ef41Sopenharmony_ci } 69761cb0ef41Sopenharmony_ci 69771cb0ef41Sopenharmony_ci /* Pad Length field is consumed immediately */ 69781cb0ef41Sopenharmony_ci rv = 69791cb0ef41Sopenharmony_ci nghttp2_session_consume(session, iframe->frame.hd.stream_id, readlen); 69801cb0ef41Sopenharmony_ci 69811cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 69821cb0ef41Sopenharmony_ci return rv; 69831cb0ef41Sopenharmony_ci } 69841cb0ef41Sopenharmony_ci 69851cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 69861cb0ef41Sopenharmony_ci return (ssize_t)inlen; 69871cb0ef41Sopenharmony_ci } 69881cb0ef41Sopenharmony_ci 69891cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id); 69901cb0ef41Sopenharmony_ci if (stream) { 69911cb0ef41Sopenharmony_ci rv = nghttp2_session_update_recv_stream_window_size( 69921cb0ef41Sopenharmony_ci session, stream, readlen, 69931cb0ef41Sopenharmony_ci iframe->payloadleft || 69941cb0ef41Sopenharmony_ci (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0); 69951cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 69961cb0ef41Sopenharmony_ci return rv; 69971cb0ef41Sopenharmony_ci } 69981cb0ef41Sopenharmony_ci } 69991cb0ef41Sopenharmony_ci 70001cb0ef41Sopenharmony_ci busy = 1; 70011cb0ef41Sopenharmony_ci 70021cb0ef41Sopenharmony_ci padlen = inbound_frame_compute_pad(iframe); 70031cb0ef41Sopenharmony_ci if (padlen < 0) { 70041cb0ef41Sopenharmony_ci rv = nghttp2_session_terminate_session_with_reason( 70051cb0ef41Sopenharmony_ci session, NGHTTP2_PROTOCOL_ERROR, "DATA: invalid padding"); 70061cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 70071cb0ef41Sopenharmony_ci return rv; 70081cb0ef41Sopenharmony_ci } 70091cb0ef41Sopenharmony_ci return (ssize_t)inlen; 70101cb0ef41Sopenharmony_ci } 70111cb0ef41Sopenharmony_ci 70121cb0ef41Sopenharmony_ci iframe->frame.data.padlen = (size_t)padlen; 70131cb0ef41Sopenharmony_ci 70141cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_READ_DATA; 70151cb0ef41Sopenharmony_ci 70161cb0ef41Sopenharmony_ci break; 70171cb0ef41Sopenharmony_ci case NGHTTP2_IB_READ_DATA: 70181cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id); 70191cb0ef41Sopenharmony_ci 70201cb0ef41Sopenharmony_ci if (!stream) { 70211cb0ef41Sopenharmony_ci busy = 1; 70221cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_DATA; 70231cb0ef41Sopenharmony_ci break; 70241cb0ef41Sopenharmony_ci } 70251cb0ef41Sopenharmony_ci 70261cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_READ_DATA]\n"); 70271cb0ef41Sopenharmony_ci 70281cb0ef41Sopenharmony_ci readlen = inbound_frame_payload_readlen(iframe, in, last); 70291cb0ef41Sopenharmony_ci iframe->payloadleft -= readlen; 70301cb0ef41Sopenharmony_ci in += readlen; 70311cb0ef41Sopenharmony_ci 70321cb0ef41Sopenharmony_ci DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, 70331cb0ef41Sopenharmony_ci iframe->payloadleft); 70341cb0ef41Sopenharmony_ci 70351cb0ef41Sopenharmony_ci if (readlen > 0) { 70361cb0ef41Sopenharmony_ci ssize_t data_readlen; 70371cb0ef41Sopenharmony_ci 70381cb0ef41Sopenharmony_ci rv = nghttp2_session_update_recv_connection_window_size(session, 70391cb0ef41Sopenharmony_ci readlen); 70401cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 70411cb0ef41Sopenharmony_ci return rv; 70421cb0ef41Sopenharmony_ci } 70431cb0ef41Sopenharmony_ci 70441cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 70451cb0ef41Sopenharmony_ci return (ssize_t)inlen; 70461cb0ef41Sopenharmony_ci } 70471cb0ef41Sopenharmony_ci 70481cb0ef41Sopenharmony_ci rv = nghttp2_session_update_recv_stream_window_size( 70491cb0ef41Sopenharmony_ci session, stream, readlen, 70501cb0ef41Sopenharmony_ci iframe->payloadleft || 70511cb0ef41Sopenharmony_ci (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0); 70521cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 70531cb0ef41Sopenharmony_ci return rv; 70541cb0ef41Sopenharmony_ci } 70551cb0ef41Sopenharmony_ci 70561cb0ef41Sopenharmony_ci data_readlen = inbound_frame_effective_readlen( 70571cb0ef41Sopenharmony_ci iframe, iframe->payloadleft, readlen); 70581cb0ef41Sopenharmony_ci 70591cb0ef41Sopenharmony_ci if (data_readlen == -1) { 70601cb0ef41Sopenharmony_ci /* everything is padding */ 70611cb0ef41Sopenharmony_ci data_readlen = 0; 70621cb0ef41Sopenharmony_ci } 70631cb0ef41Sopenharmony_ci 70641cb0ef41Sopenharmony_ci padlen = (ssize_t)readlen - data_readlen; 70651cb0ef41Sopenharmony_ci 70661cb0ef41Sopenharmony_ci if (padlen > 0) { 70671cb0ef41Sopenharmony_ci /* Padding is considered as "consumed" immediately */ 70681cb0ef41Sopenharmony_ci rv = nghttp2_session_consume(session, iframe->frame.hd.stream_id, 70691cb0ef41Sopenharmony_ci (size_t)padlen); 70701cb0ef41Sopenharmony_ci 70711cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 70721cb0ef41Sopenharmony_ci return rv; 70731cb0ef41Sopenharmony_ci } 70741cb0ef41Sopenharmony_ci 70751cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 70761cb0ef41Sopenharmony_ci return (ssize_t)inlen; 70771cb0ef41Sopenharmony_ci } 70781cb0ef41Sopenharmony_ci } 70791cb0ef41Sopenharmony_ci 70801cb0ef41Sopenharmony_ci DEBUGF("recv: data_readlen=%zd\n", data_readlen); 70811cb0ef41Sopenharmony_ci 70821cb0ef41Sopenharmony_ci if (data_readlen > 0) { 70831cb0ef41Sopenharmony_ci if (session_enforce_http_messaging(session)) { 70841cb0ef41Sopenharmony_ci if (nghttp2_http_on_data_chunk(stream, (size_t)data_readlen) != 0) { 70851cb0ef41Sopenharmony_ci if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { 70861cb0ef41Sopenharmony_ci /* Consume all data for connection immediately here */ 70871cb0ef41Sopenharmony_ci rv = session_update_connection_consumed_size( 70881cb0ef41Sopenharmony_ci session, (size_t)data_readlen); 70891cb0ef41Sopenharmony_ci 70901cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 70911cb0ef41Sopenharmony_ci return rv; 70921cb0ef41Sopenharmony_ci } 70931cb0ef41Sopenharmony_ci 70941cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_DATA) { 70951cb0ef41Sopenharmony_ci return (ssize_t)inlen; 70961cb0ef41Sopenharmony_ci } 70971cb0ef41Sopenharmony_ci } 70981cb0ef41Sopenharmony_ci 70991cb0ef41Sopenharmony_ci rv = nghttp2_session_add_rst_stream( 71001cb0ef41Sopenharmony_ci session, iframe->frame.hd.stream_id, NGHTTP2_PROTOCOL_ERROR); 71011cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 71021cb0ef41Sopenharmony_ci return rv; 71031cb0ef41Sopenharmony_ci } 71041cb0ef41Sopenharmony_ci busy = 1; 71051cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_DATA; 71061cb0ef41Sopenharmony_ci break; 71071cb0ef41Sopenharmony_ci } 71081cb0ef41Sopenharmony_ci } 71091cb0ef41Sopenharmony_ci if (session->callbacks.on_data_chunk_recv_callback) { 71101cb0ef41Sopenharmony_ci rv = session->callbacks.on_data_chunk_recv_callback( 71111cb0ef41Sopenharmony_ci session, iframe->frame.hd.flags, iframe->frame.hd.stream_id, 71121cb0ef41Sopenharmony_ci in - readlen, (size_t)data_readlen, session->user_data); 71131cb0ef41Sopenharmony_ci if (rv == NGHTTP2_ERR_PAUSE) { 71141cb0ef41Sopenharmony_ci return (ssize_t)(in - first); 71151cb0ef41Sopenharmony_ci } 71161cb0ef41Sopenharmony_ci 71171cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 71181cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 71191cb0ef41Sopenharmony_ci } 71201cb0ef41Sopenharmony_ci } 71211cb0ef41Sopenharmony_ci } 71221cb0ef41Sopenharmony_ci } 71231cb0ef41Sopenharmony_ci 71241cb0ef41Sopenharmony_ci if (iframe->payloadleft) { 71251cb0ef41Sopenharmony_ci break; 71261cb0ef41Sopenharmony_ci } 71271cb0ef41Sopenharmony_ci 71281cb0ef41Sopenharmony_ci rv = session_process_data_frame(session); 71291cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 71301cb0ef41Sopenharmony_ci return rv; 71311cb0ef41Sopenharmony_ci } 71321cb0ef41Sopenharmony_ci 71331cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 71341cb0ef41Sopenharmony_ci 71351cb0ef41Sopenharmony_ci break; 71361cb0ef41Sopenharmony_ci case NGHTTP2_IB_IGN_DATA: 71371cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_IGN_DATA]\n"); 71381cb0ef41Sopenharmony_ci 71391cb0ef41Sopenharmony_ci readlen = inbound_frame_payload_readlen(iframe, in, last); 71401cb0ef41Sopenharmony_ci iframe->payloadleft -= readlen; 71411cb0ef41Sopenharmony_ci in += readlen; 71421cb0ef41Sopenharmony_ci 71431cb0ef41Sopenharmony_ci DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, 71441cb0ef41Sopenharmony_ci iframe->payloadleft); 71451cb0ef41Sopenharmony_ci 71461cb0ef41Sopenharmony_ci if (readlen > 0) { 71471cb0ef41Sopenharmony_ci /* Update connection-level flow control window for ignored 71481cb0ef41Sopenharmony_ci DATA frame too */ 71491cb0ef41Sopenharmony_ci rv = nghttp2_session_update_recv_connection_window_size(session, 71501cb0ef41Sopenharmony_ci readlen); 71511cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 71521cb0ef41Sopenharmony_ci return rv; 71531cb0ef41Sopenharmony_ci } 71541cb0ef41Sopenharmony_ci 71551cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 71561cb0ef41Sopenharmony_ci return (ssize_t)inlen; 71571cb0ef41Sopenharmony_ci } 71581cb0ef41Sopenharmony_ci 71591cb0ef41Sopenharmony_ci if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { 71601cb0ef41Sopenharmony_ci 71611cb0ef41Sopenharmony_ci /* Ignored DATA is considered as "consumed" immediately. */ 71621cb0ef41Sopenharmony_ci rv = session_update_connection_consumed_size(session, readlen); 71631cb0ef41Sopenharmony_ci 71641cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 71651cb0ef41Sopenharmony_ci return rv; 71661cb0ef41Sopenharmony_ci } 71671cb0ef41Sopenharmony_ci 71681cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 71691cb0ef41Sopenharmony_ci return (ssize_t)inlen; 71701cb0ef41Sopenharmony_ci } 71711cb0ef41Sopenharmony_ci } 71721cb0ef41Sopenharmony_ci } 71731cb0ef41Sopenharmony_ci 71741cb0ef41Sopenharmony_ci if (iframe->payloadleft) { 71751cb0ef41Sopenharmony_ci break; 71761cb0ef41Sopenharmony_ci } 71771cb0ef41Sopenharmony_ci 71781cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 71791cb0ef41Sopenharmony_ci 71801cb0ef41Sopenharmony_ci break; 71811cb0ef41Sopenharmony_ci case NGHTTP2_IB_IGN_ALL: 71821cb0ef41Sopenharmony_ci return (ssize_t)inlen; 71831cb0ef41Sopenharmony_ci case NGHTTP2_IB_READ_EXTENSION_PAYLOAD: 71841cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_READ_EXTENSION_PAYLOAD]\n"); 71851cb0ef41Sopenharmony_ci 71861cb0ef41Sopenharmony_ci readlen = inbound_frame_payload_readlen(iframe, in, last); 71871cb0ef41Sopenharmony_ci iframe->payloadleft -= readlen; 71881cb0ef41Sopenharmony_ci in += readlen; 71891cb0ef41Sopenharmony_ci 71901cb0ef41Sopenharmony_ci DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, 71911cb0ef41Sopenharmony_ci iframe->payloadleft); 71921cb0ef41Sopenharmony_ci 71931cb0ef41Sopenharmony_ci if (readlen > 0) { 71941cb0ef41Sopenharmony_ci rv = session_call_on_extension_chunk_recv_callback( 71951cb0ef41Sopenharmony_ci session, in - readlen, readlen); 71961cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 71971cb0ef41Sopenharmony_ci return rv; 71981cb0ef41Sopenharmony_ci } 71991cb0ef41Sopenharmony_ci 72001cb0ef41Sopenharmony_ci if (rv != 0) { 72011cb0ef41Sopenharmony_ci busy = 1; 72021cb0ef41Sopenharmony_ci 72031cb0ef41Sopenharmony_ci iframe->state = NGHTTP2_IB_IGN_PAYLOAD; 72041cb0ef41Sopenharmony_ci 72051cb0ef41Sopenharmony_ci break; 72061cb0ef41Sopenharmony_ci } 72071cb0ef41Sopenharmony_ci } 72081cb0ef41Sopenharmony_ci 72091cb0ef41Sopenharmony_ci if (iframe->payloadleft > 0) { 72101cb0ef41Sopenharmony_ci break; 72111cb0ef41Sopenharmony_ci } 72121cb0ef41Sopenharmony_ci 72131cb0ef41Sopenharmony_ci rv = session_process_extension_frame(session); 72141cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 72151cb0ef41Sopenharmony_ci return rv; 72161cb0ef41Sopenharmony_ci } 72171cb0ef41Sopenharmony_ci 72181cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 72191cb0ef41Sopenharmony_ci 72201cb0ef41Sopenharmony_ci break; 72211cb0ef41Sopenharmony_ci case NGHTTP2_IB_READ_ALTSVC_PAYLOAD: 72221cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_READ_ALTSVC_PAYLOAD]\n"); 72231cb0ef41Sopenharmony_ci 72241cb0ef41Sopenharmony_ci readlen = inbound_frame_payload_readlen(iframe, in, last); 72251cb0ef41Sopenharmony_ci if (readlen > 0) { 72261cb0ef41Sopenharmony_ci iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen); 72271cb0ef41Sopenharmony_ci 72281cb0ef41Sopenharmony_ci iframe->payloadleft -= readlen; 72291cb0ef41Sopenharmony_ci in += readlen; 72301cb0ef41Sopenharmony_ci } 72311cb0ef41Sopenharmony_ci 72321cb0ef41Sopenharmony_ci DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, 72331cb0ef41Sopenharmony_ci iframe->payloadleft); 72341cb0ef41Sopenharmony_ci 72351cb0ef41Sopenharmony_ci if (iframe->payloadleft) { 72361cb0ef41Sopenharmony_ci assert(nghttp2_buf_avail(&iframe->lbuf) > 0); 72371cb0ef41Sopenharmony_ci 72381cb0ef41Sopenharmony_ci break; 72391cb0ef41Sopenharmony_ci } 72401cb0ef41Sopenharmony_ci 72411cb0ef41Sopenharmony_ci rv = session_process_altsvc_frame(session); 72421cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 72431cb0ef41Sopenharmony_ci return rv; 72441cb0ef41Sopenharmony_ci } 72451cb0ef41Sopenharmony_ci 72461cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 72471cb0ef41Sopenharmony_ci 72481cb0ef41Sopenharmony_ci break; 72491cb0ef41Sopenharmony_ci case NGHTTP2_IB_READ_ORIGIN_PAYLOAD: 72501cb0ef41Sopenharmony_ci DEBUGF("recv: [IB_READ_ORIGIN_PAYLOAD]\n"); 72511cb0ef41Sopenharmony_ci 72521cb0ef41Sopenharmony_ci readlen = inbound_frame_payload_readlen(iframe, in, last); 72531cb0ef41Sopenharmony_ci 72541cb0ef41Sopenharmony_ci if (readlen > 0) { 72551cb0ef41Sopenharmony_ci iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen); 72561cb0ef41Sopenharmony_ci 72571cb0ef41Sopenharmony_ci iframe->payloadleft -= readlen; 72581cb0ef41Sopenharmony_ci in += readlen; 72591cb0ef41Sopenharmony_ci } 72601cb0ef41Sopenharmony_ci 72611cb0ef41Sopenharmony_ci DEBUGF("recv: readlen=%zu, payloadleft=%zu\n", readlen, 72621cb0ef41Sopenharmony_ci iframe->payloadleft); 72631cb0ef41Sopenharmony_ci 72641cb0ef41Sopenharmony_ci if (iframe->payloadleft) { 72651cb0ef41Sopenharmony_ci assert(nghttp2_buf_avail(&iframe->lbuf) > 0); 72661cb0ef41Sopenharmony_ci 72671cb0ef41Sopenharmony_ci break; 72681cb0ef41Sopenharmony_ci } 72691cb0ef41Sopenharmony_ci 72701cb0ef41Sopenharmony_ci rv = session_process_origin_frame(session); 72711cb0ef41Sopenharmony_ci 72721cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 72731cb0ef41Sopenharmony_ci return rv; 72741cb0ef41Sopenharmony_ci } 72751cb0ef41Sopenharmony_ci 72761cb0ef41Sopenharmony_ci if (iframe->state == NGHTTP2_IB_IGN_ALL) { 72771cb0ef41Sopenharmony_ci return (ssize_t)inlen; 72781cb0ef41Sopenharmony_ci } 72791cb0ef41Sopenharmony_ci 72801cb0ef41Sopenharmony_ci session_inbound_frame_reset(session); 72811cb0ef41Sopenharmony_ci 72821cb0ef41Sopenharmony_ci break; 72831cb0ef41Sopenharmony_ci } 72841cb0ef41Sopenharmony_ci 72851cb0ef41Sopenharmony_ci if (!busy && in == last) { 72861cb0ef41Sopenharmony_ci break; 72871cb0ef41Sopenharmony_ci } 72881cb0ef41Sopenharmony_ci 72891cb0ef41Sopenharmony_ci busy = 0; 72901cb0ef41Sopenharmony_ci } 72911cb0ef41Sopenharmony_ci 72921cb0ef41Sopenharmony_ci assert(in == last); 72931cb0ef41Sopenharmony_ci 72941cb0ef41Sopenharmony_ci return (ssize_t)(in - first); 72951cb0ef41Sopenharmony_ci} 72961cb0ef41Sopenharmony_ci 72971cb0ef41Sopenharmony_ciint nghttp2_session_recv(nghttp2_session *session) { 72981cb0ef41Sopenharmony_ci uint8_t buf[NGHTTP2_INBOUND_BUFFER_LENGTH]; 72991cb0ef41Sopenharmony_ci while (1) { 73001cb0ef41Sopenharmony_ci ssize_t readlen; 73011cb0ef41Sopenharmony_ci readlen = session_recv(session, buf, sizeof(buf)); 73021cb0ef41Sopenharmony_ci if (readlen > 0) { 73031cb0ef41Sopenharmony_ci ssize_t proclen = nghttp2_session_mem_recv(session, buf, (size_t)readlen); 73041cb0ef41Sopenharmony_ci if (proclen < 0) { 73051cb0ef41Sopenharmony_ci return (int)proclen; 73061cb0ef41Sopenharmony_ci } 73071cb0ef41Sopenharmony_ci assert(proclen == readlen); 73081cb0ef41Sopenharmony_ci } else if (readlen == 0 || readlen == NGHTTP2_ERR_WOULDBLOCK) { 73091cb0ef41Sopenharmony_ci return 0; 73101cb0ef41Sopenharmony_ci } else if (readlen == NGHTTP2_ERR_EOF) { 73111cb0ef41Sopenharmony_ci return NGHTTP2_ERR_EOF; 73121cb0ef41Sopenharmony_ci } else if (readlen < 0) { 73131cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 73141cb0ef41Sopenharmony_ci } 73151cb0ef41Sopenharmony_ci } 73161cb0ef41Sopenharmony_ci} 73171cb0ef41Sopenharmony_ci 73181cb0ef41Sopenharmony_ci/* 73191cb0ef41Sopenharmony_ci * Returns the number of active streams, which includes streams in 73201cb0ef41Sopenharmony_ci * reserved state. 73211cb0ef41Sopenharmony_ci */ 73221cb0ef41Sopenharmony_cistatic size_t session_get_num_active_streams(nghttp2_session *session) { 73231cb0ef41Sopenharmony_ci return nghttp2_map_size(&session->streams) - session->num_closed_streams - 73241cb0ef41Sopenharmony_ci session->num_idle_streams; 73251cb0ef41Sopenharmony_ci} 73261cb0ef41Sopenharmony_ci 73271cb0ef41Sopenharmony_ciint nghttp2_session_want_read(nghttp2_session *session) { 73281cb0ef41Sopenharmony_ci size_t num_active_streams; 73291cb0ef41Sopenharmony_ci 73301cb0ef41Sopenharmony_ci /* If this flag is set, we don't want to read. The application 73311cb0ef41Sopenharmony_ci should drop the connection. */ 73321cb0ef41Sopenharmony_ci if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_SENT) { 73331cb0ef41Sopenharmony_ci return 0; 73341cb0ef41Sopenharmony_ci } 73351cb0ef41Sopenharmony_ci 73361cb0ef41Sopenharmony_ci num_active_streams = session_get_num_active_streams(session); 73371cb0ef41Sopenharmony_ci 73381cb0ef41Sopenharmony_ci /* Unless termination GOAWAY is sent or received, we always want to 73391cb0ef41Sopenharmony_ci read incoming frames. */ 73401cb0ef41Sopenharmony_ci 73411cb0ef41Sopenharmony_ci if (num_active_streams > 0) { 73421cb0ef41Sopenharmony_ci return 1; 73431cb0ef41Sopenharmony_ci } 73441cb0ef41Sopenharmony_ci 73451cb0ef41Sopenharmony_ci /* If there is no active streams and GOAWAY has been sent or 73461cb0ef41Sopenharmony_ci received, we are done with this session. */ 73471cb0ef41Sopenharmony_ci return (session->goaway_flags & 73481cb0ef41Sopenharmony_ci (NGHTTP2_GOAWAY_SENT | NGHTTP2_GOAWAY_RECV)) == 0; 73491cb0ef41Sopenharmony_ci} 73501cb0ef41Sopenharmony_ci 73511cb0ef41Sopenharmony_ciint nghttp2_session_want_write(nghttp2_session *session) { 73521cb0ef41Sopenharmony_ci /* If these flag is set, we don't want to write any data. The 73531cb0ef41Sopenharmony_ci application should drop the connection. */ 73541cb0ef41Sopenharmony_ci if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_SENT) { 73551cb0ef41Sopenharmony_ci return 0; 73561cb0ef41Sopenharmony_ci } 73571cb0ef41Sopenharmony_ci 73581cb0ef41Sopenharmony_ci /* 73591cb0ef41Sopenharmony_ci * Unless termination GOAWAY is sent or received, we want to write 73601cb0ef41Sopenharmony_ci * frames if there is pending ones. If pending frame is request/push 73611cb0ef41Sopenharmony_ci * response HEADERS and concurrent stream limit is reached, we don't 73621cb0ef41Sopenharmony_ci * want to write them. 73631cb0ef41Sopenharmony_ci */ 73641cb0ef41Sopenharmony_ci return session->aob.item || nghttp2_outbound_queue_top(&session->ob_urgent) || 73651cb0ef41Sopenharmony_ci nghttp2_outbound_queue_top(&session->ob_reg) || 73661cb0ef41Sopenharmony_ci ((!nghttp2_pq_empty(&session->root.obq) || 73671cb0ef41Sopenharmony_ci !session_sched_empty(session)) && 73681cb0ef41Sopenharmony_ci session->remote_window_size > 0) || 73691cb0ef41Sopenharmony_ci (nghttp2_outbound_queue_top(&session->ob_syn) && 73701cb0ef41Sopenharmony_ci !session_is_outgoing_concurrent_streams_max(session)); 73711cb0ef41Sopenharmony_ci} 73721cb0ef41Sopenharmony_ci 73731cb0ef41Sopenharmony_ciint nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags, 73741cb0ef41Sopenharmony_ci const uint8_t *opaque_data) { 73751cb0ef41Sopenharmony_ci int rv; 73761cb0ef41Sopenharmony_ci nghttp2_outbound_item *item; 73771cb0ef41Sopenharmony_ci nghttp2_frame *frame; 73781cb0ef41Sopenharmony_ci nghttp2_mem *mem; 73791cb0ef41Sopenharmony_ci 73801cb0ef41Sopenharmony_ci mem = &session->mem; 73811cb0ef41Sopenharmony_ci 73821cb0ef41Sopenharmony_ci if ((flags & NGHTTP2_FLAG_ACK) && 73831cb0ef41Sopenharmony_ci session->obq_flood_counter_ >= session->max_outbound_ack) { 73841cb0ef41Sopenharmony_ci return NGHTTP2_ERR_FLOODED; 73851cb0ef41Sopenharmony_ci } 73861cb0ef41Sopenharmony_ci 73871cb0ef41Sopenharmony_ci item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); 73881cb0ef41Sopenharmony_ci if (item == NULL) { 73891cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 73901cb0ef41Sopenharmony_ci } 73911cb0ef41Sopenharmony_ci 73921cb0ef41Sopenharmony_ci nghttp2_outbound_item_init(item); 73931cb0ef41Sopenharmony_ci 73941cb0ef41Sopenharmony_ci frame = &item->frame; 73951cb0ef41Sopenharmony_ci 73961cb0ef41Sopenharmony_ci nghttp2_frame_ping_init(&frame->ping, flags, opaque_data); 73971cb0ef41Sopenharmony_ci 73981cb0ef41Sopenharmony_ci rv = nghttp2_session_add_item(session, item); 73991cb0ef41Sopenharmony_ci 74001cb0ef41Sopenharmony_ci if (rv != 0) { 74011cb0ef41Sopenharmony_ci nghttp2_frame_ping_free(&frame->ping); 74021cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, item); 74031cb0ef41Sopenharmony_ci return rv; 74041cb0ef41Sopenharmony_ci } 74051cb0ef41Sopenharmony_ci 74061cb0ef41Sopenharmony_ci if (flags & NGHTTP2_FLAG_ACK) { 74071cb0ef41Sopenharmony_ci ++session->obq_flood_counter_; 74081cb0ef41Sopenharmony_ci } 74091cb0ef41Sopenharmony_ci 74101cb0ef41Sopenharmony_ci return 0; 74111cb0ef41Sopenharmony_ci} 74121cb0ef41Sopenharmony_ci 74131cb0ef41Sopenharmony_ciint nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id, 74141cb0ef41Sopenharmony_ci uint32_t error_code, const uint8_t *opaque_data, 74151cb0ef41Sopenharmony_ci size_t opaque_data_len, uint8_t aux_flags) { 74161cb0ef41Sopenharmony_ci int rv; 74171cb0ef41Sopenharmony_ci nghttp2_outbound_item *item; 74181cb0ef41Sopenharmony_ci nghttp2_frame *frame; 74191cb0ef41Sopenharmony_ci uint8_t *opaque_data_copy = NULL; 74201cb0ef41Sopenharmony_ci nghttp2_goaway_aux_data *aux_data; 74211cb0ef41Sopenharmony_ci nghttp2_mem *mem; 74221cb0ef41Sopenharmony_ci 74231cb0ef41Sopenharmony_ci mem = &session->mem; 74241cb0ef41Sopenharmony_ci 74251cb0ef41Sopenharmony_ci if (nghttp2_session_is_my_stream_id(session, last_stream_id)) { 74261cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 74271cb0ef41Sopenharmony_ci } 74281cb0ef41Sopenharmony_ci 74291cb0ef41Sopenharmony_ci if (opaque_data_len) { 74301cb0ef41Sopenharmony_ci if (opaque_data_len + 8 > NGHTTP2_MAX_PAYLOADLEN) { 74311cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 74321cb0ef41Sopenharmony_ci } 74331cb0ef41Sopenharmony_ci opaque_data_copy = nghttp2_mem_malloc(mem, opaque_data_len); 74341cb0ef41Sopenharmony_ci if (opaque_data_copy == NULL) { 74351cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 74361cb0ef41Sopenharmony_ci } 74371cb0ef41Sopenharmony_ci memcpy(opaque_data_copy, opaque_data, opaque_data_len); 74381cb0ef41Sopenharmony_ci } 74391cb0ef41Sopenharmony_ci 74401cb0ef41Sopenharmony_ci item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); 74411cb0ef41Sopenharmony_ci if (item == NULL) { 74421cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, opaque_data_copy); 74431cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 74441cb0ef41Sopenharmony_ci } 74451cb0ef41Sopenharmony_ci 74461cb0ef41Sopenharmony_ci nghttp2_outbound_item_init(item); 74471cb0ef41Sopenharmony_ci 74481cb0ef41Sopenharmony_ci frame = &item->frame; 74491cb0ef41Sopenharmony_ci 74501cb0ef41Sopenharmony_ci /* last_stream_id must not be increased from the value previously 74511cb0ef41Sopenharmony_ci sent */ 74521cb0ef41Sopenharmony_ci last_stream_id = nghttp2_min(last_stream_id, session->local_last_stream_id); 74531cb0ef41Sopenharmony_ci 74541cb0ef41Sopenharmony_ci nghttp2_frame_goaway_init(&frame->goaway, last_stream_id, error_code, 74551cb0ef41Sopenharmony_ci opaque_data_copy, opaque_data_len); 74561cb0ef41Sopenharmony_ci 74571cb0ef41Sopenharmony_ci aux_data = &item->aux_data.goaway; 74581cb0ef41Sopenharmony_ci aux_data->flags = aux_flags; 74591cb0ef41Sopenharmony_ci 74601cb0ef41Sopenharmony_ci rv = nghttp2_session_add_item(session, item); 74611cb0ef41Sopenharmony_ci if (rv != 0) { 74621cb0ef41Sopenharmony_ci nghttp2_frame_goaway_free(&frame->goaway, mem); 74631cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, item); 74641cb0ef41Sopenharmony_ci return rv; 74651cb0ef41Sopenharmony_ci } 74661cb0ef41Sopenharmony_ci 74671cb0ef41Sopenharmony_ci session->goaway_flags |= NGHTTP2_GOAWAY_SUBMITTED; 74681cb0ef41Sopenharmony_ci 74691cb0ef41Sopenharmony_ci return 0; 74701cb0ef41Sopenharmony_ci} 74711cb0ef41Sopenharmony_ci 74721cb0ef41Sopenharmony_ciint nghttp2_session_add_window_update(nghttp2_session *session, uint8_t flags, 74731cb0ef41Sopenharmony_ci int32_t stream_id, 74741cb0ef41Sopenharmony_ci int32_t window_size_increment) { 74751cb0ef41Sopenharmony_ci int rv; 74761cb0ef41Sopenharmony_ci nghttp2_outbound_item *item; 74771cb0ef41Sopenharmony_ci nghttp2_frame *frame; 74781cb0ef41Sopenharmony_ci nghttp2_mem *mem; 74791cb0ef41Sopenharmony_ci 74801cb0ef41Sopenharmony_ci mem = &session->mem; 74811cb0ef41Sopenharmony_ci item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); 74821cb0ef41Sopenharmony_ci if (item == NULL) { 74831cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 74841cb0ef41Sopenharmony_ci } 74851cb0ef41Sopenharmony_ci 74861cb0ef41Sopenharmony_ci nghttp2_outbound_item_init(item); 74871cb0ef41Sopenharmony_ci 74881cb0ef41Sopenharmony_ci frame = &item->frame; 74891cb0ef41Sopenharmony_ci 74901cb0ef41Sopenharmony_ci nghttp2_frame_window_update_init(&frame->window_update, flags, stream_id, 74911cb0ef41Sopenharmony_ci window_size_increment); 74921cb0ef41Sopenharmony_ci 74931cb0ef41Sopenharmony_ci rv = nghttp2_session_add_item(session, item); 74941cb0ef41Sopenharmony_ci 74951cb0ef41Sopenharmony_ci if (rv != 0) { 74961cb0ef41Sopenharmony_ci nghttp2_frame_window_update_free(&frame->window_update); 74971cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, item); 74981cb0ef41Sopenharmony_ci return rv; 74991cb0ef41Sopenharmony_ci } 75001cb0ef41Sopenharmony_ci return 0; 75011cb0ef41Sopenharmony_ci} 75021cb0ef41Sopenharmony_ci 75031cb0ef41Sopenharmony_cistatic void 75041cb0ef41Sopenharmony_cisession_append_inflight_settings(nghttp2_session *session, 75051cb0ef41Sopenharmony_ci nghttp2_inflight_settings *settings) { 75061cb0ef41Sopenharmony_ci nghttp2_inflight_settings **i; 75071cb0ef41Sopenharmony_ci 75081cb0ef41Sopenharmony_ci for (i = &session->inflight_settings_head; *i; i = &(*i)->next) 75091cb0ef41Sopenharmony_ci ; 75101cb0ef41Sopenharmony_ci 75111cb0ef41Sopenharmony_ci *i = settings; 75121cb0ef41Sopenharmony_ci} 75131cb0ef41Sopenharmony_ci 75141cb0ef41Sopenharmony_ciint nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags, 75151cb0ef41Sopenharmony_ci const nghttp2_settings_entry *iv, size_t niv) { 75161cb0ef41Sopenharmony_ci nghttp2_outbound_item *item; 75171cb0ef41Sopenharmony_ci nghttp2_frame *frame; 75181cb0ef41Sopenharmony_ci nghttp2_settings_entry *iv_copy; 75191cb0ef41Sopenharmony_ci size_t i; 75201cb0ef41Sopenharmony_ci int rv; 75211cb0ef41Sopenharmony_ci nghttp2_mem *mem; 75221cb0ef41Sopenharmony_ci nghttp2_inflight_settings *inflight_settings = NULL; 75231cb0ef41Sopenharmony_ci uint8_t no_rfc7540_pri = session->pending_no_rfc7540_priorities; 75241cb0ef41Sopenharmony_ci 75251cb0ef41Sopenharmony_ci mem = &session->mem; 75261cb0ef41Sopenharmony_ci 75271cb0ef41Sopenharmony_ci if (flags & NGHTTP2_FLAG_ACK) { 75281cb0ef41Sopenharmony_ci if (niv != 0) { 75291cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 75301cb0ef41Sopenharmony_ci } 75311cb0ef41Sopenharmony_ci 75321cb0ef41Sopenharmony_ci if (session->obq_flood_counter_ >= session->max_outbound_ack) { 75331cb0ef41Sopenharmony_ci return NGHTTP2_ERR_FLOODED; 75341cb0ef41Sopenharmony_ci } 75351cb0ef41Sopenharmony_ci } 75361cb0ef41Sopenharmony_ci 75371cb0ef41Sopenharmony_ci if (!nghttp2_iv_check(iv, niv)) { 75381cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 75391cb0ef41Sopenharmony_ci } 75401cb0ef41Sopenharmony_ci 75411cb0ef41Sopenharmony_ci for (i = 0; i < niv; ++i) { 75421cb0ef41Sopenharmony_ci if (iv[i].settings_id != NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES) { 75431cb0ef41Sopenharmony_ci continue; 75441cb0ef41Sopenharmony_ci } 75451cb0ef41Sopenharmony_ci 75461cb0ef41Sopenharmony_ci if (no_rfc7540_pri == UINT8_MAX) { 75471cb0ef41Sopenharmony_ci no_rfc7540_pri = (uint8_t)iv[i].value; 75481cb0ef41Sopenharmony_ci continue; 75491cb0ef41Sopenharmony_ci } 75501cb0ef41Sopenharmony_ci 75511cb0ef41Sopenharmony_ci if (iv[i].value != (uint32_t)no_rfc7540_pri) { 75521cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 75531cb0ef41Sopenharmony_ci } 75541cb0ef41Sopenharmony_ci } 75551cb0ef41Sopenharmony_ci 75561cb0ef41Sopenharmony_ci item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); 75571cb0ef41Sopenharmony_ci if (item == NULL) { 75581cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 75591cb0ef41Sopenharmony_ci } 75601cb0ef41Sopenharmony_ci 75611cb0ef41Sopenharmony_ci if (niv > 0) { 75621cb0ef41Sopenharmony_ci iv_copy = nghttp2_frame_iv_copy(iv, niv, mem); 75631cb0ef41Sopenharmony_ci if (iv_copy == NULL) { 75641cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, item); 75651cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 75661cb0ef41Sopenharmony_ci } 75671cb0ef41Sopenharmony_ci } else { 75681cb0ef41Sopenharmony_ci iv_copy = NULL; 75691cb0ef41Sopenharmony_ci } 75701cb0ef41Sopenharmony_ci 75711cb0ef41Sopenharmony_ci if ((flags & NGHTTP2_FLAG_ACK) == 0) { 75721cb0ef41Sopenharmony_ci rv = inflight_settings_new(&inflight_settings, iv, niv, mem); 75731cb0ef41Sopenharmony_ci if (rv != 0) { 75741cb0ef41Sopenharmony_ci assert(nghttp2_is_fatal(rv)); 75751cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, iv_copy); 75761cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, item); 75771cb0ef41Sopenharmony_ci return rv; 75781cb0ef41Sopenharmony_ci } 75791cb0ef41Sopenharmony_ci } 75801cb0ef41Sopenharmony_ci 75811cb0ef41Sopenharmony_ci nghttp2_outbound_item_init(item); 75821cb0ef41Sopenharmony_ci 75831cb0ef41Sopenharmony_ci frame = &item->frame; 75841cb0ef41Sopenharmony_ci 75851cb0ef41Sopenharmony_ci nghttp2_frame_settings_init(&frame->settings, flags, iv_copy, niv); 75861cb0ef41Sopenharmony_ci rv = nghttp2_session_add_item(session, item); 75871cb0ef41Sopenharmony_ci if (rv != 0) { 75881cb0ef41Sopenharmony_ci /* The only expected error is fatal one */ 75891cb0ef41Sopenharmony_ci assert(nghttp2_is_fatal(rv)); 75901cb0ef41Sopenharmony_ci 75911cb0ef41Sopenharmony_ci inflight_settings_del(inflight_settings, mem); 75921cb0ef41Sopenharmony_ci 75931cb0ef41Sopenharmony_ci nghttp2_frame_settings_free(&frame->settings, mem); 75941cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, item); 75951cb0ef41Sopenharmony_ci 75961cb0ef41Sopenharmony_ci return rv; 75971cb0ef41Sopenharmony_ci } 75981cb0ef41Sopenharmony_ci 75991cb0ef41Sopenharmony_ci if (flags & NGHTTP2_FLAG_ACK) { 76001cb0ef41Sopenharmony_ci ++session->obq_flood_counter_; 76011cb0ef41Sopenharmony_ci } else { 76021cb0ef41Sopenharmony_ci session_append_inflight_settings(session, inflight_settings); 76031cb0ef41Sopenharmony_ci } 76041cb0ef41Sopenharmony_ci 76051cb0ef41Sopenharmony_ci /* Extract NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS and ENABLE_PUSH 76061cb0ef41Sopenharmony_ci here. We use it to refuse the incoming stream and PUSH_PROMISE 76071cb0ef41Sopenharmony_ci with RST_STREAM. */ 76081cb0ef41Sopenharmony_ci 76091cb0ef41Sopenharmony_ci for (i = niv; i > 0; --i) { 76101cb0ef41Sopenharmony_ci if (iv[i - 1].settings_id == NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS) { 76111cb0ef41Sopenharmony_ci session->pending_local_max_concurrent_stream = iv[i - 1].value; 76121cb0ef41Sopenharmony_ci break; 76131cb0ef41Sopenharmony_ci } 76141cb0ef41Sopenharmony_ci } 76151cb0ef41Sopenharmony_ci 76161cb0ef41Sopenharmony_ci for (i = niv; i > 0; --i) { 76171cb0ef41Sopenharmony_ci if (iv[i - 1].settings_id == NGHTTP2_SETTINGS_ENABLE_PUSH) { 76181cb0ef41Sopenharmony_ci session->pending_enable_push = (uint8_t)iv[i - 1].value; 76191cb0ef41Sopenharmony_ci break; 76201cb0ef41Sopenharmony_ci } 76211cb0ef41Sopenharmony_ci } 76221cb0ef41Sopenharmony_ci 76231cb0ef41Sopenharmony_ci for (i = niv; i > 0; --i) { 76241cb0ef41Sopenharmony_ci if (iv[i - 1].settings_id == NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL) { 76251cb0ef41Sopenharmony_ci session->pending_enable_connect_protocol = (uint8_t)iv[i - 1].value; 76261cb0ef41Sopenharmony_ci break; 76271cb0ef41Sopenharmony_ci } 76281cb0ef41Sopenharmony_ci } 76291cb0ef41Sopenharmony_ci 76301cb0ef41Sopenharmony_ci if (no_rfc7540_pri == UINT8_MAX) { 76311cb0ef41Sopenharmony_ci session->pending_no_rfc7540_priorities = 0; 76321cb0ef41Sopenharmony_ci } else { 76331cb0ef41Sopenharmony_ci session->pending_no_rfc7540_priorities = no_rfc7540_pri; 76341cb0ef41Sopenharmony_ci } 76351cb0ef41Sopenharmony_ci 76361cb0ef41Sopenharmony_ci return 0; 76371cb0ef41Sopenharmony_ci} 76381cb0ef41Sopenharmony_ci 76391cb0ef41Sopenharmony_ciint nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs, 76401cb0ef41Sopenharmony_ci size_t datamax, nghttp2_frame *frame, 76411cb0ef41Sopenharmony_ci nghttp2_data_aux_data *aux_data, 76421cb0ef41Sopenharmony_ci nghttp2_stream *stream) { 76431cb0ef41Sopenharmony_ci int rv; 76441cb0ef41Sopenharmony_ci uint32_t data_flags; 76451cb0ef41Sopenharmony_ci ssize_t payloadlen; 76461cb0ef41Sopenharmony_ci ssize_t padded_payloadlen; 76471cb0ef41Sopenharmony_ci nghttp2_buf *buf; 76481cb0ef41Sopenharmony_ci size_t max_payloadlen; 76491cb0ef41Sopenharmony_ci 76501cb0ef41Sopenharmony_ci assert(bufs->head == bufs->cur); 76511cb0ef41Sopenharmony_ci 76521cb0ef41Sopenharmony_ci buf = &bufs->cur->buf; 76531cb0ef41Sopenharmony_ci 76541cb0ef41Sopenharmony_ci if (session->callbacks.read_length_callback) { 76551cb0ef41Sopenharmony_ci 76561cb0ef41Sopenharmony_ci payloadlen = session->callbacks.read_length_callback( 76571cb0ef41Sopenharmony_ci session, frame->hd.type, stream->stream_id, session->remote_window_size, 76581cb0ef41Sopenharmony_ci stream->remote_window_size, session->remote_settings.max_frame_size, 76591cb0ef41Sopenharmony_ci session->user_data); 76601cb0ef41Sopenharmony_ci 76611cb0ef41Sopenharmony_ci DEBUGF("send: read_length_callback=%zd\n", payloadlen); 76621cb0ef41Sopenharmony_ci 76631cb0ef41Sopenharmony_ci payloadlen = nghttp2_session_enforce_flow_control_limits(session, stream, 76641cb0ef41Sopenharmony_ci payloadlen); 76651cb0ef41Sopenharmony_ci 76661cb0ef41Sopenharmony_ci DEBUGF("send: read_length_callback after flow control=%zd\n", payloadlen); 76671cb0ef41Sopenharmony_ci 76681cb0ef41Sopenharmony_ci if (payloadlen <= 0) { 76691cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 76701cb0ef41Sopenharmony_ci } 76711cb0ef41Sopenharmony_ci 76721cb0ef41Sopenharmony_ci if ((size_t)payloadlen > nghttp2_buf_avail(buf)) { 76731cb0ef41Sopenharmony_ci /* Resize the current buffer(s). The reason why we do +1 for 76741cb0ef41Sopenharmony_ci buffer size is for possible padding field. */ 76751cb0ef41Sopenharmony_ci rv = nghttp2_bufs_realloc(&session->aob.framebufs, 76761cb0ef41Sopenharmony_ci (size_t)(NGHTTP2_FRAME_HDLEN + 1 + payloadlen)); 76771cb0ef41Sopenharmony_ci 76781cb0ef41Sopenharmony_ci if (rv != 0) { 76791cb0ef41Sopenharmony_ci DEBUGF("send: realloc buffer failed rv=%d", rv); 76801cb0ef41Sopenharmony_ci /* If reallocation failed, old buffers are still in tact. So 76811cb0ef41Sopenharmony_ci use safe limit. */ 76821cb0ef41Sopenharmony_ci payloadlen = (ssize_t)datamax; 76831cb0ef41Sopenharmony_ci 76841cb0ef41Sopenharmony_ci DEBUGF("send: use safe limit payloadlen=%zd", payloadlen); 76851cb0ef41Sopenharmony_ci } else { 76861cb0ef41Sopenharmony_ci assert(&session->aob.framebufs == bufs); 76871cb0ef41Sopenharmony_ci 76881cb0ef41Sopenharmony_ci buf = &bufs->cur->buf; 76891cb0ef41Sopenharmony_ci } 76901cb0ef41Sopenharmony_ci } 76911cb0ef41Sopenharmony_ci datamax = (size_t)payloadlen; 76921cb0ef41Sopenharmony_ci } 76931cb0ef41Sopenharmony_ci 76941cb0ef41Sopenharmony_ci /* Current max DATA length is less then buffer chunk size */ 76951cb0ef41Sopenharmony_ci assert(nghttp2_buf_avail(buf) >= datamax); 76961cb0ef41Sopenharmony_ci 76971cb0ef41Sopenharmony_ci data_flags = NGHTTP2_DATA_FLAG_NONE; 76981cb0ef41Sopenharmony_ci payloadlen = aux_data->data_prd.read_callback( 76991cb0ef41Sopenharmony_ci session, frame->hd.stream_id, buf->pos, datamax, &data_flags, 77001cb0ef41Sopenharmony_ci &aux_data->data_prd.source, session->user_data); 77011cb0ef41Sopenharmony_ci 77021cb0ef41Sopenharmony_ci if (payloadlen == NGHTTP2_ERR_DEFERRED || 77031cb0ef41Sopenharmony_ci payloadlen == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE || 77041cb0ef41Sopenharmony_ci payloadlen == NGHTTP2_ERR_PAUSE) { 77051cb0ef41Sopenharmony_ci DEBUGF("send: DATA postponed due to %s\n", 77061cb0ef41Sopenharmony_ci nghttp2_strerror((int)payloadlen)); 77071cb0ef41Sopenharmony_ci 77081cb0ef41Sopenharmony_ci return (int)payloadlen; 77091cb0ef41Sopenharmony_ci } 77101cb0ef41Sopenharmony_ci 77111cb0ef41Sopenharmony_ci if (payloadlen < 0 || datamax < (size_t)payloadlen) { 77121cb0ef41Sopenharmony_ci /* This is the error code when callback is failed. */ 77131cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 77141cb0ef41Sopenharmony_ci } 77151cb0ef41Sopenharmony_ci 77161cb0ef41Sopenharmony_ci buf->last = buf->pos + payloadlen; 77171cb0ef41Sopenharmony_ci buf->pos -= NGHTTP2_FRAME_HDLEN; 77181cb0ef41Sopenharmony_ci 77191cb0ef41Sopenharmony_ci /* Clear flags, because this may contain previous flags of previous 77201cb0ef41Sopenharmony_ci DATA */ 77211cb0ef41Sopenharmony_ci frame->hd.flags = NGHTTP2_FLAG_NONE; 77221cb0ef41Sopenharmony_ci 77231cb0ef41Sopenharmony_ci if (data_flags & NGHTTP2_DATA_FLAG_EOF) { 77241cb0ef41Sopenharmony_ci aux_data->eof = 1; 77251cb0ef41Sopenharmony_ci /* If NGHTTP2_DATA_FLAG_NO_END_STREAM is set, don't set 77261cb0ef41Sopenharmony_ci NGHTTP2_FLAG_END_STREAM */ 77271cb0ef41Sopenharmony_ci if ((aux_data->flags & NGHTTP2_FLAG_END_STREAM) && 77281cb0ef41Sopenharmony_ci (data_flags & NGHTTP2_DATA_FLAG_NO_END_STREAM) == 0) { 77291cb0ef41Sopenharmony_ci frame->hd.flags |= NGHTTP2_FLAG_END_STREAM; 77301cb0ef41Sopenharmony_ci } 77311cb0ef41Sopenharmony_ci } 77321cb0ef41Sopenharmony_ci 77331cb0ef41Sopenharmony_ci if (data_flags & NGHTTP2_DATA_FLAG_NO_COPY) { 77341cb0ef41Sopenharmony_ci if (session->callbacks.send_data_callback == NULL) { 77351cb0ef41Sopenharmony_ci DEBUGF("NGHTTP2_DATA_FLAG_NO_COPY requires send_data_callback set\n"); 77361cb0ef41Sopenharmony_ci 77371cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CALLBACK_FAILURE; 77381cb0ef41Sopenharmony_ci } 77391cb0ef41Sopenharmony_ci aux_data->no_copy = 1; 77401cb0ef41Sopenharmony_ci } 77411cb0ef41Sopenharmony_ci 77421cb0ef41Sopenharmony_ci frame->hd.length = (size_t)payloadlen; 77431cb0ef41Sopenharmony_ci frame->data.padlen = 0; 77441cb0ef41Sopenharmony_ci 77451cb0ef41Sopenharmony_ci max_payloadlen = nghttp2_min(datamax, frame->hd.length + NGHTTP2_MAX_PADLEN); 77461cb0ef41Sopenharmony_ci 77471cb0ef41Sopenharmony_ci padded_payloadlen = 77481cb0ef41Sopenharmony_ci session_call_select_padding(session, frame, max_payloadlen); 77491cb0ef41Sopenharmony_ci 77501cb0ef41Sopenharmony_ci if (nghttp2_is_fatal((int)padded_payloadlen)) { 77511cb0ef41Sopenharmony_ci return (int)padded_payloadlen; 77521cb0ef41Sopenharmony_ci } 77531cb0ef41Sopenharmony_ci 77541cb0ef41Sopenharmony_ci frame->data.padlen = (size_t)(padded_payloadlen - payloadlen); 77551cb0ef41Sopenharmony_ci 77561cb0ef41Sopenharmony_ci nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); 77571cb0ef41Sopenharmony_ci 77581cb0ef41Sopenharmony_ci nghttp2_frame_add_pad(bufs, &frame->hd, frame->data.padlen, 77591cb0ef41Sopenharmony_ci aux_data->no_copy); 77601cb0ef41Sopenharmony_ci 77611cb0ef41Sopenharmony_ci session_reschedule_stream(session, stream); 77621cb0ef41Sopenharmony_ci 77631cb0ef41Sopenharmony_ci if (frame->hd.length == 0 && (data_flags & NGHTTP2_DATA_FLAG_EOF) && 77641cb0ef41Sopenharmony_ci (data_flags & NGHTTP2_DATA_FLAG_NO_END_STREAM)) { 77651cb0ef41Sopenharmony_ci /* DATA payload length is 0, and DATA frame does not bear 77661cb0ef41Sopenharmony_ci END_STREAM. In this case, there is no point to send 0 length 77671cb0ef41Sopenharmony_ci DATA frame. */ 77681cb0ef41Sopenharmony_ci return NGHTTP2_ERR_CANCEL; 77691cb0ef41Sopenharmony_ci } 77701cb0ef41Sopenharmony_ci 77711cb0ef41Sopenharmony_ci return 0; 77721cb0ef41Sopenharmony_ci} 77731cb0ef41Sopenharmony_ci 77741cb0ef41Sopenharmony_civoid *nghttp2_session_get_stream_user_data(nghttp2_session *session, 77751cb0ef41Sopenharmony_ci int32_t stream_id) { 77761cb0ef41Sopenharmony_ci nghttp2_stream *stream; 77771cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 77781cb0ef41Sopenharmony_ci if (stream) { 77791cb0ef41Sopenharmony_ci return stream->stream_user_data; 77801cb0ef41Sopenharmony_ci } else { 77811cb0ef41Sopenharmony_ci return NULL; 77821cb0ef41Sopenharmony_ci } 77831cb0ef41Sopenharmony_ci} 77841cb0ef41Sopenharmony_ci 77851cb0ef41Sopenharmony_ciint nghttp2_session_set_stream_user_data(nghttp2_session *session, 77861cb0ef41Sopenharmony_ci int32_t stream_id, 77871cb0ef41Sopenharmony_ci void *stream_user_data) { 77881cb0ef41Sopenharmony_ci nghttp2_stream *stream; 77891cb0ef41Sopenharmony_ci nghttp2_frame *frame; 77901cb0ef41Sopenharmony_ci nghttp2_outbound_item *item; 77911cb0ef41Sopenharmony_ci 77921cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 77931cb0ef41Sopenharmony_ci if (stream) { 77941cb0ef41Sopenharmony_ci stream->stream_user_data = stream_user_data; 77951cb0ef41Sopenharmony_ci return 0; 77961cb0ef41Sopenharmony_ci } 77971cb0ef41Sopenharmony_ci 77981cb0ef41Sopenharmony_ci if (session->server || !nghttp2_session_is_my_stream_id(session, stream_id) || 77991cb0ef41Sopenharmony_ci !nghttp2_outbound_queue_top(&session->ob_syn)) { 78001cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 78011cb0ef41Sopenharmony_ci } 78021cb0ef41Sopenharmony_ci 78031cb0ef41Sopenharmony_ci frame = &nghttp2_outbound_queue_top(&session->ob_syn)->frame; 78041cb0ef41Sopenharmony_ci assert(frame->hd.type == NGHTTP2_HEADERS); 78051cb0ef41Sopenharmony_ci 78061cb0ef41Sopenharmony_ci if (frame->hd.stream_id > stream_id || 78071cb0ef41Sopenharmony_ci (uint32_t)stream_id >= session->next_stream_id) { 78081cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 78091cb0ef41Sopenharmony_ci } 78101cb0ef41Sopenharmony_ci 78111cb0ef41Sopenharmony_ci for (item = session->ob_syn.head; item; item = item->qnext) { 78121cb0ef41Sopenharmony_ci if (item->frame.hd.stream_id < stream_id) { 78131cb0ef41Sopenharmony_ci continue; 78141cb0ef41Sopenharmony_ci } 78151cb0ef41Sopenharmony_ci 78161cb0ef41Sopenharmony_ci if (item->frame.hd.stream_id > stream_id) { 78171cb0ef41Sopenharmony_ci break; 78181cb0ef41Sopenharmony_ci } 78191cb0ef41Sopenharmony_ci 78201cb0ef41Sopenharmony_ci item->aux_data.headers.stream_user_data = stream_user_data; 78211cb0ef41Sopenharmony_ci return 0; 78221cb0ef41Sopenharmony_ci } 78231cb0ef41Sopenharmony_ci 78241cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 78251cb0ef41Sopenharmony_ci} 78261cb0ef41Sopenharmony_ci 78271cb0ef41Sopenharmony_ciint nghttp2_session_resume_data(nghttp2_session *session, int32_t stream_id) { 78281cb0ef41Sopenharmony_ci int rv; 78291cb0ef41Sopenharmony_ci nghttp2_stream *stream; 78301cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 78311cb0ef41Sopenharmony_ci if (stream == NULL || !nghttp2_stream_check_deferred_item(stream)) { 78321cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 78331cb0ef41Sopenharmony_ci } 78341cb0ef41Sopenharmony_ci 78351cb0ef41Sopenharmony_ci rv = session_resume_deferred_stream_item(session, stream, 78361cb0ef41Sopenharmony_ci NGHTTP2_STREAM_FLAG_DEFERRED_USER); 78371cb0ef41Sopenharmony_ci 78381cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 78391cb0ef41Sopenharmony_ci return rv; 78401cb0ef41Sopenharmony_ci } 78411cb0ef41Sopenharmony_ci 78421cb0ef41Sopenharmony_ci return 0; 78431cb0ef41Sopenharmony_ci} 78441cb0ef41Sopenharmony_ci 78451cb0ef41Sopenharmony_cisize_t nghttp2_session_get_outbound_queue_size(nghttp2_session *session) { 78461cb0ef41Sopenharmony_ci return nghttp2_outbound_queue_size(&session->ob_urgent) + 78471cb0ef41Sopenharmony_ci nghttp2_outbound_queue_size(&session->ob_reg) + 78481cb0ef41Sopenharmony_ci nghttp2_outbound_queue_size(&session->ob_syn); 78491cb0ef41Sopenharmony_ci /* TODO account for item attached to stream */ 78501cb0ef41Sopenharmony_ci} 78511cb0ef41Sopenharmony_ci 78521cb0ef41Sopenharmony_ciint32_t 78531cb0ef41Sopenharmony_cinghttp2_session_get_stream_effective_recv_data_length(nghttp2_session *session, 78541cb0ef41Sopenharmony_ci int32_t stream_id) { 78551cb0ef41Sopenharmony_ci nghttp2_stream *stream; 78561cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 78571cb0ef41Sopenharmony_ci if (stream == NULL) { 78581cb0ef41Sopenharmony_ci return -1; 78591cb0ef41Sopenharmony_ci } 78601cb0ef41Sopenharmony_ci return stream->recv_window_size < 0 ? 0 : stream->recv_window_size; 78611cb0ef41Sopenharmony_ci} 78621cb0ef41Sopenharmony_ci 78631cb0ef41Sopenharmony_ciint32_t 78641cb0ef41Sopenharmony_cinghttp2_session_get_stream_effective_local_window_size(nghttp2_session *session, 78651cb0ef41Sopenharmony_ci int32_t stream_id) { 78661cb0ef41Sopenharmony_ci nghttp2_stream *stream; 78671cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 78681cb0ef41Sopenharmony_ci if (stream == NULL) { 78691cb0ef41Sopenharmony_ci return -1; 78701cb0ef41Sopenharmony_ci } 78711cb0ef41Sopenharmony_ci return stream->local_window_size; 78721cb0ef41Sopenharmony_ci} 78731cb0ef41Sopenharmony_ci 78741cb0ef41Sopenharmony_ciint32_t nghttp2_session_get_stream_local_window_size(nghttp2_session *session, 78751cb0ef41Sopenharmony_ci int32_t stream_id) { 78761cb0ef41Sopenharmony_ci nghttp2_stream *stream; 78771cb0ef41Sopenharmony_ci int32_t size; 78781cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 78791cb0ef41Sopenharmony_ci if (stream == NULL) { 78801cb0ef41Sopenharmony_ci return -1; 78811cb0ef41Sopenharmony_ci } 78821cb0ef41Sopenharmony_ci 78831cb0ef41Sopenharmony_ci size = stream->local_window_size - stream->recv_window_size; 78841cb0ef41Sopenharmony_ci 78851cb0ef41Sopenharmony_ci /* size could be negative if local endpoint reduced 78861cb0ef41Sopenharmony_ci SETTINGS_INITIAL_WINDOW_SIZE */ 78871cb0ef41Sopenharmony_ci if (size < 0) { 78881cb0ef41Sopenharmony_ci return 0; 78891cb0ef41Sopenharmony_ci } 78901cb0ef41Sopenharmony_ci 78911cb0ef41Sopenharmony_ci return size; 78921cb0ef41Sopenharmony_ci} 78931cb0ef41Sopenharmony_ci 78941cb0ef41Sopenharmony_ciint32_t 78951cb0ef41Sopenharmony_cinghttp2_session_get_effective_recv_data_length(nghttp2_session *session) { 78961cb0ef41Sopenharmony_ci return session->recv_window_size < 0 ? 0 : session->recv_window_size; 78971cb0ef41Sopenharmony_ci} 78981cb0ef41Sopenharmony_ci 78991cb0ef41Sopenharmony_ciint32_t 79001cb0ef41Sopenharmony_cinghttp2_session_get_effective_local_window_size(nghttp2_session *session) { 79011cb0ef41Sopenharmony_ci return session->local_window_size; 79021cb0ef41Sopenharmony_ci} 79031cb0ef41Sopenharmony_ci 79041cb0ef41Sopenharmony_ciint32_t nghttp2_session_get_local_window_size(nghttp2_session *session) { 79051cb0ef41Sopenharmony_ci return session->local_window_size - session->recv_window_size; 79061cb0ef41Sopenharmony_ci} 79071cb0ef41Sopenharmony_ci 79081cb0ef41Sopenharmony_ciint32_t nghttp2_session_get_stream_remote_window_size(nghttp2_session *session, 79091cb0ef41Sopenharmony_ci int32_t stream_id) { 79101cb0ef41Sopenharmony_ci nghttp2_stream *stream; 79111cb0ef41Sopenharmony_ci 79121cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 79131cb0ef41Sopenharmony_ci if (stream == NULL) { 79141cb0ef41Sopenharmony_ci return -1; 79151cb0ef41Sopenharmony_ci } 79161cb0ef41Sopenharmony_ci 79171cb0ef41Sopenharmony_ci /* stream->remote_window_size can be negative when 79181cb0ef41Sopenharmony_ci SETTINGS_INITIAL_WINDOW_SIZE is changed. */ 79191cb0ef41Sopenharmony_ci return nghttp2_max(0, stream->remote_window_size); 79201cb0ef41Sopenharmony_ci} 79211cb0ef41Sopenharmony_ci 79221cb0ef41Sopenharmony_ciint32_t nghttp2_session_get_remote_window_size(nghttp2_session *session) { 79231cb0ef41Sopenharmony_ci return session->remote_window_size; 79241cb0ef41Sopenharmony_ci} 79251cb0ef41Sopenharmony_ci 79261cb0ef41Sopenharmony_ciuint32_t nghttp2_session_get_remote_settings(nghttp2_session *session, 79271cb0ef41Sopenharmony_ci nghttp2_settings_id id) { 79281cb0ef41Sopenharmony_ci switch (id) { 79291cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: 79301cb0ef41Sopenharmony_ci return session->remote_settings.header_table_size; 79311cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_ENABLE_PUSH: 79321cb0ef41Sopenharmony_ci return session->remote_settings.enable_push; 79331cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: 79341cb0ef41Sopenharmony_ci return session->remote_settings.max_concurrent_streams; 79351cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: 79361cb0ef41Sopenharmony_ci return session->remote_settings.initial_window_size; 79371cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: 79381cb0ef41Sopenharmony_ci return session->remote_settings.max_frame_size; 79391cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: 79401cb0ef41Sopenharmony_ci return session->remote_settings.max_header_list_size; 79411cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: 79421cb0ef41Sopenharmony_ci return session->remote_settings.enable_connect_protocol; 79431cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES: 79441cb0ef41Sopenharmony_ci return session->remote_settings.no_rfc7540_priorities; 79451cb0ef41Sopenharmony_ci } 79461cb0ef41Sopenharmony_ci 79471cb0ef41Sopenharmony_ci assert(0); 79481cb0ef41Sopenharmony_ci abort(); /* if NDEBUG is set */ 79491cb0ef41Sopenharmony_ci} 79501cb0ef41Sopenharmony_ci 79511cb0ef41Sopenharmony_ciuint32_t nghttp2_session_get_local_settings(nghttp2_session *session, 79521cb0ef41Sopenharmony_ci nghttp2_settings_id id) { 79531cb0ef41Sopenharmony_ci switch (id) { 79541cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: 79551cb0ef41Sopenharmony_ci return session->local_settings.header_table_size; 79561cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_ENABLE_PUSH: 79571cb0ef41Sopenharmony_ci return session->local_settings.enable_push; 79581cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: 79591cb0ef41Sopenharmony_ci return session->local_settings.max_concurrent_streams; 79601cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: 79611cb0ef41Sopenharmony_ci return session->local_settings.initial_window_size; 79621cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: 79631cb0ef41Sopenharmony_ci return session->local_settings.max_frame_size; 79641cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: 79651cb0ef41Sopenharmony_ci return session->local_settings.max_header_list_size; 79661cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: 79671cb0ef41Sopenharmony_ci return session->local_settings.enable_connect_protocol; 79681cb0ef41Sopenharmony_ci case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES: 79691cb0ef41Sopenharmony_ci return session->local_settings.no_rfc7540_priorities; 79701cb0ef41Sopenharmony_ci } 79711cb0ef41Sopenharmony_ci 79721cb0ef41Sopenharmony_ci assert(0); 79731cb0ef41Sopenharmony_ci abort(); /* if NDEBUG is set */ 79741cb0ef41Sopenharmony_ci} 79751cb0ef41Sopenharmony_ci 79761cb0ef41Sopenharmony_cistatic int nghttp2_session_upgrade_internal(nghttp2_session *session, 79771cb0ef41Sopenharmony_ci const uint8_t *settings_payload, 79781cb0ef41Sopenharmony_ci size_t settings_payloadlen, 79791cb0ef41Sopenharmony_ci void *stream_user_data) { 79801cb0ef41Sopenharmony_ci nghttp2_stream *stream; 79811cb0ef41Sopenharmony_ci nghttp2_frame frame; 79821cb0ef41Sopenharmony_ci nghttp2_settings_entry *iv; 79831cb0ef41Sopenharmony_ci size_t niv; 79841cb0ef41Sopenharmony_ci int rv; 79851cb0ef41Sopenharmony_ci nghttp2_priority_spec pri_spec; 79861cb0ef41Sopenharmony_ci nghttp2_mem *mem; 79871cb0ef41Sopenharmony_ci 79881cb0ef41Sopenharmony_ci mem = &session->mem; 79891cb0ef41Sopenharmony_ci 79901cb0ef41Sopenharmony_ci if ((!session->server && session->next_stream_id != 1) || 79911cb0ef41Sopenharmony_ci (session->server && session->last_recv_stream_id >= 1)) { 79921cb0ef41Sopenharmony_ci return NGHTTP2_ERR_PROTO; 79931cb0ef41Sopenharmony_ci } 79941cb0ef41Sopenharmony_ci if (settings_payloadlen % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) { 79951cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 79961cb0ef41Sopenharmony_ci } 79971cb0ef41Sopenharmony_ci /* SETTINGS frame contains too many settings */ 79981cb0ef41Sopenharmony_ci if (settings_payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH > 79991cb0ef41Sopenharmony_ci session->max_settings) { 80001cb0ef41Sopenharmony_ci return NGHTTP2_ERR_TOO_MANY_SETTINGS; 80011cb0ef41Sopenharmony_ci } 80021cb0ef41Sopenharmony_ci rv = nghttp2_frame_unpack_settings_payload2(&iv, &niv, settings_payload, 80031cb0ef41Sopenharmony_ci settings_payloadlen, mem); 80041cb0ef41Sopenharmony_ci if (rv != 0) { 80051cb0ef41Sopenharmony_ci return rv; 80061cb0ef41Sopenharmony_ci } 80071cb0ef41Sopenharmony_ci 80081cb0ef41Sopenharmony_ci if (session->server) { 80091cb0ef41Sopenharmony_ci nghttp2_frame_hd_init(&frame.hd, settings_payloadlen, NGHTTP2_SETTINGS, 80101cb0ef41Sopenharmony_ci NGHTTP2_FLAG_NONE, 0); 80111cb0ef41Sopenharmony_ci frame.settings.iv = iv; 80121cb0ef41Sopenharmony_ci frame.settings.niv = niv; 80131cb0ef41Sopenharmony_ci rv = nghttp2_session_on_settings_received(session, &frame, 1 /* No ACK */); 80141cb0ef41Sopenharmony_ci } else { 80151cb0ef41Sopenharmony_ci rv = nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, niv); 80161cb0ef41Sopenharmony_ci } 80171cb0ef41Sopenharmony_ci nghttp2_mem_free(mem, iv); 80181cb0ef41Sopenharmony_ci if (rv != 0) { 80191cb0ef41Sopenharmony_ci return rv; 80201cb0ef41Sopenharmony_ci } 80211cb0ef41Sopenharmony_ci 80221cb0ef41Sopenharmony_ci nghttp2_priority_spec_default_init(&pri_spec); 80231cb0ef41Sopenharmony_ci 80241cb0ef41Sopenharmony_ci stream = nghttp2_session_open_stream( 80251cb0ef41Sopenharmony_ci session, 1, NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_OPENING, 80261cb0ef41Sopenharmony_ci session->server ? NULL : stream_user_data); 80271cb0ef41Sopenharmony_ci if (stream == NULL) { 80281cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 80291cb0ef41Sopenharmony_ci } 80301cb0ef41Sopenharmony_ci 80311cb0ef41Sopenharmony_ci /* We don't call nghttp2_session_adjust_closed_stream(), since this 80321cb0ef41Sopenharmony_ci should be the first stream open. */ 80331cb0ef41Sopenharmony_ci 80341cb0ef41Sopenharmony_ci if (session->server) { 80351cb0ef41Sopenharmony_ci nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); 80361cb0ef41Sopenharmony_ci session->last_recv_stream_id = 1; 80371cb0ef41Sopenharmony_ci session->last_proc_stream_id = 1; 80381cb0ef41Sopenharmony_ci } else { 80391cb0ef41Sopenharmony_ci nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); 80401cb0ef41Sopenharmony_ci session->last_sent_stream_id = 1; 80411cb0ef41Sopenharmony_ci session->next_stream_id += 2; 80421cb0ef41Sopenharmony_ci } 80431cb0ef41Sopenharmony_ci return 0; 80441cb0ef41Sopenharmony_ci} 80451cb0ef41Sopenharmony_ci 80461cb0ef41Sopenharmony_ciint nghttp2_session_upgrade(nghttp2_session *session, 80471cb0ef41Sopenharmony_ci const uint8_t *settings_payload, 80481cb0ef41Sopenharmony_ci size_t settings_payloadlen, 80491cb0ef41Sopenharmony_ci void *stream_user_data) { 80501cb0ef41Sopenharmony_ci int rv; 80511cb0ef41Sopenharmony_ci nghttp2_stream *stream; 80521cb0ef41Sopenharmony_ci 80531cb0ef41Sopenharmony_ci rv = nghttp2_session_upgrade_internal(session, settings_payload, 80541cb0ef41Sopenharmony_ci settings_payloadlen, stream_user_data); 80551cb0ef41Sopenharmony_ci if (rv != 0) { 80561cb0ef41Sopenharmony_ci return rv; 80571cb0ef41Sopenharmony_ci } 80581cb0ef41Sopenharmony_ci 80591cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, 1); 80601cb0ef41Sopenharmony_ci assert(stream); 80611cb0ef41Sopenharmony_ci 80621cb0ef41Sopenharmony_ci /* We have no information about request header fields when Upgrade 80631cb0ef41Sopenharmony_ci was happened. So we don't know the request method here. If 80641cb0ef41Sopenharmony_ci request method is HEAD, we have a trouble because we may have 80651cb0ef41Sopenharmony_ci nonzero content-length header field in response headers, and we 80661cb0ef41Sopenharmony_ci will going to check it against the actual DATA frames, but we may 80671cb0ef41Sopenharmony_ci get mismatch because HEAD response body must be empty. Because 80681cb0ef41Sopenharmony_ci of this reason, nghttp2_session_upgrade() was deprecated in favor 80691cb0ef41Sopenharmony_ci of nghttp2_session_upgrade2(), which has |head_request| parameter 80701cb0ef41Sopenharmony_ci to indicate that request method is HEAD or not. */ 80711cb0ef41Sopenharmony_ci stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND; 80721cb0ef41Sopenharmony_ci return 0; 80731cb0ef41Sopenharmony_ci} 80741cb0ef41Sopenharmony_ci 80751cb0ef41Sopenharmony_ciint nghttp2_session_upgrade2(nghttp2_session *session, 80761cb0ef41Sopenharmony_ci const uint8_t *settings_payload, 80771cb0ef41Sopenharmony_ci size_t settings_payloadlen, int head_request, 80781cb0ef41Sopenharmony_ci void *stream_user_data) { 80791cb0ef41Sopenharmony_ci int rv; 80801cb0ef41Sopenharmony_ci nghttp2_stream *stream; 80811cb0ef41Sopenharmony_ci 80821cb0ef41Sopenharmony_ci rv = nghttp2_session_upgrade_internal(session, settings_payload, 80831cb0ef41Sopenharmony_ci settings_payloadlen, stream_user_data); 80841cb0ef41Sopenharmony_ci if (rv != 0) { 80851cb0ef41Sopenharmony_ci return rv; 80861cb0ef41Sopenharmony_ci } 80871cb0ef41Sopenharmony_ci 80881cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, 1); 80891cb0ef41Sopenharmony_ci assert(stream); 80901cb0ef41Sopenharmony_ci 80911cb0ef41Sopenharmony_ci if (head_request) { 80921cb0ef41Sopenharmony_ci stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD; 80931cb0ef41Sopenharmony_ci } 80941cb0ef41Sopenharmony_ci 80951cb0ef41Sopenharmony_ci return 0; 80961cb0ef41Sopenharmony_ci} 80971cb0ef41Sopenharmony_ci 80981cb0ef41Sopenharmony_ciint nghttp2_session_get_stream_local_close(nghttp2_session *session, 80991cb0ef41Sopenharmony_ci int32_t stream_id) { 81001cb0ef41Sopenharmony_ci nghttp2_stream *stream; 81011cb0ef41Sopenharmony_ci 81021cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 81031cb0ef41Sopenharmony_ci 81041cb0ef41Sopenharmony_ci if (!stream) { 81051cb0ef41Sopenharmony_ci return -1; 81061cb0ef41Sopenharmony_ci } 81071cb0ef41Sopenharmony_ci 81081cb0ef41Sopenharmony_ci return (stream->shut_flags & NGHTTP2_SHUT_WR) != 0; 81091cb0ef41Sopenharmony_ci} 81101cb0ef41Sopenharmony_ci 81111cb0ef41Sopenharmony_ciint nghttp2_session_get_stream_remote_close(nghttp2_session *session, 81121cb0ef41Sopenharmony_ci int32_t stream_id) { 81131cb0ef41Sopenharmony_ci nghttp2_stream *stream; 81141cb0ef41Sopenharmony_ci 81151cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 81161cb0ef41Sopenharmony_ci 81171cb0ef41Sopenharmony_ci if (!stream) { 81181cb0ef41Sopenharmony_ci return -1; 81191cb0ef41Sopenharmony_ci } 81201cb0ef41Sopenharmony_ci 81211cb0ef41Sopenharmony_ci return (stream->shut_flags & NGHTTP2_SHUT_RD) != 0; 81221cb0ef41Sopenharmony_ci} 81231cb0ef41Sopenharmony_ci 81241cb0ef41Sopenharmony_ciint nghttp2_session_consume(nghttp2_session *session, int32_t stream_id, 81251cb0ef41Sopenharmony_ci size_t size) { 81261cb0ef41Sopenharmony_ci int rv; 81271cb0ef41Sopenharmony_ci nghttp2_stream *stream; 81281cb0ef41Sopenharmony_ci 81291cb0ef41Sopenharmony_ci if (stream_id == 0) { 81301cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 81311cb0ef41Sopenharmony_ci } 81321cb0ef41Sopenharmony_ci 81331cb0ef41Sopenharmony_ci if (!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) { 81341cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_STATE; 81351cb0ef41Sopenharmony_ci } 81361cb0ef41Sopenharmony_ci 81371cb0ef41Sopenharmony_ci rv = session_update_connection_consumed_size(session, size); 81381cb0ef41Sopenharmony_ci 81391cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 81401cb0ef41Sopenharmony_ci return rv; 81411cb0ef41Sopenharmony_ci } 81421cb0ef41Sopenharmony_ci 81431cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 81441cb0ef41Sopenharmony_ci 81451cb0ef41Sopenharmony_ci if (!stream) { 81461cb0ef41Sopenharmony_ci return 0; 81471cb0ef41Sopenharmony_ci } 81481cb0ef41Sopenharmony_ci 81491cb0ef41Sopenharmony_ci rv = session_update_stream_consumed_size(session, stream, size); 81501cb0ef41Sopenharmony_ci 81511cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 81521cb0ef41Sopenharmony_ci return rv; 81531cb0ef41Sopenharmony_ci } 81541cb0ef41Sopenharmony_ci 81551cb0ef41Sopenharmony_ci return 0; 81561cb0ef41Sopenharmony_ci} 81571cb0ef41Sopenharmony_ci 81581cb0ef41Sopenharmony_ciint nghttp2_session_consume_connection(nghttp2_session *session, size_t size) { 81591cb0ef41Sopenharmony_ci int rv; 81601cb0ef41Sopenharmony_ci 81611cb0ef41Sopenharmony_ci if (!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) { 81621cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_STATE; 81631cb0ef41Sopenharmony_ci } 81641cb0ef41Sopenharmony_ci 81651cb0ef41Sopenharmony_ci rv = session_update_connection_consumed_size(session, size); 81661cb0ef41Sopenharmony_ci 81671cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 81681cb0ef41Sopenharmony_ci return rv; 81691cb0ef41Sopenharmony_ci } 81701cb0ef41Sopenharmony_ci 81711cb0ef41Sopenharmony_ci return 0; 81721cb0ef41Sopenharmony_ci} 81731cb0ef41Sopenharmony_ci 81741cb0ef41Sopenharmony_ciint nghttp2_session_consume_stream(nghttp2_session *session, int32_t stream_id, 81751cb0ef41Sopenharmony_ci size_t size) { 81761cb0ef41Sopenharmony_ci int rv; 81771cb0ef41Sopenharmony_ci nghttp2_stream *stream; 81781cb0ef41Sopenharmony_ci 81791cb0ef41Sopenharmony_ci if (stream_id == 0) { 81801cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 81811cb0ef41Sopenharmony_ci } 81821cb0ef41Sopenharmony_ci 81831cb0ef41Sopenharmony_ci if (!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) { 81841cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_STATE; 81851cb0ef41Sopenharmony_ci } 81861cb0ef41Sopenharmony_ci 81871cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream(session, stream_id); 81881cb0ef41Sopenharmony_ci 81891cb0ef41Sopenharmony_ci if (!stream) { 81901cb0ef41Sopenharmony_ci return 0; 81911cb0ef41Sopenharmony_ci } 81921cb0ef41Sopenharmony_ci 81931cb0ef41Sopenharmony_ci rv = session_update_stream_consumed_size(session, stream, size); 81941cb0ef41Sopenharmony_ci 81951cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 81961cb0ef41Sopenharmony_ci return rv; 81971cb0ef41Sopenharmony_ci } 81981cb0ef41Sopenharmony_ci 81991cb0ef41Sopenharmony_ci return 0; 82001cb0ef41Sopenharmony_ci} 82011cb0ef41Sopenharmony_ci 82021cb0ef41Sopenharmony_ciint nghttp2_session_set_next_stream_id(nghttp2_session *session, 82031cb0ef41Sopenharmony_ci int32_t next_stream_id) { 82041cb0ef41Sopenharmony_ci if (next_stream_id <= 0 || 82051cb0ef41Sopenharmony_ci session->next_stream_id > (uint32_t)next_stream_id) { 82061cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 82071cb0ef41Sopenharmony_ci } 82081cb0ef41Sopenharmony_ci 82091cb0ef41Sopenharmony_ci if (session->server) { 82101cb0ef41Sopenharmony_ci if (next_stream_id % 2) { 82111cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 82121cb0ef41Sopenharmony_ci } 82131cb0ef41Sopenharmony_ci } else if (next_stream_id % 2 == 0) { 82141cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 82151cb0ef41Sopenharmony_ci } 82161cb0ef41Sopenharmony_ci 82171cb0ef41Sopenharmony_ci session->next_stream_id = (uint32_t)next_stream_id; 82181cb0ef41Sopenharmony_ci return 0; 82191cb0ef41Sopenharmony_ci} 82201cb0ef41Sopenharmony_ci 82211cb0ef41Sopenharmony_ciuint32_t nghttp2_session_get_next_stream_id(nghttp2_session *session) { 82221cb0ef41Sopenharmony_ci return session->next_stream_id; 82231cb0ef41Sopenharmony_ci} 82241cb0ef41Sopenharmony_ci 82251cb0ef41Sopenharmony_ciint32_t nghttp2_session_get_last_proc_stream_id(nghttp2_session *session) { 82261cb0ef41Sopenharmony_ci return session->last_proc_stream_id; 82271cb0ef41Sopenharmony_ci} 82281cb0ef41Sopenharmony_ci 82291cb0ef41Sopenharmony_cinghttp2_stream *nghttp2_session_find_stream(nghttp2_session *session, 82301cb0ef41Sopenharmony_ci int32_t stream_id) { 82311cb0ef41Sopenharmony_ci if (stream_id == 0) { 82321cb0ef41Sopenharmony_ci return &session->root; 82331cb0ef41Sopenharmony_ci } 82341cb0ef41Sopenharmony_ci 82351cb0ef41Sopenharmony_ci return nghttp2_session_get_stream_raw(session, stream_id); 82361cb0ef41Sopenharmony_ci} 82371cb0ef41Sopenharmony_ci 82381cb0ef41Sopenharmony_cinghttp2_stream *nghttp2_session_get_root_stream(nghttp2_session *session) { 82391cb0ef41Sopenharmony_ci return &session->root; 82401cb0ef41Sopenharmony_ci} 82411cb0ef41Sopenharmony_ci 82421cb0ef41Sopenharmony_ciint nghttp2_session_check_server_session(nghttp2_session *session) { 82431cb0ef41Sopenharmony_ci return session->server; 82441cb0ef41Sopenharmony_ci} 82451cb0ef41Sopenharmony_ci 82461cb0ef41Sopenharmony_ciint nghttp2_session_change_stream_priority( 82471cb0ef41Sopenharmony_ci nghttp2_session *session, int32_t stream_id, 82481cb0ef41Sopenharmony_ci const nghttp2_priority_spec *pri_spec) { 82491cb0ef41Sopenharmony_ci int rv; 82501cb0ef41Sopenharmony_ci nghttp2_stream *stream; 82511cb0ef41Sopenharmony_ci nghttp2_priority_spec pri_spec_copy; 82521cb0ef41Sopenharmony_ci 82531cb0ef41Sopenharmony_ci if (session->pending_no_rfc7540_priorities == 1) { 82541cb0ef41Sopenharmony_ci return 0; 82551cb0ef41Sopenharmony_ci } 82561cb0ef41Sopenharmony_ci 82571cb0ef41Sopenharmony_ci if (stream_id == 0 || stream_id == pri_spec->stream_id) { 82581cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 82591cb0ef41Sopenharmony_ci } 82601cb0ef41Sopenharmony_ci 82611cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream_raw(session, stream_id); 82621cb0ef41Sopenharmony_ci if (!stream) { 82631cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 82641cb0ef41Sopenharmony_ci } 82651cb0ef41Sopenharmony_ci 82661cb0ef41Sopenharmony_ci pri_spec_copy = *pri_spec; 82671cb0ef41Sopenharmony_ci nghttp2_priority_spec_normalize_weight(&pri_spec_copy); 82681cb0ef41Sopenharmony_ci 82691cb0ef41Sopenharmony_ci rv = nghttp2_session_reprioritize_stream(session, stream, &pri_spec_copy); 82701cb0ef41Sopenharmony_ci 82711cb0ef41Sopenharmony_ci if (nghttp2_is_fatal(rv)) { 82721cb0ef41Sopenharmony_ci return rv; 82731cb0ef41Sopenharmony_ci } 82741cb0ef41Sopenharmony_ci 82751cb0ef41Sopenharmony_ci /* We don't intentionally call nghttp2_session_adjust_idle_stream() 82761cb0ef41Sopenharmony_ci so that idle stream created by this function, and existing ones 82771cb0ef41Sopenharmony_ci are kept for application. We will adjust number of idle stream 82781cb0ef41Sopenharmony_ci in nghttp2_session_mem_send or nghttp2_session_mem_recv is 82791cb0ef41Sopenharmony_ci called. */ 82801cb0ef41Sopenharmony_ci return 0; 82811cb0ef41Sopenharmony_ci} 82821cb0ef41Sopenharmony_ci 82831cb0ef41Sopenharmony_ciint nghttp2_session_create_idle_stream(nghttp2_session *session, 82841cb0ef41Sopenharmony_ci int32_t stream_id, 82851cb0ef41Sopenharmony_ci const nghttp2_priority_spec *pri_spec) { 82861cb0ef41Sopenharmony_ci nghttp2_stream *stream; 82871cb0ef41Sopenharmony_ci nghttp2_priority_spec pri_spec_copy; 82881cb0ef41Sopenharmony_ci 82891cb0ef41Sopenharmony_ci if (session->pending_no_rfc7540_priorities == 1) { 82901cb0ef41Sopenharmony_ci return 0; 82911cb0ef41Sopenharmony_ci } 82921cb0ef41Sopenharmony_ci 82931cb0ef41Sopenharmony_ci if (stream_id == 0 || stream_id == pri_spec->stream_id || 82941cb0ef41Sopenharmony_ci !session_detect_idle_stream(session, stream_id)) { 82951cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 82961cb0ef41Sopenharmony_ci } 82971cb0ef41Sopenharmony_ci 82981cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream_raw(session, stream_id); 82991cb0ef41Sopenharmony_ci if (stream) { 83001cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 83011cb0ef41Sopenharmony_ci } 83021cb0ef41Sopenharmony_ci 83031cb0ef41Sopenharmony_ci pri_spec_copy = *pri_spec; 83041cb0ef41Sopenharmony_ci nghttp2_priority_spec_normalize_weight(&pri_spec_copy); 83051cb0ef41Sopenharmony_ci 83061cb0ef41Sopenharmony_ci stream = 83071cb0ef41Sopenharmony_ci nghttp2_session_open_stream(session, stream_id, NGHTTP2_STREAM_FLAG_NONE, 83081cb0ef41Sopenharmony_ci &pri_spec_copy, NGHTTP2_STREAM_IDLE, NULL); 83091cb0ef41Sopenharmony_ci if (!stream) { 83101cb0ef41Sopenharmony_ci return NGHTTP2_ERR_NOMEM; 83111cb0ef41Sopenharmony_ci } 83121cb0ef41Sopenharmony_ci 83131cb0ef41Sopenharmony_ci /* We don't intentionally call nghttp2_session_adjust_idle_stream() 83141cb0ef41Sopenharmony_ci so that idle stream created by this function, and existing ones 83151cb0ef41Sopenharmony_ci are kept for application. We will adjust number of idle stream 83161cb0ef41Sopenharmony_ci in nghttp2_session_mem_send or nghttp2_session_mem_recv is 83171cb0ef41Sopenharmony_ci called. */ 83181cb0ef41Sopenharmony_ci return 0; 83191cb0ef41Sopenharmony_ci} 83201cb0ef41Sopenharmony_ci 83211cb0ef41Sopenharmony_cisize_t 83221cb0ef41Sopenharmony_cinghttp2_session_get_hd_inflate_dynamic_table_size(nghttp2_session *session) { 83231cb0ef41Sopenharmony_ci return nghttp2_hd_inflate_get_dynamic_table_size(&session->hd_inflater); 83241cb0ef41Sopenharmony_ci} 83251cb0ef41Sopenharmony_ci 83261cb0ef41Sopenharmony_cisize_t 83271cb0ef41Sopenharmony_cinghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session) { 83281cb0ef41Sopenharmony_ci return nghttp2_hd_deflate_get_dynamic_table_size(&session->hd_deflater); 83291cb0ef41Sopenharmony_ci} 83301cb0ef41Sopenharmony_ci 83311cb0ef41Sopenharmony_civoid nghttp2_session_set_user_data(nghttp2_session *session, void *user_data) { 83321cb0ef41Sopenharmony_ci session->user_data = user_data; 83331cb0ef41Sopenharmony_ci} 83341cb0ef41Sopenharmony_ci 83351cb0ef41Sopenharmony_ciint nghttp2_session_change_extpri_stream_priority( 83361cb0ef41Sopenharmony_ci nghttp2_session *session, int32_t stream_id, 83371cb0ef41Sopenharmony_ci const nghttp2_extpri *extpri_in, int ignore_client_signal) { 83381cb0ef41Sopenharmony_ci nghttp2_stream *stream; 83391cb0ef41Sopenharmony_ci nghttp2_extpri extpri = *extpri_in; 83401cb0ef41Sopenharmony_ci 83411cb0ef41Sopenharmony_ci if (!session->server) { 83421cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_STATE; 83431cb0ef41Sopenharmony_ci } 83441cb0ef41Sopenharmony_ci 83451cb0ef41Sopenharmony_ci if (session->pending_no_rfc7540_priorities != 1) { 83461cb0ef41Sopenharmony_ci return 0; 83471cb0ef41Sopenharmony_ci } 83481cb0ef41Sopenharmony_ci 83491cb0ef41Sopenharmony_ci if (stream_id == 0) { 83501cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 83511cb0ef41Sopenharmony_ci } 83521cb0ef41Sopenharmony_ci 83531cb0ef41Sopenharmony_ci stream = nghttp2_session_get_stream_raw(session, stream_id); 83541cb0ef41Sopenharmony_ci if (!stream) { 83551cb0ef41Sopenharmony_ci return NGHTTP2_ERR_INVALID_ARGUMENT; 83561cb0ef41Sopenharmony_ci } 83571cb0ef41Sopenharmony_ci 83581cb0ef41Sopenharmony_ci if (extpri.urgency > NGHTTP2_EXTPRI_URGENCY_LOW) { 83591cb0ef41Sopenharmony_ci extpri.urgency = NGHTTP2_EXTPRI_URGENCY_LOW; 83601cb0ef41Sopenharmony_ci } 83611cb0ef41Sopenharmony_ci 83621cb0ef41Sopenharmony_ci if (ignore_client_signal) { 83631cb0ef41Sopenharmony_ci stream->flags |= NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES; 83641cb0ef41Sopenharmony_ci } 83651cb0ef41Sopenharmony_ci 83661cb0ef41Sopenharmony_ci return session_update_stream_priority(session, stream, 83671cb0ef41Sopenharmony_ci nghttp2_extpri_to_uint8(&extpri)); 83681cb0ef41Sopenharmony_ci} 8369