h2_proc_in.c (10011B)
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_in.c 41 * @brief Implementation of HTTP/2 connection incoming 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 #include "mhd_unreachable.h" 52 53 #include "mhd_buffer.h" 54 #include "mhd_connection.h" 55 56 #include <string.h> 57 58 #include "h2_frame_types.h" 59 #include "h2_frame_codec.h" 60 61 #include "h2_conn_streams.h" 62 #include "h2_proc_settings.h" 63 #include "h2_proc_out.h" 64 #include "h2_proc_conn.h" 65 66 #include "h2_proc_in.h" 67 68 69 enum mhd_H2ProcInFrameResult 70 { 71 mhd_H2_PROC_IN_FRAME_CONTINUE = mhd_H2_STNGS_PROC_OK, 72 mhd_H2_PROC_IN_FRAME_BLOCKED_BY_OUT = mhd_H2_STNGS_PROC_NO_OUT_BUFF, 73 mhd_H2_PROC_IN_FRAME_CONN_BROKEN = mhd_H2_STNGS_PROC_STNGS_ERR 74 }; 75 76 /** 77 * Process incoming frame 78 * @param c the connection to use 79 * @param h2frame the frame information 80 * @param payload the frame payload (excluding known extra headers) 81 * @return 'true' if frame was successfully and completely processed, 82 * 'false' if frame should be processed again later or if connection 83 * if in closing or broken state (and no incoming frames should be 84 * processed anymore) 85 */ 86 static MHD_FN_PAR_NONNULL_ALL_ bool 87 process_inc_frame (struct MHD_Connection *restrict c, 88 const union mhd_H2FrameUnion *h2frame, 89 struct mhd_Buffer *payload) 90 { 91 if (0u != c->h2.state.continuation_stream_id) 92 { 93 if ((mhd_H2_FRAME_IDS_CONTINUATION_ID != h2frame->selector.type) 94 || (c->h2.state.continuation_stream_id != 95 h2frame->continuation.stream_id)) 96 return ! mhd_h2_conn_finish (c, 97 mhd_H2_ERR_PROTOCOL_ERROR, 98 false); 99 } 100 else 101 mhd_assert (0u == c->h2.buff.unproc_hdrs_size); 102 103 switch (h2frame->selector.type) 104 { 105 case mhd_H2_FRAME_IDS_DATA_ID: 106 mhd_assert (0); 107 return mhd_h2_conn_finish (c, 108 mhd_H2_ERR_PROTOCOL_ERROR, 109 false); 110 case mhd_H2_FRAME_IDS_HEADERS_ID: 111 return mhd_h2_conn_streamid_in_headers (c, 112 h2frame->headers.stream_id, 113 h2frame->headers.end_stream, 114 h2frame->headers.end_headers, 115 payload); 116 case mhd_H2_FRAME_IDS_RST_STREAM_ID: 117 return mhd_h2_conn_streamid_in_rst_stream (c, 118 h2frame->rst_stream.stream_id, 119 h2frame->rst_stream.error_code); 120 return mhd_H2_PROC_IN_FRAME_CONTINUE; 121 case mhd_H2_FRAME_IDS_SETTINGS_ID: 122 return (mhd_H2_STNGS_PROC_OK == mhd_h2_proc_new_settings (c, 123 payload)); 124 case mhd_H2_FRAME_IDS_PUSH_PROMISE_ID: 125 return ! mhd_h2_conn_finish (c, 126 mhd_H2_ERR_PROTOCOL_ERROR, 127 false); 128 case mhd_H2_FRAME_IDS_PING_ID: 129 return mhd_h2_q_ping (c, 130 true, 131 h2frame->ping.opaque_data); 132 case mhd_H2_FRAME_IDS_GOAWAY_ID: 133 return mhd_h2_conn_process_in_goaway (c, 134 h2frame->goaway.last_stream_id, 135 h2frame->goaway.error_code); 136 case mhd_H2_FRAME_IDS_WINDOW_UPDATE_ID: 137 if (0u != h2frame->window_update.stream_id) 138 { 139 return 140 mhd_h2_conn_streamid_window_incr ( 141 c, 142 h2frame->window_update.stream_id, 143 h2frame->window_update.window_size_increment); 144 } 145 if ((h2frame->window_update.window_size_increment 146 + (uint_least32_t) c->h2.state.send_window) > 0x7FFFFFFFu) 147 return ! mhd_h2_conn_finish (c, 148 mhd_H2_ERR_FLOW_CONTROL_ERROR, 149 false); 150 c->h2.state.send_window += 151 (int_least32_t) h2frame->window_update.window_size_increment; 152 return true; 153 case mhd_H2_FRAME_IDS_CONTINUATION_ID: 154 return 155 mhd_h2_conn_streamid_in_continuation (c, 156 h2frame->continuation.stream_id, 157 h2frame->continuation.end_headers, 158 payload); 159 case mhd_H2_FRAME_IDS_PRIORITY_ID: 160 default: 161 break; /* Ignored */ 162 } 163 /* Ignored types of frame */ 164 return true; 165 } 166 167 168 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool 169 mhd_h2_conn_process_in_data (struct MHD_Connection *restrict c) 170 { 171 mhd_assert (mhd_HTTP_LAYER_CONNECTED == c->h_layer.state); 172 173 mhd_assert (c->read_buffer_size >= c->read_buffer_offset); 174 mhd_assert (c->read_buffer_offset >= c->h2.buff.r_cur_frame); 175 176 if (c->h2.buff.r_cur_frame == c->read_buffer_offset) 177 return true; /* Shortcut, nothing to process */ 178 179 do 180 { 181 union mhd_H2FrameUnion h2frame; 182 enum mhd_H2FrameDecodeResult dec_res; 183 struct mhd_Buffer payload; 184 bool proc_next; 185 uint8_t *const frame_buff = 186 (uint8_t *) c->read_buffer + c->h2.buff.r_cur_frame; 187 const size_t buff_left = c->read_buffer_offset - c->h2.buff.r_cur_frame; 188 189 proc_next = true; 190 dec_res = mhd_h2_frame_decode (buff_left, 191 frame_buff, 192 c->h2.rcv_cfg.max_frame_size, 193 &h2frame, 194 &payload); 195 switch (dec_res) 196 { 197 case mhd_H2_F_DEC_OK: 198 proc_next = process_inc_frame (c, 199 &h2frame, 200 &payload); 201 proc_next = (proc_next && (mhd_HTTP_LAYER_CONNECTED == c->h_layer.state)); 202 if (c->h2.state.top_seen_stream_id < h2frame.selector.stream_id) 203 c->h2.state.top_seen_stream_id = h2frame.selector.stream_id; 204 break; 205 case mhd_H2_F_DEC_F_PAYLOAD_INCOMPLETE: 206 case mhd_H2_F_DEC_F_HEADER_INCOMPLETE: 207 proc_next = false; 208 break; 209 case mhd_H2_F_DEC_STREAM_ERR_F_SIZE: 210 case mhd_H2_F_DEC_STREAM_ERR_PROT: 211 if (mhd_h2_frame_get_total_size (&h2frame) > buff_left) 212 { 213 /* The frame is not yet complete */ 214 proc_next = false; 215 break; 216 } 217 proc_next = 218 mhd_h2_conn_streamid_abort ( 219 c, 220 h2frame.selector.stream_id, 221 (mhd_H2_F_DEC_STREAM_ERR_F_SIZE == dec_res) ? 222 mhd_H2_ERR_FRAME_SIZE_ERROR : mhd_H2_ERR_PROTOCOL_ERROR); 223 if (c->h2.state.top_seen_stream_id < h2frame.selector.stream_id) 224 c->h2.state.top_seen_stream_id = h2frame.selector.stream_id; 225 break; 226 case mhd_H2_F_DEC_CONN_ERR_F_SIZE: 227 mhd_h2_conn_finish (c, 228 mhd_H2_ERR_FRAME_SIZE_ERROR, 229 false); 230 return false; 231 case mhd_H2_F_DEC_CONN_ERR_PROT: 232 mhd_h2_conn_finish (c, 233 mhd_H2_ERR_PROTOCOL_ERROR, 234 false); 235 return false; 236 break; 237 default: 238 break; /* ignore unknown types */ 239 } 240 241 if (! proc_next) 242 break; 243 244 mhd_assert (mhd_HTTP_LAYER_CONNECTED == c->h_layer.state); 245 246 mhd_assert ((c->read_buffer_offset - c->h2.buff.r_cur_frame) >= 247 mhd_h2_frame_get_total_size (&h2frame)); 248 249 c->h2.buff.r_cur_frame += mhd_h2_frame_get_total_size (&h2frame); 250 } while (c->h2.buff.r_cur_frame < c->read_buffer_offset); 251 252 mhd_assert (c->read_buffer_offset >= c->h2.buff.r_cur_frame); 253 if (mhd_HTTP_LAYER_CONNECTED == c->h_layer.state) 254 { 255 const size_t data_left = c->read_buffer_offset - c->h2.buff.r_cur_frame; 256 257 mhd_assert (data_left <= c->read_buffer_offset); 258 259 memmove (c->read_buffer, 260 c->read_buffer + c->h2.buff.unproc_hdrs_pos, 261 c->h2.buff.unproc_hdrs_size); 262 c->h2.buff.unproc_hdrs_pos = 0u; 263 264 memmove (c->read_buffer + c->h2.buff.unproc_hdrs_size, 265 c->read_buffer + c->h2.buff.r_cur_frame, 266 data_left); 267 268 c->h2.buff.r_cur_frame = c->h2.buff.unproc_hdrs_size; 269 c->read_buffer_offset = c->h2.buff.r_cur_frame + data_left; 270 } 271 272 return (mhd_HTTP_LAYER_CONNECTED == c->h_layer.state); 273 }