action.c (12513B)
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) const struct MHD_Action * 140 MHD_action_process_upload (struct MHD_Request *request, 141 size_t large_buffer_size, 142 MHD_UploadCallback uc_full, 143 void *uc_full_cls, 144 MHD_UploadCallback uc_inc, 145 void *uc_inc_cls) 146 { 147 struct MHD_Action *const head_act = mhd_REQ_GET_ACT_HEAD (request); 148 149 if (mhd_ACTION_NO_ACTION != head_act->act) 150 return (const struct MHD_Action *) NULL; 151 152 if (0 == large_buffer_size) 153 { 154 if (NULL != uc_full) 155 return (const struct MHD_Action *) NULL; 156 if (NULL == uc_inc) 157 return (const struct MHD_Action *) NULL; 158 } 159 else 160 { 161 if (NULL == uc_full) 162 return (const struct MHD_Action *) NULL; 163 } 164 165 head_act->act = mhd_ACTION_UPLOAD; 166 head_act->data.upload.large_buffer_size = large_buffer_size; 167 head_act->data.upload.full.cb = uc_full; 168 head_act->data.upload.full.cls = uc_full_cls; 169 head_act->data.upload.inc.cb = uc_inc; 170 head_act->data.upload.inc.cls = uc_inc_cls; 171 172 return head_act; 173 } 174 175 176 MHD_EXTERN_ 177 MHD_FN_PAR_NONNULL_ (1) const struct MHD_Action * 178 MHD_action_parse_post (struct MHD_Request *request, 179 size_t buffer_size, 180 size_t max_nonstream_size, 181 enum MHD_HTTP_PostEncoding enc, 182 MHD_PostDataReader stream_reader, 183 void *reader_cls, 184 MHD_PostDataFinished done_cb, 185 void *done_cb_cls) 186 { 187 #ifdef MHD_SUPPORT_POST_PARSER 188 struct MHD_Action *const head_act = mhd_REQ_GET_ACT_HEAD (request); 189 190 if (mhd_ACTION_NO_ACTION != head_act->act) 191 return (const struct MHD_Action *) NULL; 192 193 if (NULL == done_cb) 194 return (const struct MHD_Action *) NULL; 195 196 head_act->act = mhd_ACTION_POST_PARSE; 197 head_act->data.post_parse.buffer_size = buffer_size; 198 head_act->data.post_parse.max_nonstream_size = max_nonstream_size; 199 head_act->data.post_parse.enc = enc; 200 head_act->data.post_parse.stream_reader = stream_reader; 201 head_act->data.post_parse.reader_cls = reader_cls; 202 head_act->data.post_parse.done_cb = done_cb; 203 head_act->data.post_parse.done_cb_cls = done_cb_cls; 204 205 return head_act; 206 #else /* ! MHD_SUPPORT_POST_PARSER */ 207 (void) request; (void) buffer_size; (void) max_nonstream_size; 208 (void) enc; (void) stream_reader; (void) reader_cls; 209 (void) done_cb; (void) done_cb_cls; 210 return NULL; 211 #endif /* ! MHD_SUPPORT_POST_PARSER */ 212 } 213 214 215 #ifdef MHD_SUPPORT_UPGRADE 216 217 MHD_EXTERN_ 218 MHD_FN_PAR_NONNULL_ (1) 219 MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_CSTR_ (2) 220 MHD_FN_PAR_IN_SIZE_ (6,5) const struct MHD_Action * 221 MHD_action_upgrade (struct MHD_Request *MHD_RESTRICT request, 222 const char *MHD_RESTRICT upgrade_hdr_value, 223 MHD_UpgradeHandler upgrade_handler, 224 void *upgrade_handler_cls, 225 size_t num_headers, 226 const struct MHD_NameValueCStr *MHD_RESTRICT headers) 227 { 228 struct MHD_Action *const restrict head_act = 229 &(request->app_act.head_act); 230 231 if (mhd_REQ_IS_HTTP2 (request)) 232 return (const struct MHD_Action *) NULL; 233 if (mhd_ACTION_NO_ACTION != head_act->act) 234 return (const struct MHD_Action *) NULL; 235 if (NULL == upgrade_handler) 236 return (const struct MHD_Action *) NULL; 237 if (request->cntn.cntn_size != request->cntn.recv_size) 238 return (const struct MHD_Action *) NULL; /* Cannot start "Upgrade" if any content upload is pending */ 239 240 if (! mhd_upgrade_prep_for_action (request, 241 upgrade_hdr_value, 242 num_headers, 243 headers, 244 false)) 245 return (const struct MHD_Action *) NULL; 246 247 head_act->act = mhd_ACTION_UPGRADE; 248 head_act->data.upgrd.cb = upgrade_handler; 249 head_act->data.upgrd.cb_cls = upgrade_handler_cls; 250 251 return head_act; 252 } 253 254 255 MHD_EXTERN_ 256 MHD_FN_PAR_NONNULL_ (1) 257 MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_CSTR_ (2) 258 MHD_FN_PAR_IN_SIZE_ (6,5) const struct MHD_UploadAction * 259 MHD_upload_action_upgrade ( 260 struct MHD_Request *MHD_RESTRICT request, 261 const char *MHD_RESTRICT upgrade_hdr_value, 262 MHD_UpgradeHandler upgrade_handler, 263 void *upgrade_handler_cls, 264 size_t num_headers, 265 const struct MHD_NameValueCStr *MHD_RESTRICT headers) 266 { 267 struct MHD_UploadAction *const restrict upl_act = 268 &(request->app_act.upl_act); 269 270 if (mhd_REQ_IS_HTTP2 (request)) 271 return (const struct MHD_UploadAction *) NULL; 272 if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act) 273 return (const struct MHD_UploadAction *) NULL; 274 if (NULL == upgrade_handler) 275 return (const struct MHD_UploadAction *) NULL; 276 if (request->cntn.cntn_size != request->cntn.recv_size) 277 return (const struct MHD_UploadAction *) NULL; /* Cannot start "Upgrade" if any content upload is pending */ 278 279 if (! mhd_upgrade_prep_for_action (request, 280 upgrade_hdr_value, 281 num_headers, 282 headers, 283 true)) 284 return (const struct MHD_UploadAction *) NULL; 285 286 upl_act->act = mhd_UPLOAD_ACTION_UPGRADE; 287 upl_act->data.upgrd.cb = upgrade_handler; 288 upl_act->data.upgrd.cb_cls = upgrade_handler_cls; 289 290 return upl_act; 291 } 292 293 294 #endif /* MHD_SUPPORT_UPGRADE */ 295 296 297 MHD_EXTERN_ MHD_FN_PAR_NONNULL_ALL_ 298 const struct MHD_UploadAction * 299 MHD_upload_action_suspend (struct MHD_Request *request) 300 { 301 struct MHD_UploadAction *const upl_act = mhd_REQ_GET_ACT_UPLD (request); 302 if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act) 303 return (const struct MHD_UploadAction *) NULL; 304 305 upl_act->act = mhd_UPLOAD_ACTION_SUSPEND; 306 307 return upl_act; 308 } 309 310 311 MHD_EXTERN_ 312 MHD_FN_PAR_NONNULL_ (1) const struct MHD_UploadAction * 313 MHD_upload_action_from_response (struct MHD_Request *MHD_RESTRICT request, 314 struct MHD_Response *MHD_RESTRICT response) 315 { 316 struct MHD_UploadAction *const upl_act = mhd_REQ_GET_ACT_UPLD (request); 317 if (NULL == response) 318 return (const struct MHD_UploadAction *) NULL; 319 320 mhd_response_check_frozen_freeze (response); 321 mhd_response_inc_use_count (response); 322 323 #ifdef MHD_SUPPORT_HTTP2 324 if (mhd_REQ_IS_HTTP2 (request)) 325 { 326 if (! mhd_h2_act_is_resp_h2_compatible ((struct mhd_H2RequestData*) request, 327 response)) 328 { 329 /* Clean-up unused response */ 330 mhd_response_dec_use_count (response); 331 return (const struct MHD_UploadAction *) NULL; 332 } 333 } 334 #endif /* MHD_SUPPORT_HTTP2 */ 335 336 if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act) 337 { 338 /* Clean-up unused response */ 339 mhd_response_dec_use_count (response); 340 return (const struct MHD_UploadAction *) NULL; 341 } 342 #ifdef MHD_SUPPORT_AUTH_DIGEST 343 if (mhd_RESP_HAS_AUTH_DIGEST (response) && 344 ! mhd_D_HAS_AUTH_DIGEST ( \ 345 mhd_CNTNR_CPTR (request, struct MHD_Connection, rq)->daemon)) 346 { 347 /* Clean-up unused response */ 348 mhd_response_dec_use_count (response); 349 // TODO: get connection pointer for HTTP/2 350 mhd_assert (! mhd_REQ_IS_HTTP2 (request)); 351 mhd_LOG_MSG (mhd_CNTNR_PTR (request, struct MHD_Connection, rq)->daemon, \ 352 MHD_SC_AUTH_DIGEST_UNSUPPORTED, \ 353 "Attempted to use a response with Digest Auth challenge on " \ 354 "the daemon without enabled Digest Auth support"); 355 return (const struct MHD_UploadAction *) NULL; 356 } 357 #endif /* MHD_SUPPORT_AUTH_DIGEST */ 358 359 upl_act->act = mhd_UPLOAD_ACTION_RESPONSE; 360 upl_act->data.response = response; 361 362 return upl_act; 363 } 364 365 366 MHD_EXTERN_ 367 MHD_FN_PAR_NONNULL_ (1) const struct MHD_UploadAction * 368 MHD_upload_action_continue (struct MHD_Request *request) 369 { 370 struct MHD_UploadAction *const upl_act = mhd_REQ_GET_ACT_UPLD (request); 371 if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act) 372 return (const struct MHD_UploadAction *) NULL; 373 374 upl_act->act = mhd_UPLOAD_ACTION_CONTINUE; 375 376 return upl_act; 377 }