Coverage Report

Created: 2026-03-12 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mhd2/src/mhd2/action.c
Line
Count
Source
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
0
{
73
0
  struct MHD_Action *const head_act = mhd_REQ_GET_ACT_HEAD (request);
74
75
0
  if (mhd_ACTION_NO_ACTION != head_act->act)
76
0
    return (const struct MHD_Action *) NULL;
77
78
0
  head_act->act = mhd_ACTION_SUSPEND;
79
0
  return head_act;
80
0
}
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
0
{
88
0
  struct MHD_Action *const head_act = mhd_REQ_GET_ACT_HEAD (request);
89
0
  if (NULL == response)
90
0
    return (const struct MHD_Action *) NULL;
91
92
0
  mhd_response_check_frozen_freeze (response);
93
0
  mhd_response_inc_use_count (response);
94
95
0
#ifdef MHD_SUPPORT_HTTP2
96
0
  if (mhd_REQ_IS_HTTP2 (request))
97
0
  {
98
0
    if (! mhd_h2_act_is_resp_h2_compatible ((struct mhd_H2RequestData*) request,
99
0
                                            response))
100
0
    {
101
      /* Clean-up unused response */
102
0
      mhd_response_dec_use_count (response);
103
0
      return (const struct MHD_Action *) NULL;
104
0
    }
105
0
  }
106
0
#endif /* MHD_SUPPORT_HTTP2 */
107
108
0
  if (mhd_ACTION_NO_ACTION != head_act->act)
109
0
  {
110
    /* Clean-up unused response */
111
0
    mhd_response_dec_use_count (response);
112
0
    return (const struct MHD_Action *) NULL;
113
0
  }
114
0
#ifdef MHD_SUPPORT_AUTH_DIGEST
115
0
  if (mhd_RESP_HAS_AUTH_DIGEST (response) &&
116
0
      ! mhd_D_HAS_AUTH_DIGEST ( \
117
0
        mhd_CNTNR_CPTR (request, struct MHD_Connection, rq)->daemon))
118
0
  {
119
    /* Clean-up unused response */
120
0
    mhd_response_dec_use_count (response);
121
    // TODO: get connection pointer for HTTP/2
122
0
    mhd_assert (! mhd_REQ_IS_HTTP2 (request));
123
0
    mhd_LOG_MSG (mhd_CNTNR_PTR (request, struct MHD_Connection, rq)->daemon, \
124
0
                 MHD_SC_AUTH_DIGEST_UNSUPPORTED, \
125
0
                 "Attempted to use a response with Digest Auth challenge on " \
126
0
                 "the daemon without enabled Digest Auth support");
127
0
    return (const struct MHD_Action *) NULL;
128
0
  }
129
0
#endif /* MHD_SUPPORT_AUTH_DIGEST */
130
131
0
  head_act->act = mhd_ACTION_RESPONSE;
132
0
  head_act->data.response = response;
133
134
0
  return head_act;
135
0
}
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
0
{
147
0
  struct MHD_Action *const head_act = mhd_REQ_GET_ACT_HEAD (request);
148
149
0
  if (mhd_ACTION_NO_ACTION != head_act->act)
150
0
    return (const struct MHD_Action *) NULL;
151
152
0
  if (0 == large_buffer_size)
153
0
  {
154
0
    if (NULL != uc_full)
155
0
      return (const struct MHD_Action *) NULL;
156
0
    if (NULL == uc_inc)
157
0
      return (const struct MHD_Action *) NULL;
158
0
  }
159
0
  else
160
0
  {
161
0
    if (NULL == uc_full)
162
0
      return (const struct MHD_Action *) NULL;
163
0
  }
164
165
0
  head_act->act = mhd_ACTION_UPLOAD;
166
0
  head_act->data.upload.large_buffer_size = large_buffer_size;
167
0
  head_act->data.upload.full.cb = uc_full;
168
0
  head_act->data.upload.full.cls = uc_full_cls;
169
0
  head_act->data.upload.inc.cb = uc_inc;
170
0
  head_act->data.upload.inc.cls = uc_inc_cls;
171
172
0
  return head_act;
173
0
}
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
0
{
187
0
#ifdef MHD_SUPPORT_POST_PARSER
188
0
  struct MHD_Action *const head_act = mhd_REQ_GET_ACT_HEAD (request);
189
190
0
  if (mhd_ACTION_NO_ACTION != head_act->act)
191
0
    return (const struct MHD_Action *) NULL;
192
193
0
  if (NULL == done_cb)
194
0
    return (const struct MHD_Action *) NULL;
195
196
0
  head_act->act = mhd_ACTION_POST_PARSE;
197
0
  head_act->data.post_parse.buffer_size = buffer_size;
198
0
  head_act->data.post_parse.max_nonstream_size = max_nonstream_size;
199
0
  head_act->data.post_parse.enc = enc;
200
0
  head_act->data.post_parse.stream_reader = stream_reader;
201
0
  head_act->data.post_parse.reader_cls = reader_cls;
202
0
  head_act->data.post_parse.done_cb = done_cb;
203
0
  head_act->data.post_parse.done_cb_cls = done_cb_cls;
204
205
0
  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
0
}
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
0
{
228
0
  struct MHD_Action *const restrict head_act =
229
0
    &(request->app_act.head_act);
230
231
0
  if (mhd_REQ_IS_HTTP2 (request))
232
0
    return (const struct MHD_Action *) NULL;
233
0
  if (mhd_ACTION_NO_ACTION != head_act->act)
234
0
    return (const struct MHD_Action *) NULL;
235
0
  if (NULL == upgrade_handler)
236
0
    return (const struct MHD_Action *) NULL;
237
0
  if (request->cntn.cntn_size != request->cntn.recv_size)
238
0
    return (const struct MHD_Action *) NULL; /* Cannot start "Upgrade" if any content upload is pending */
239
240
0
  if (! mhd_upgrade_prep_for_action (request,
241
0
                                     upgrade_hdr_value,
242
0
                                     num_headers,
243
0
                                     headers,
244
0
                                     false))
245
0
    return (const struct MHD_Action *) NULL;
246
247
0
  head_act->act = mhd_ACTION_UPGRADE;
248
0
  head_act->data.upgrd.cb = upgrade_handler;
249
0
  head_act->data.upgrd.cb_cls = upgrade_handler_cls;
250
251
0
  return head_act;
252
0
}
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
0
{
267
0
  struct MHD_UploadAction *const restrict upl_act =
268
0
    &(request->app_act.upl_act);
269
270
0
  if (mhd_REQ_IS_HTTP2 (request))
271
0
    return (const struct MHD_UploadAction *) NULL;
272
0
  if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act)
273
0
    return (const struct MHD_UploadAction *) NULL;
274
0
  if (NULL == upgrade_handler)
275
0
    return (const struct MHD_UploadAction *) NULL;
276
0
  if (request->cntn.cntn_size != request->cntn.recv_size)
277
0
    return (const struct MHD_UploadAction *) NULL; /* Cannot start "Upgrade" if any content upload is pending */
278
279
0
  if (! mhd_upgrade_prep_for_action (request,
280
0
                                     upgrade_hdr_value,
281
0
                                     num_headers,
282
0
                                     headers,
283
0
                                     true))
284
0
    return (const struct MHD_UploadAction *) NULL;
285
286
0
  upl_act->act = mhd_UPLOAD_ACTION_UPGRADE;
287
0
  upl_act->data.upgrd.cb = upgrade_handler;
288
0
  upl_act->data.upgrd.cb_cls = upgrade_handler_cls;
289
290
0
  return upl_act;
291
0
}
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
0
{
301
0
  struct MHD_UploadAction *const upl_act = mhd_REQ_GET_ACT_UPLD (request);
302
0
  if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act)
303
0
    return (const struct MHD_UploadAction *) NULL;
304
305
0
  upl_act->act = mhd_UPLOAD_ACTION_SUSPEND;
306
307
0
  return upl_act;
308
0
}
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
0
{
316
0
  struct MHD_UploadAction *const upl_act = mhd_REQ_GET_ACT_UPLD (request);
317
0
  if (NULL == response)
318
0
    return (const struct MHD_UploadAction *) NULL;
319
320
0
  mhd_response_check_frozen_freeze (response);
321
0
  mhd_response_inc_use_count (response);
322
323
0
#ifdef MHD_SUPPORT_HTTP2
324
0
  if (mhd_REQ_IS_HTTP2 (request))
325
0
  {
326
0
    if (! mhd_h2_act_is_resp_h2_compatible ((struct mhd_H2RequestData*) request,
327
0
                                            response))
328
0
    {
329
      /* Clean-up unused response */
330
0
      mhd_response_dec_use_count (response);
331
0
      return (const struct MHD_UploadAction *) NULL;
332
0
    }
333
0
  }
334
0
#endif /* MHD_SUPPORT_HTTP2 */
335
336
0
  if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act)
337
0
  {
338
    /* Clean-up unused response */
339
0
    mhd_response_dec_use_count (response);
340
0
    return (const struct MHD_UploadAction *) NULL;
341
0
  }
342
0
#ifdef MHD_SUPPORT_AUTH_DIGEST
343
0
  if (mhd_RESP_HAS_AUTH_DIGEST (response) &&
344
0
      ! mhd_D_HAS_AUTH_DIGEST ( \
345
0
        mhd_CNTNR_CPTR (request, struct MHD_Connection, rq)->daemon))
346
0
  {
347
    /* Clean-up unused response */
348
0
    mhd_response_dec_use_count (response);
349
    // TODO: get connection pointer for HTTP/2
350
0
    mhd_assert (! mhd_REQ_IS_HTTP2 (request));
351
0
    mhd_LOG_MSG (mhd_CNTNR_PTR (request, struct MHD_Connection, rq)->daemon, \
352
0
                 MHD_SC_AUTH_DIGEST_UNSUPPORTED, \
353
0
                 "Attempted to use a response with Digest Auth challenge on " \
354
0
                 "the daemon without enabled Digest Auth support");
355
0
    return (const struct MHD_UploadAction *) NULL;
356
0
  }
357
0
#endif /* MHD_SUPPORT_AUTH_DIGEST */
358
359
0
  upl_act->act = mhd_UPLOAD_ACTION_RESPONSE;
360
0
  upl_act->data.response = response;
361
362
0
  return upl_act;
363
0
}
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
0
{
370
0
  struct MHD_UploadAction *const upl_act = mhd_REQ_GET_ACT_UPLD (request);
371
0
  if (mhd_UPLOAD_ACTION_NO_ACTION != upl_act->act)
372
0
    return (const struct MHD_UploadAction *) NULL;
373
374
0
  upl_act->act = mhd_UPLOAD_ACTION_CONTINUE;
375
376
0
  return upl_act;
377
0
}