action.c (12474B)
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; 208 (void)buffer_size; 209 (void)max_nonstream_size; 210 (void)enc; 211 (void)stream_reader; 212 (void)reader_cls; 213 (void)done_cb; 214 (void)done_cb_cls; 215 return NULL; 216 #endif /* ! MHD_SUPPORT_POST_PARSER */ 217 } 218 219 220 #ifdef MHD_SUPPORT_UPGRADE 221 222 MHD_EXTERN_ 223 MHD_FN_PAR_NONNULL_ (1) 224 MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_CSTR_ (2) 225 MHD_FN_PAR_IN_SIZE_ (6, 5) const struct MHD_Action * 226 MHD_action_upgrade (struct MHD_Request *MHD_RESTRICT request, 227 const char *MHD_RESTRICT upgrade_hdr_value, 228 MHD_UpgradeHandler upgrade_handler, 229 void *upgrade_handler_cls, 230 size_t num_headers, 231 const struct MHD_NameValueCStr *MHD_RESTRICT headers) 232 { 233 struct MHD_Action *const restrict head_act = 234 &(request->app_act.head_act); 235 236 if (mhd_REQ_IS_HTTP2 (request)) 237 return (const struct MHD_Action *)NULL; 238 if (mhd_ACTION_NO_ACTION != head_act->act) 239 return (const struct MHD_Action *)NULL; 240 if (NULL == upgrade_handler) 241 return (const struct MHD_Action *)NULL; 242 if (request->cntn.cntn_size != request->cntn.recv_size) 243 return (const struct MHD_Action *)NULL; /* Cannot start "Upgrade" if any content upload is pending */ 244 245 if (!mhd_upgrade_prep_for_action (request, 246 upgrade_hdr_value, 247 num_headers, 248 headers, 249 false)) 250 return (const struct MHD_Action *)NULL; 251 252 head_act->act = mhd_ACTION_UPGRADE; 253 head_act->data.upgrd.cb = upgrade_handler; 254 head_act->data.upgrd.cb_cls = upgrade_handler_cls; 255 256 return head_act; 257 } 258 259 260 MHD_EXTERN_ 261 MHD_FN_PAR_NONNULL_ (1) 262 MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_CSTR_ (2) 263 MHD_FN_PAR_IN_SIZE_ (6, 5) const struct MHD_UploadAction * 264 MHD_upload_action_upgrade ( 265 struct MHD_Request *MHD_RESTRICT request, 266 const char *MHD_RESTRICT upgrade_hdr_value, 267 MHD_UpgradeHandler upgrade_handler, 268 void *upgrade_handler_cls, 269 size_t num_headers, 270 const struct MHD_NameValueCStr *MHD_RESTRICT headers) 271 { 272 struct MHD_UploadAction *const restrict upl_act = 273 &(request->app_act.upl_act); 274 275 if (mhd_REQ_IS_HTTP2 (request)) 276 return (const struct MHD_UploadAction *)NULL; 277 if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act) 278 return (const struct MHD_UploadAction *)NULL; 279 if (NULL == upgrade_handler) 280 return (const struct MHD_UploadAction *)NULL; 281 if (request->cntn.cntn_size != request->cntn.recv_size) 282 return (const struct MHD_UploadAction *)NULL; /* Cannot start "Upgrade" if any content upload is pending */ 283 284 if (!mhd_upgrade_prep_for_action (request, 285 upgrade_hdr_value, 286 num_headers, 287 headers, 288 true)) 289 return (const struct MHD_UploadAction *)NULL; 290 291 upl_act->act = mhd_UPLOAD_ACTION_UPGRADE; 292 upl_act->data.upgrd.cb = upgrade_handler; 293 upl_act->data.upgrd.cb_cls = upgrade_handler_cls; 294 295 return upl_act; 296 } 297 298 299 #endif /* MHD_SUPPORT_UPGRADE */ 300 301 302 MHD_EXTERN_ MHD_FN_PAR_NONNULL_ALL_ 303 const struct MHD_UploadAction * 304 MHD_upload_action_suspend (struct MHD_Request *request) 305 { 306 struct MHD_UploadAction *const upl_act = mhd_REQ_GET_ACT_UPLD (request); 307 if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act) 308 return (const struct MHD_UploadAction *)NULL; 309 310 upl_act->act = mhd_UPLOAD_ACTION_SUSPEND; 311 312 return upl_act; 313 } 314 315 316 MHD_EXTERN_ 317 MHD_FN_PAR_NONNULL_ (1) const struct MHD_UploadAction * 318 MHD_upload_action_from_response (struct MHD_Request *MHD_RESTRICT request, 319 struct MHD_Response *MHD_RESTRICT response) 320 { 321 struct MHD_UploadAction *const upl_act = mhd_REQ_GET_ACT_UPLD (request); 322 if (NULL == response) 323 return (const struct MHD_UploadAction *)NULL; 324 325 mhd_response_check_frozen_freeze (response); 326 mhd_response_inc_use_count (response); 327 328 #ifdef MHD_SUPPORT_HTTP2 329 if (mhd_REQ_IS_HTTP2 (request)) 330 { 331 if (!mhd_h2_act_is_resp_h2_compatible ((struct mhd_H2RequestData *)request, 332 response)) 333 { 334 /* Clean-up unused response */ 335 mhd_response_dec_use_count (response); 336 return (const struct MHD_UploadAction *)NULL; 337 } 338 } 339 #endif /* MHD_SUPPORT_HTTP2 */ 340 341 if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act) 342 { 343 /* Clean-up unused response */ 344 mhd_response_dec_use_count (response); 345 return (const struct MHD_UploadAction *)NULL; 346 } 347 #ifdef MHD_SUPPORT_AUTH_DIGEST 348 if (mhd_RESP_HAS_AUTH_DIGEST (response) 349 && !mhd_D_HAS_AUTH_DIGEST ( \ 350 mhd_CNTNR_CPTR (request, struct MHD_Connection, rq)->daemon)) 351 { 352 /* Clean-up unused response */ 353 mhd_response_dec_use_count (response); 354 // TODO: get connection pointer for HTTP/2 355 mhd_assert (!mhd_REQ_IS_HTTP2 (request)); 356 mhd_LOG_MSG (mhd_CNTNR_PTR (request, struct MHD_Connection, rq)->daemon, \ 357 MHD_SC_AUTH_DIGEST_UNSUPPORTED, \ 358 "Attempted to use a response with Digest Auth challenge on " \ 359 "the daemon without enabled Digest Auth support"); 360 return (const struct MHD_UploadAction *)NULL; 361 } 362 #endif /* MHD_SUPPORT_AUTH_DIGEST */ 363 364 upl_act->act = mhd_UPLOAD_ACTION_RESPONSE; 365 upl_act->data.response = response; 366 367 return upl_act; 368 } 369 370 371 MHD_EXTERN_ 372 MHD_FN_PAR_NONNULL_ (1) const struct MHD_UploadAction * 373 MHD_upload_action_continue (struct MHD_Request *request) 374 { 375 struct MHD_UploadAction *const upl_act = mhd_REQ_GET_ACT_UPLD (request); 376 if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act) 377 return (const struct MHD_UploadAction *)NULL; 378 379 upl_act->act = mhd_UPLOAD_ACTION_CONTINUE; 380 381 return upl_act; 382 }