libmicrohttpd2

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

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 }