libmicrohttpd2

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

conn_data_process.c (7059B)


      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 #endif /* MHD_SUPPORT_HTTPS */
     88 
     89   return mhd_COMM_LAYER_OK;
     90 }
     91 
     92 
     93 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
     94 mhd_conn_process_recv_send_data (struct MHD_Connection *restrict c)
     95 {
     96   bool send_ready_state_known;
     97   bool has_sock_err;
     98   bool data_processed;
     99 
    100   data_processed = false;
    101 
    102   mhd_assert (! c->suspended);
    103   if (c->resuming)
    104   {
    105     /* Fully resume the connection + call app callbacks for the data */
    106     if (! mhd_conn_process_data (c))
    107       return false;
    108 
    109     data_processed = true;
    110   }
    111 
    112   if (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err)
    113   {
    114     if (! mhd_conn_process_data (c))
    115       return false;
    116   }
    117 
    118   switch (process_conn_layer (c))
    119   {
    120   case mhd_COMM_LAYER_OK:
    121     break;        /* Connected, the data */
    122   case mhd_COMM_LAYER_PROCESSING:
    123     return true;  /* Not yet fully connected, too early for the data */
    124   case mhd_COMM_LAYER_BROKEN:
    125     return false; /* Connection is broken */
    126   default:
    127     mhd_UNREACHABLE ();
    128     return false;
    129   }
    130 
    131   /* The "send-ready" state is known if system polling call is edge-triggered
    132      (it always checks for both send- and recv-ready) or if connection needs
    133      sending (therefore "send-ready" was explicitly checked by sockets polling
    134      call). */
    135   send_ready_state_known =
    136     ((mhd_D_HAS_EDGE_TRIGG (c->daemon)) ||
    137      (0 != (MHD_EVENT_LOOP_INFO_SEND & c->event_loop_info)));
    138   has_sock_err =
    139     (0 != (mhd_SOCKET_NET_STATE_ERROR_READY & c->sk.ready));
    140   mhd_assert (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err);
    141 
    142   if (0 != (MHD_EVENT_LOOP_INFO_RECV & c->event_loop_info))
    143   {
    144     bool use_recv;
    145     use_recv = (0 != (mhd_SOCKET_NET_STATE_RECV_READY
    146                       & (c->sk.ready | mhd_C_HAS_TLS_DATA_IN (c))));
    147     use_recv = use_recv ||
    148                (has_sock_err && c->sk.props.is_nonblck);
    149 
    150     if (use_recv)
    151     {
    152       mhd_conn_data_recv (c, has_sock_err);
    153       mhd_assert (! has_sock_err ||
    154                   (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err));
    155       if (! mhd_C_IS_HTTP2 (c))
    156       {
    157         if (! mhd_conn_process_data (c))
    158           return false;
    159         data_processed = true;
    160         mhd_ASSUME (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err);
    161       }
    162     }
    163   }
    164 
    165   if (0 != (MHD_EVENT_LOOP_INFO_SEND & c->event_loop_info))
    166   {
    167     bool use_send;
    168     /* Perform sending if:
    169      * + connection is ready for sending or
    170      * + just formed send data, connection send ready status is not known and
    171      *   connection socket is non-blocking
    172      * + detected network error on the connection, to check for the error */
    173     /* Assuming that after finishing receiving phase, connection send system
    174        buffers should have some space as sending was performed before receiving
    175        or has not been performed yet. */
    176     use_send = (0 != (mhd_SOCKET_NET_STATE_SEND_READY & c->sk.ready));
    177 
    178     /* Do not try to send if connection is broken when receiving */
    179     use_send = use_send && (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err);
    180 
    181     if (! mhd_C_IS_HTTP2 (c))
    182     {
    183       use_send = use_send ||
    184                  (data_processed && (! send_ready_state_known)
    185                   && c->sk.props.is_nonblck);
    186       use_send = use_send ||
    187                  (has_sock_err && c->sk.props.is_nonblck);
    188     }
    189 
    190     if (use_send)
    191     {
    192       mhd_conn_data_send (c);
    193       mhd_assert (! has_sock_err ||
    194                   (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err));
    195       if (! mhd_C_IS_HTTP2 (c))
    196       {
    197         if (! mhd_conn_process_data (c))
    198           return false;
    199         data_processed = true;
    200         mhd_ASSUME (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err);
    201       }
    202     }
    203   }
    204 
    205   if (mhd_SCKT_NET_ST_HAS_FLAG (c->sk.ready,
    206                                 mhd_SOCKET_NET_STATE_ERROR_READY) &&
    207       (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err))
    208   {
    209     c->sk.state.discnt_err = mhd_socket_error_get_from_socket (c->sk.fd);
    210     mhd_ASSUME (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err);
    211   }
    212 
    213   if (! data_processed ||
    214       mhd_C_IS_HTTP2 (c) ||
    215       (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err))
    216     return mhd_conn_process_data (c);
    217 
    218   return true;
    219 }