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 }