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 }