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