libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

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 }