libmicrohttpd2

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

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 }