/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 | } |