h2_proc_out.c (8460B)
1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */ 2 /* 3 This file is part of GNU libmicrohttpd. 4 Copyright (C) 2025 Evgeny Grin (Karlson2k) 5 6 GNU libmicrohttpd is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 GNU libmicrohttpd is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 Alternatively, you can redistribute GNU libmicrohttpd and/or 17 modify it under the terms of the GNU General Public License as 18 published by the Free Software Foundation; either version 2 of 19 the License, or (at your option) any later version, together 20 with the eCos exception, as follows: 21 22 As a special exception, if other files instantiate templates or 23 use macros or inline functions from this file, or you compile this 24 file and link it with other works to produce a work based on this 25 file, this file does not by itself cause the resulting work to be 26 covered by the GNU General Public License. However the source code 27 for this file must still be made available in accordance with 28 section (3) of the GNU General Public License v2. 29 30 This exception does not invalidate any other reasons why a work 31 based on this file might be covered by the GNU General Public 32 License. 33 34 You should have received copies of the GNU Lesser General Public 35 License and the GNU General Public License along with this library; 36 if not, see <https://www.gnu.org/licenses/>. 37 */ 38 39 /** 40 * @file src/mhd2/h2/h2_proc_out.c 41 * @brief Implementation of HTTP/2 connection outgoing data processing functions 42 * @author Karlson2k (Evgeny Grin) 43 */ 44 45 #include "mhd_sys_options.h" 46 47 #include "sys_bool_type.h" 48 #include "sys_base_types.h" 49 50 #include "mhd_assert.h" 51 52 #include "mhd_connection.h" 53 54 #include "h2_err_codes.h" 55 #include "h2_frame_types.h" 56 #include "h2_frame_init.h" 57 #include "h2_frame_codec.h" 58 59 #include "h2_proc_in.h" 60 61 #include "h2_proc_out.h" 62 63 64 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 65 mhd_h2_out_buff_has_space_sz (struct MHD_Connection *restrict c, 66 size_t space_needed) 67 { 68 size_t have_buff_space; 69 mhd_assert (c->write_buffer_size >= c->write_buffer_append_offset); 70 71 mhd_assert (! c->h2.dbg.w_buff_updating); 72 mhd_H2_W_BUFF_UPDATING_SET (&(c->h2)); 73 74 have_buff_space = c->write_buffer_size - c->write_buffer_append_offset; 75 76 mhd_H2_W_BUFF_UPDATING_CLEAR (&(c->h2)); 77 78 return (space_needed <= have_buff_space); 79 } 80 81 82 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 83 mhd_h2_out_buff_has_space_fr (struct MHD_Connection *restrict c, 84 union mhd_H2FrameUnion *restrict h2frame) 85 { 86 return mhd_h2_out_buff_has_space_sz (c, 87 mhd_h2_frame_get_total_size (h2frame)); 88 } 89 90 91 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 92 mhd_h2_out_buff_acquire_fr_w_payload_l ( 93 struct MHD_Connection *restrict c, 94 const union mhd_H2FrameUnion *restrict h2frame, 95 uint_least32_t full_payload_limit, 96 struct mhd_Buffer *restrict buff, 97 size_t *restrict payload_offset) 98 { 99 const size_t extra_hdr_size = mhd_h2_frame_get_extra_hdr_size (h2frame); 100 const size_t padding_size = mhd_h2_frame_get_padding_size (h2frame); 101 size_t w_buff_space; 102 103 mhd_assert (! c->h2.dbg.w_buff_updating); 104 mhd_H2_W_BUFF_UPDATING_SET (&(c->h2)); 105 mhd_assert (c->write_buffer_size >= c->write_buffer_append_offset); 106 107 if (full_payload_limit > c->h2.peer.max_frame_size) 108 full_payload_limit = (uint_least32_t) c->h2.peer.max_frame_size; 109 110 w_buff_space = c->write_buffer_size - c->write_buffer_append_offset; 111 if (((mhd_H2_FR_HDR_BASE_SIZE + extra_hdr_size + padding_size) 112 >= w_buff_space) || 113 ((extra_hdr_size + padding_size) >= full_payload_limit)) 114 { 115 mhd_H2_W_BUFF_UPDATING_CLEAR (&(c->h2)); 116 return false; 117 } 118 119 mhd_assert (c->h2.peer.max_frame_size > mhd_H2_FR_HDR_BASE_SIZE); 120 121 if (full_payload_limit < (w_buff_space - mhd_H2_FR_HDR_BASE_SIZE)) 122 w_buff_space = full_payload_limit + mhd_H2_FR_HDR_BASE_SIZE; 123 124 buff->data = c->write_buffer + c->write_buffer_append_offset; 125 buff->size = w_buff_space - padding_size; 126 *payload_offset = mhd_H2_FR_HDR_BASE_SIZE + extra_hdr_size; 127 128 return true; 129 } 130 131 132 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 133 mhd_h2_out_buff_acquire_fr_w_payload ( 134 struct MHD_Connection *restrict c, 135 const union mhd_H2FrameUnion *restrict h2frame, 136 struct mhd_Buffer *restrict buff, 137 size_t *restrict payload_offset) 138 { 139 return 140 mhd_h2_out_buff_acquire_fr_w_payload_l (c, 141 h2frame, 142 0xFFFFFFFFu, 143 buff, 144 payload_offset); 145 } 146 147 148 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 149 mhd_h2_out_buff_unlock (struct MHD_Connection *restrict c, 150 size_t size_used) 151 { 152 mhd_assert (c->h2.dbg.w_buff_updating); 153 mhd_assert (c->write_buffer_size >= size_used); 154 mhd_assert ((c->write_buffer_size - size_used) 155 >= c->write_buffer_append_offset); 156 157 c->write_buffer_append_offset += size_used; 158 mhd_H2_W_BUFF_UPDATING_CLEAR (&(c->h2)); 159 } 160 161 162 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 163 mhd_h2_q_frame_no_payload (struct MHD_Connection *restrict c, 164 union mhd_H2FrameUnion *restrict h2frame) 165 { 166 size_t fr_hdr_size; 167 size_t w_buff_space; 168 bool succeed; 169 170 mhd_assert (mhd_h2_frame_get_extra_hdr_size (h2frame) == 171 h2frame->selector.length); 172 173 fr_hdr_size = mhd_H2_FR_HDR_BASE_SIZE 174 + mhd_h2_frame_get_extra_hdr_size (h2frame); 175 176 mhd_assert (! c->h2.dbg.w_buff_updating); 177 mhd_H2_W_BUFF_UPDATING_SET (&(c->h2)); 178 179 succeed = false; 180 w_buff_space = c->write_buffer_size - c->write_buffer_append_offset; 181 if (fr_hdr_size <= w_buff_space) 182 { 183 uint8_t *w_buff; 184 size_t written; 185 w_buff = (uint8_t *) c->write_buffer + c->write_buffer_append_offset; 186 187 written = mhd_h2_frame_hdr_encode (h2frame, 188 w_buff_space, 189 w_buff); 190 mhd_assert (fr_hdr_size == written); 191 c->write_buffer_append_offset += written; 192 193 succeed = true; 194 } 195 196 mhd_H2_W_BUFF_UPDATING_CLEAR (&(c->h2)); 197 return succeed; 198 } 199 200 201 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 202 mhd_h2_q_rst_stream (struct MHD_Connection *restrict c, 203 uint_least32_t stream_id, 204 enum mhd_H2ErrorCode err) 205 { 206 union mhd_H2FrameUnion h2frame; 207 208 mhd_assert (0u != stream_id); 209 if (c->h2.state.top_rst_stream_id < stream_id) 210 c->h2.state.top_rst_stream_id = stream_id; 211 212 mhd_h2_frame_init_rst_stream (&h2frame, 213 stream_id, 214 err); 215 216 return mhd_h2_q_frame_no_payload (c, 217 &h2frame); 218 } 219 220 221 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 222 mhd_h2_q_ping (struct MHD_Connection *restrict c, 223 bool ack, 224 const uint8_t opaque_data[MHD_FN_PAR_FIX_ARR_SIZE_ (8)]) 225 { 226 union mhd_H2FrameUnion h2frame; 227 228 mhd_h2_frame_init_ping (&h2frame, 229 ack, 230 opaque_data); 231 232 return mhd_h2_q_frame_no_payload (c, 233 &h2frame); 234 } 235 236 237 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 238 mhd_h2_q_goaway (struct MHD_Connection *restrict c, 239 enum mhd_H2ErrorCode err) 240 { 241 union mhd_H2FrameUnion h2frame; 242 243 mhd_h2_frame_init_goaway (&h2frame, 244 c->h2.state.top_proc_stream_id, 245 err); 246 247 return mhd_h2_q_frame_no_payload (c, 248 &h2frame); 249 } 250 251 252 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 253 mhd_h2_q_window_update (struct MHD_Connection *restrict c, 254 uint_least32_t stream_id, 255 uint_least32_t win_size_incr) 256 { 257 union mhd_H2FrameUnion h2frame; 258 259 mhd_assert (0u != win_size_incr); 260 261 mhd_h2_frame_init_window_update (&h2frame, 262 stream_id, 263 win_size_incr); 264 265 return mhd_h2_q_frame_no_payload (c, 266 &h2frame); 267 }