libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

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 }