action.c (12588B)
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 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/action.c 41 * @brief The definition of the MHD_action_*() and MHD_upload_action_*() 42 * @author Karlson2k (Evgeny Grin) 43 */ 44 45 #include "mhd_sys_options.h" 46 47 #include "mhd_cntnr_ptr.h" 48 #include "mhd_connection.h" 49 #include "mhd_daemon.h" 50 #include "mhd_action.h" 51 #include "mhd_request.h" 52 #include "mhd_response.h" 53 54 #include "daemon_logger.h" 55 56 #include "response_funcs.h" 57 #include "response_destroy.h" 58 59 #ifdef MHD_SUPPORT_UPGRADE 60 # include "upgrade_prep.h" 61 #endif 62 #ifdef MHD_SUPPORT_HTTP2 63 # include "h2/h2_action.h" 64 #endif 65 66 #include "mhd_public_api.h" 67 68 69 MHD_EXTERN_ MHD_FN_PAR_NONNULL_ALL_ 70 const struct MHD_Action * 71 MHD_action_suspend (struct MHD_Request *request) 72 { 73 struct MHD_Action *const head_act = mhd_REQ_GET_ACT_HEAD (request); 74 75 if (mhd_ACTION_NO_ACTION != head_act->act) 76 return (const struct MHD_Action *)NULL; 77 78 head_act->act = mhd_ACTION_SUSPEND; 79 return head_act; 80 } 81 82 83 MHD_EXTERN_ 84 MHD_FN_PAR_NONNULL_ (1) const struct MHD_Action * 85 MHD_action_from_response (struct MHD_Request *MHD_RESTRICT request, 86 struct MHD_Response *MHD_RESTRICT response) 87 { 88 struct MHD_Action *const head_act = mhd_REQ_GET_ACT_HEAD (request); 89 if (NULL == response) 90 return (const struct MHD_Action *)NULL; 91 92 mhd_response_check_frozen_freeze (response); 93 mhd_response_inc_use_count (response); 94 95 #ifdef MHD_SUPPORT_HTTP2 96 if (mhd_REQ_IS_HTTP2 (request)) 97 { 98 if (!mhd_h2_act_is_resp_h2_compatible ((struct mhd_H2RequestData *)request, 99 response)) 100 { 101 /* Clean-up unused response */ 102 mhd_response_dec_use_count (response); 103 return (const struct MHD_Action *)NULL; 104 } 105 } 106 #endif /* MHD_SUPPORT_HTTP2 */ 107 108 if (mhd_ACTION_NO_ACTION != head_act->act) 109 { 110 /* Clean-up unused response */ 111 mhd_response_dec_use_count (response); 112 return (const struct MHD_Action *)NULL; 113 } 114 #ifdef MHD_SUPPORT_AUTH_DIGEST 115 if (mhd_RESP_HAS_AUTH_DIGEST (response) 116 && !mhd_D_HAS_AUTH_DIGEST ( \ 117 mhd_CNTNR_CPTR (request, struct MHD_Connection, rq)->daemon)) 118 { 119 /* Clean-up unused response */ 120 mhd_response_dec_use_count (response); 121 // TODO: get connection pointer for HTTP/2 122 mhd_assert (!mhd_REQ_IS_HTTP2 (request)); 123 mhd_LOG_MSG (mhd_CNTNR_PTR (request, struct MHD_Connection, rq)->daemon, \ 124 MHD_SC_AUTH_DIGEST_UNSUPPORTED, \ 125 "Attempted to use a response with Digest Auth challenge on " \ 126 "the daemon without enabled Digest Auth support"); 127 return (const struct MHD_Action *)NULL; 128 } 129 #endif /* MHD_SUPPORT_AUTH_DIGEST */ 130 131 head_act->act = mhd_ACTION_RESPONSE; 132 head_act->data.response = response; 133 134 return head_act; 135 } 136 137 138 MHD_EXTERN_ 139 MHD_FN_PAR_NONNULL_ (1) 140 MHD_FN_PAR_NONNULL_IF_NONZERO_ (3, 2) const struct MHD_Action * 141 MHD_action_process_upload (struct MHD_Request *request, 142 size_t large_buffer_size, 143 MHD_UploadCallback uc_full, 144 void *uc_full_cls, 145 MHD_UploadCallback uc_inc, 146 void *uc_inc_cls) 147 { 148 struct MHD_Action *const head_act = mhd_REQ_GET_ACT_HEAD (request); 149 150 if (mhd_ACTION_NO_ACTION != head_act->act) 151 return (const struct MHD_Action *)NULL; 152 153 if (0 == large_buffer_size) 154 { 155 if (NULL != uc_full) 156 return (const struct MHD_Action *)NULL; 157 if (NULL == uc_inc) 158 return (const struct MHD_Action *)NULL; 159 } 160 else 161 { 162 if (NULL == uc_full) 163 return (const struct MHD_Action *)NULL; 164 } 165 166 head_act->act = mhd_ACTION_UPLOAD; 167 head_act->data.upload.large_buffer_size = large_buffer_size; 168 head_act->data.upload.full.cb = uc_full; 169 head_act->data.upload.full.cls = uc_full_cls; 170 head_act->data.upload.inc.cb = uc_inc; 171 head_act->data.upload.inc.cls = uc_inc_cls; 172 173 return head_act; 174 } 175 176 177 MHD_EXTERN_ 178 MHD_FN_PAR_NONNULL_ (1) const struct MHD_Action * 179 MHD_action_parse_post (struct MHD_Request *request, 180 size_t buffer_size, 181 size_t max_nonstream_size, 182 enum MHD_HTTP_PostEncoding enc, 183 MHD_PostDataReader stream_reader, 184 void *reader_cls, 185 MHD_PostDataFinished done_cb, 186 void *done_cb_cls) 187 { 188 #ifdef MHD_SUPPORT_POST_PARSER 189 struct MHD_Action *const head_act = mhd_REQ_GET_ACT_HEAD (request); 190 191 if (mhd_ACTION_NO_ACTION != head_act->act) 192 return (const struct MHD_Action *)NULL; 193 194 if (NULL == done_cb) 195 return (const struct MHD_Action *)NULL; 196 197 head_act->act = mhd_ACTION_POST_PARSE; 198 head_act->data.post_parse.buffer_size = buffer_size; 199 head_act->data.post_parse.max_nonstream_size = max_nonstream_size; 200 head_act->data.post_parse.enc = enc; 201 head_act->data.post_parse.stream_reader = stream_reader; 202 head_act->data.post_parse.reader_cls = reader_cls; 203 head_act->data.post_parse.done_cb = done_cb; 204 head_act->data.post_parse.done_cb_cls = done_cb_cls; 205 206 return head_act; 207 #else /* ! MHD_SUPPORT_POST_PARSER */ 208 (void)request; 209 (void)buffer_size; 210 (void)max_nonstream_size; 211 (void)enc; 212 (void)stream_reader; 213 (void)reader_cls; 214 (void)done_cb; 215 (void)done_cb_cls; 216 return NULL; 217 #endif /* ! MHD_SUPPORT_POST_PARSER */ 218 } 219 220 221 #ifdef MHD_SUPPORT_UPGRADE 222 223 MHD_EXTERN_ 224 MHD_FN_PAR_NONNULL_ (1) 225 MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_CSTR_ (2) 226 MHD_FN_PAR_NONNULL_IF_NONZERO_ (6, 5) 227 MHD_FN_PAR_IN_SIZE_ (6, 5) const struct MHD_Action * 228 MHD_action_upgrade (struct MHD_Request *MHD_RESTRICT request, 229 const char *MHD_RESTRICT upgrade_hdr_value, 230 MHD_UpgradeHandler upgrade_handler, 231 void *upgrade_handler_cls, 232 size_t num_headers, 233 const struct MHD_NameValueCStr *MHD_RESTRICT headers) 234 { 235 struct MHD_Action *const restrict head_act = 236 &(request->app_act.head_act); 237 238 if (mhd_REQ_IS_HTTP2 (request)) 239 return (const struct MHD_Action *)NULL; 240 if (mhd_ACTION_NO_ACTION != head_act->act) 241 return (const struct MHD_Action *)NULL; 242 if (NULL == upgrade_handler) 243 return (const struct MHD_Action *)NULL; 244 if (request->cntn.cntn_size != request->cntn.recv_size) 245 return (const struct MHD_Action *)NULL; /* Cannot start "Upgrade" if any content upload is pending */ 246 247 if (!mhd_upgrade_prep_for_action (request, 248 upgrade_hdr_value, 249 num_headers, 250 headers, 251 false)) 252 return (const struct MHD_Action *)NULL; 253 254 head_act->act = mhd_ACTION_UPGRADE; 255 head_act->data.upgrd.cb = upgrade_handler; 256 head_act->data.upgrd.cb_cls = upgrade_handler_cls; 257 258 return head_act; 259 } 260 261 262 MHD_EXTERN_ 263 MHD_FN_PAR_NONNULL_ (1) 264 MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_CSTR_ (2) 265 MHD_FN_PAR_NONNULL_IF_NONZERO_ (6, 5) 266 MHD_FN_PAR_IN_SIZE_ (6, 5) const struct MHD_UploadAction * 267 MHD_upload_action_upgrade ( 268 struct MHD_Request *MHD_RESTRICT request, 269 const char *MHD_RESTRICT upgrade_hdr_value, 270 MHD_UpgradeHandler upgrade_handler, 271 void *upgrade_handler_cls, 272 size_t num_headers, 273 const struct MHD_NameValueCStr *MHD_RESTRICT headers) 274 { 275 struct MHD_UploadAction *const restrict upl_act = 276 &(request->app_act.upl_act); 277 278 if (mhd_REQ_IS_HTTP2 (request)) 279 return (const struct MHD_UploadAction *)NULL; 280 if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act) 281 return (const struct MHD_UploadAction *)NULL; 282 if (NULL == upgrade_handler) 283 return (const struct MHD_UploadAction *)NULL; 284 if (request->cntn.cntn_size != request->cntn.recv_size) 285 return (const struct MHD_UploadAction *)NULL; /* Cannot start "Upgrade" if any content upload is pending */ 286 287 if (!mhd_upgrade_prep_for_action (request, 288 upgrade_hdr_value, 289 num_headers, 290 headers, 291 true)) 292 return (const struct MHD_UploadAction *)NULL; 293 294 upl_act->act = mhd_UPLOAD_ACTION_UPGRADE; 295 upl_act->data.upgrd.cb = upgrade_handler; 296 upl_act->data.upgrd.cb_cls = upgrade_handler_cls; 297 298 return upl_act; 299 } 300 301 302 #endif /* MHD_SUPPORT_UPGRADE */ 303 304 305 MHD_EXTERN_ MHD_FN_PAR_NONNULL_ALL_ 306 const struct MHD_UploadAction * 307 MHD_upload_action_suspend (struct MHD_Request *request) 308 { 309 struct MHD_UploadAction *const upl_act = mhd_REQ_GET_ACT_UPLD (request); 310 if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act) 311 return (const struct MHD_UploadAction *)NULL; 312 313 upl_act->act = mhd_UPLOAD_ACTION_SUSPEND; 314 315 return upl_act; 316 } 317 318 319 MHD_EXTERN_ 320 MHD_FN_PAR_NONNULL_ (1) const struct MHD_UploadAction * 321 MHD_upload_action_from_response (struct MHD_Request *MHD_RESTRICT request, 322 struct MHD_Response *MHD_RESTRICT response) 323 { 324 struct MHD_UploadAction *const upl_act = mhd_REQ_GET_ACT_UPLD (request); 325 if (NULL == response) 326 return (const struct MHD_UploadAction *)NULL; 327 328 mhd_response_check_frozen_freeze (response); 329 mhd_response_inc_use_count (response); 330 331 #ifdef MHD_SUPPORT_HTTP2 332 if (mhd_REQ_IS_HTTP2 (request)) 333 { 334 if (!mhd_h2_act_is_resp_h2_compatible ((struct mhd_H2RequestData *)request, 335 response)) 336 { 337 /* Clean-up unused response */ 338 mhd_response_dec_use_count (response); 339 return (const struct MHD_UploadAction *)NULL; 340 } 341 } 342 #endif /* MHD_SUPPORT_HTTP2 */ 343 344 if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act) 345 { 346 /* Clean-up unused response */ 347 mhd_response_dec_use_count (response); 348 return (const struct MHD_UploadAction *)NULL; 349 } 350 #ifdef MHD_SUPPORT_AUTH_DIGEST 351 if (mhd_RESP_HAS_AUTH_DIGEST (response) 352 && !mhd_D_HAS_AUTH_DIGEST ( \ 353 mhd_CNTNR_CPTR (request, struct MHD_Connection, rq)->daemon)) 354 { 355 /* Clean-up unused response */ 356 mhd_response_dec_use_count (response); 357 // TODO: get connection pointer for HTTP/2 358 mhd_assert (!mhd_REQ_IS_HTTP2 (request)); 359 mhd_LOG_MSG (mhd_CNTNR_PTR (request, struct MHD_Connection, rq)->daemon, \ 360 MHD_SC_AUTH_DIGEST_UNSUPPORTED, \ 361 "Attempted to use a response with Digest Auth challenge on " \ 362 "the daemon without enabled Digest Auth support"); 363 return (const struct MHD_UploadAction *)NULL; 364 } 365 #endif /* MHD_SUPPORT_AUTH_DIGEST */ 366 367 upl_act->act = mhd_UPLOAD_ACTION_RESPONSE; 368 upl_act->data.response = response; 369 370 return upl_act; 371 } 372 373 374 MHD_EXTERN_ 375 MHD_FN_PAR_NONNULL_ (1) const struct MHD_UploadAction * 376 MHD_upload_action_continue (struct MHD_Request *request) 377 { 378 struct MHD_UploadAction *const upl_act = mhd_REQ_GET_ACT_UPLD (request); 379 if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act) 380 return (const struct MHD_UploadAction *)NULL; 381 382 upl_act->act = mhd_UPLOAD_ACTION_CONTINUE; 383 384 return upl_act; 385 }