conn_data_recv.c (6984B)
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) 2024-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/conn_data_recv.c 41 * @brief The implementation of data receiving functions for connection 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 "conn_timeout.h" 55 #include "stream_funcs.h" 56 #include "mhd_socket_error_funcs.h" 57 #include "sckt_recv.h" 58 59 #include "mhd_recv.h" 60 61 #include "conn_data_recv.h" 62 63 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void 64 mhd_conn_data_recv (struct MHD_Connection *c, 65 bool has_err) 66 { 67 void *buf; 68 size_t buf_size; 69 size_t received; 70 enum mhd_SocketError res; 71 72 mhd_assert (mhd_HTTP_STAGE_CLOSED != c->stage); 73 mhd_assert (NULL != c->read_buffer); 74 mhd_assert (c->read_buffer_size > c->read_buffer_offset); 75 mhd_assert (!has_err \ 76 || (0 != (c->sk.ready & mhd_SOCKET_NET_STATE_ERROR_READY))); 77 mhd_assert ((0 == (c->sk.ready & mhd_SOCKET_NET_STATE_ERROR_READY)) \ 78 || has_err); 79 mhd_assert (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err); 80 81 buf = c->read_buffer + c->read_buffer_offset; 82 buf_size = c->read_buffer_size - c->read_buffer_offset; 83 84 res = mhd_recv (c, 85 buf_size, 86 (char *)buf, 87 &received); 88 89 mhd_assert (mhd_SOCKET_ERR_NO_ERROR == c->sk.state.discnt_err); 90 91 if ((mhd_SOCKET_ERR_NO_ERROR != res) || has_err) 92 { 93 /* Handle errors */ 94 if ((mhd_SOCKET_ERR_NO_ERROR == res) && (0 == received)) 95 { 96 c->sk.state.rmt_shut_wr = true; 97 c->sk.state.discnt_err = mhd_SOCKET_ERR_REMT_DISCONN; 98 return; 99 } 100 101 if (mhd_SOCKET_ERR_IS_HARD (res) 102 || has_err) 103 { 104 /* Hard error. Clarify and set disconnect error. */ 105 if (mhd_SOCKET_ERR_IS_NOT_SCKT (res)) 106 { 107 c->sk.state.discnt_err = res; 108 } 109 else 110 { 111 if (!mhd_SOCKET_ERR_IS_HARD (res) 112 && (c->sk.props.is_nonblck)) 113 { 114 /* Re-try the last time with direct socket recv() to detect the error */ 115 uint_fast64_t dummy_buf; 116 enum mhd_SocketError raw_sckt_err; 117 118 mhd_assert (has_err); 119 120 raw_sckt_err = mhd_sckt_recv (&(c->sk), 121 sizeof(dummy_buf), 122 (char *)&dummy_buf, 123 &received); 124 if (mhd_SOCKET_ERR_IS_HARD (raw_sckt_err)) 125 res = raw_sckt_err; 126 } 127 128 if (!mhd_SOCKET_ERR_IS_HARD (res)) 129 { 130 mhd_assert (has_err); 131 c->sk.state.discnt_err = 132 mhd_socket_error_get_from_socket (c->sk.fd); 133 } 134 else 135 { 136 c->sk.state.discnt_err = res; 137 mhd_SCKT_NET_ST_SET_FLAG (&(c->sk.ready), 138 mhd_SOCKET_NET_STATE_ERROR_READY); 139 } 140 } 141 142 mhd_assert (mhd_SOCKET_ERR_NO_ERROR != c->sk.state.discnt_err); 143 mhd_assert (mhd_SOCKET_ERR_IS_HARD (c->sk.state.discnt_err)); 144 return; 145 } 146 147 mhd_assert (!mhd_SOCKET_ERR_IS_HARD (c->sk.state.discnt_err)); 148 return; 149 } 150 151 mhd_assert (!mhd_SOCKET_ERR_IS_HARD (res)); 152 mhd_assert (!has_err); 153 154 if (0 == received) 155 c->sk.state.rmt_shut_wr = true; 156 157 c->read_buffer_offset += received; 158 mhd_conn_update_activity_mark (c); 159 return; 160 } 161 162 163 #if 0 // TODO: report disconnect 164 if ((bytes_read < 0) || socket_error) 165 { 166 if (MHD_ERR_CONNRESET_ == bytes_read) 167 { 168 if ((mhd_HTTP_STAGE_INIT < c->stage) 169 && (mhd_HTTP_STAGE_FULL_REQ_RECEIVED > c->stage)) 170 { 171 # ifdef HAVE_MESSAGES 172 MHD_DLOG (c->daemon, 173 _ ("Socket has been disconnected when reading request.\n")); 174 # endif 175 c->discard_request = true; 176 } 177 MHD_connection_close_ (c, 178 MHD_REQUEST_TERMINATED_READ_ERROR); 179 return; 180 } 181 182 # ifdef HAVE_MESSAGES 183 if (mhd_HTTP_STAGE_INIT != c->stage) 184 MHD_DLOG (c->daemon, 185 _ ("Connection socket is closed when reading " \ 186 "request due to the error: %s\n"), 187 (bytes_read < 0) ? str_conn_error_ (bytes_read) : 188 "detected c closure"); 189 # endif 190 CONNECTION_CLOSE_ERROR (c, 191 NULL); 192 return; 193 } 194 195 # if 0 // TODO: handle remote shut WR 196 if (0 == bytes_read) 197 { /* Remote side closed c. */ // FIXME: Actually NOT! 198 c->sk.state.rmt_shut_wr = true; 199 if ((mhd_HTTP_STAGE_INIT < c->stage) 200 && (mhd_HTTP_STAGE_FULL_REQ_RECEIVED > c->stage)) 201 { 202 # ifdef HAVE_MESSAGES 203 MHD_DLOG (c->daemon, 204 _ ("Connection was closed by remote side with incomplete " 205 "request.\n")); 206 # endif 207 c->discard_request = true; 208 MHD_connection_close_ (c, 209 MHD_REQUEST_TERMINATED_CLIENT_ABORT); 210 } 211 else if (mhd_HTTP_STAGE_INIT == c->stage) 212 /* This termination code cannot be reported to the application 213 * because application has not been informed yet about this request */ 214 MHD_connection_close_ (c, 215 MHD_REQUEST_TERMINATED_COMPLETED_OK); 216 else 217 MHD_connection_close_ (c, 218 MHD_REQUEST_TERMINATED_WITH_ERROR); 219 return; 220 } 221 # endif 222 #endif