libmicrohttpd2

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

conn_data_process.c (7094B)


      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) 2015-2024 Evgeny Grin (Karlson2k)
      5   Copyright (C) 2007-2020 Daniel Pittman and Christian Grothoff
      6 
      7   GNU libmicrohttpd is free software; you can redistribute it and/or
      8   modify it under the terms of the GNU Lesser General Public
      9   License as published by the Free Software Foundation; either
     10   version 2.1 of the License, or (at your option) any later version.
     11 
     12   GNU libmicrohttpd is distributed in the hope that it will be useful,
     13   but WITHOUT ANY WARRANTY; without even the implied warranty of
     14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15   Lesser General Public License for more details.
     16 
     17   Alternatively, you can redistribute GNU libmicrohttpd and/or
     18   modify it under the terms of the GNU General Public License as
     19   published by the Free Software Foundation; either version 2 of
     20   the License, or (at your option) any later version, together
     21   with the eCos exception, as follows:
     22 
     23     As a special exception, if other files instantiate templates or
     24     use macros or inline functions from this file, or you compile this
     25     file and link it with other works to produce a work based on this
     26     file, this file does not by itself cause the resulting work to be
     27     covered by the GNU General Public License. However the source code
     28     for this file must still be made available in accordance with
     29     section (3) of the GNU General Public License v2.
     30 
     31     This exception does not invalidate any other reasons why a work
     32     based on this file might be covered by the GNU General Public
     33     License.
     34 
     35   You should have received copies of the GNU Lesser General Public
     36   License and the GNU General Public License along with this library;
     37   if not, see <https://www.gnu.org/licenses/>.
     38 */
     39 
     40 /**
     41  * @file src/mhd2/data_process.c
     42  * @brief  The implementation of data receiving, sending and processing
     43  *         functions for connection
     44  * @author Karlson2k (Evgeny Grin)
     45  *
     46  * Based on the MHD v0.x code by Daniel Pittman, Christian Grothoff and other
     47  * contributors.
     48  */
     49 
     50 #include "mhd_sys_options.h"
     51 
     52 #include "conn_data_process.h"
     53 #include "sys_bool_type.h"
     54 #include "sys_base_types.h"
     55 
     56 #include "mhd_assert.h"
     57 #include "mhd_assume.h"
     58 #include "mhd_unreachable.h"
     59 #include "mhd_constexpr.h"
     60 
     61 #include <string.h>
     62 
     63 #include "mhd_daemon.h"
     64 #include "mhd_connection.h"
     65 
     66 #include "mhd_socket_error_funcs.h"
     67 
     68 #include "daemon_logger.h"
     69 
     70 #include "mhd_comm_layer_state.h"
     71 #ifdef MHD_SUPPORT_HTTPS
     72 #  include "conn_tls_check.h"
     73 #endif /* MHD_SUPPORT_HTTPS */
     74 
     75 #include "conn_data_recv.h"
     76 #include "conn_data_send.h"
     77 #include "stream_process_states.h"
     78 #include "mhd_comm_layer_state.h"
     79 
     80 
     81 mhd_static_inline enum mhd_CommLayerState
     82 process_conn_layer (struct MHD_Connection *restrict c)
     83 {
     84 #ifdef MHD_SUPPORT_HTTPS
     85   if (mhd_C_HAS_TLS (c))
     86     return mhd_conn_tls_check (c);
     87 #else  /* !MHD_SUPPORT_HTTPS */
     88   (void)c;
     89 #endif /* !MHD_SUPPORT_HTTPS */
     90 
     91   return mhd_COMM_LAYER_OK;
     92 }
     93 
     94 
     95 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
     96 mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c)
     97 {
     98   bool send_ready_state_known;
     99   bool has_sock_err;
    100   bool data_processed;
    101 
    102   data_processed = false;
    103 
    104   mhd_assert (!c->suspended);
    105   if (c->resuming)
    106   {
    107     /* Fully resume the connection + call app callbacks for the data */
    108     if (!mhd_conn_process_data (c))
    109       return false;
    110 
    111     data_processed = true;
    112   }
    113 
    114   if (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err)
    115   {
    116     if (!mhd_conn_process_data (c))
    117       return false;
    118   }
    119 
    120   switch (process_conn_layer (c))
    121   {
    122   case mhd_COMM_LAYER_OK:
    123     break;        /* Connected, the data */
    124   case mhd_COMM_LAYER_PROCESSING:
    125     return true;  /* Not yet fully connected, too early for the data */
    126   case mhd_COMM_LAYER_BROKEN:
    127     return false; /* Connection is broken */
    128   default:
    129     mhd_UNREACHABLE ();
    130     return false;
    131   }
    132 
    133   /* The "send-ready" state is known if system polling call is edge-triggered
    134      (it always checks for both send- and recv-ready) or if connection needs
    135      sending (therefore "send-ready" was explicitly checked by sockets polling
    136      call). */
    137   send_ready_state_known =
    138     ((mhd_D_HAS_EDGE_TRIGG (c->daemon))
    139      || (0 != (MHD_EVENT_LOOP_INFO_SEND & c->event_loop_info)));
    140   has_sock_err =
    141     (0 != (mhd_SOCKET_NET_STATE_ERROR_READY & c->sk.ready));
    142   mhd_assert (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err);
    143 
    144   if (0 != (MHD_EVENT_LOOP_INFO_RECV & c->event_loop_info))
    145   {
    146     bool use_recv;
    147     use_recv = (0 != (mhd_SOCKET_NET_STATE_RECV_READY
    148                       & (c->sk.ready | mhd_C_HAS_TLS_DATA_IN (c))));
    149     use_recv = use_recv
    150                || (has_sock_err && c->sk.props.is_nonblck);
    151 
    152     if (use_recv)
    153     {
    154       mhd_conn_data_recv (c, has_sock_err);
    155       mhd_assert (!has_sock_err
    156                   || (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err));
    157       if (!mhd_C_IS_HTTP2 (c))
    158       {
    159         if (!mhd_conn_process_data (c))
    160           return false;
    161         data_processed = true;
    162         mhd_ASSUME (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err);
    163       }
    164     }
    165   }
    166 
    167   if (0 != (MHD_EVENT_LOOP_INFO_SEND & c->event_loop_info))
    168   {
    169     bool use_send;
    170     /* Perform sending if:
    171      * + connection is ready for sending or
    172      * + just formed send data, connection send ready status is not known and
    173      *   connection socket is non-blocking
    174      * + detected network error on the connection, to check for the error */
    175     /* Assuming that after finishing receiving phase, connection send system
    176        buffers should have some space as sending was performed before receiving
    177        or has not been performed yet. */
    178     use_send = (0 != (mhd_SOCKET_NET_STATE_SEND_READY & c->sk.ready));
    179 
    180     /* Do not try to send if connection is broken when receiving */
    181     use_send = use_send && (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err);
    182 
    183     if (!mhd_C_IS_HTTP2 (c))
    184     {
    185       use_send = use_send
    186                  || (data_processed && (!send_ready_state_known)
    187                      && c->sk.props.is_nonblck);
    188       use_send = use_send
    189                  || (has_sock_err && c->sk.props.is_nonblck);
    190     }
    191 
    192     if (use_send)
    193     {
    194       mhd_conn_data_send (c);
    195       mhd_assert (!has_sock_err
    196                   || (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err));
    197       if (!mhd_C_IS_HTTP2 (c))
    198       {
    199         if (!mhd_conn_process_data (c))
    200           return false;
    201         data_processed = true;
    202         mhd_ASSUME (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err);
    203       }
    204     }
    205   }
    206 
    207   if (mhd_SCKT_NET_ST_HAS_FLAG (c->sk.ready,
    208                                 mhd_SOCKET_NET_STATE_ERROR_READY)
    209       && (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err))
    210   {
    211     c->sk.state.discnt_err = mhd_socket_error_get_from_socket (c->sk.fd);
    212     mhd_ASSUME (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err);
    213   }
    214 
    215   if (!data_processed
    216       || mhd_C_IS_HTTP2 (c)
    217       || (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err))
    218     return mhd_conn_process_data (c);
    219 
    220   return true;
    221 }