Coverage Report

Created: 2026-03-08 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mhd2/src/mhd2/request_get_value.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 Christian Grothoff
5
  Copyright (C) 2024 Evgeny Grin (Karlson2k)
6
7
  GNU libmicrohttpd is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public
9
  License as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
12
  GNU libmicrohttpd is distributed in the hope that it will be useful,
13
  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
  Lesser General Public License for more details.
16
17
  Alternatively, you can redistribute GNU libmicrohttpd and/or
18
  modify it under the terms of the GNU General Public License as
19
  published by the Free Software Foundation; either version 2 of
20
  the License, or (at your option) any later version, together
21
  with the eCos exception, as follows:
22
23
    As a special exception, if other files instantiate templates or
24
    use macros or inline functions from this file, or you compile this
25
    file and link it with other works to produce a work based on this
26
    file, this file does not by itself cause the resulting work to be
27
    covered by the GNU General Public License. However the source code
28
    for this file must still be made available in accordance with
29
    section (3) of the GNU General Public License v2.
30
31
    This exception does not invalidate any other reasons why a work
32
    based on this file might be covered by the GNU General Public
33
    License.
34
35
  You should have received copies of the GNU Lesser General Public
36
  License and the GNU General Public License along with this library;
37
  if not, see <https://www.gnu.org/licenses/>.
38
*/
39
40
/**
41
 * @file src/mhd2/request_get_value.c
42
 * @brief  The implementation of MHD_request_get_value*() functions
43
 * @author Karlson2k (Evgeny Grin)
44
 */
45
46
#include "mhd_sys_options.h"
47
#include "request_get_value.h"
48
#include "sys_base_types.h"
49
#include <string.h>
50
51
#include "mhd_request.h"
52
53
#include "mhd_connection.h"
54
55
#include "mhd_dlinked_list.h"
56
#include "mhd_assert.h"
57
#include "mhd_str.h"
58
59
#ifdef MHD_SUPPORT_HTTP2
60
#  include "h2/h2_req_get_items.h"
61
#endif /* MHD_SUPPORT_HTTP2 */
62
63
#include "mhd_public_api.h"
64
65
66
MHD_INTERNAL
67
MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_IN_SIZE_ (4,3)
68
MHD_FN_PAR_NONNULL_ (4) MHD_FN_PAR_CSTR_ (4)
69
MHD_FN_PAR_OUT_ (5) bool
70
mhd_request_get_value_n (struct MHD_Request *restrict request,
71
                         enum MHD_ValueKind kind,
72
                         size_t key_len,
73
                         const char *restrict key,
74
                         struct MHD_StringNullable *restrict value_out)
75
2.85k
{
76
2.85k
  mhd_assert (strlen (key) == key_len);
77
2.85k
  value_out->len = 0u;
78
2.85k
  value_out->cstr = NULL;
79
80
2.85k
  mhd_assert (strlen (key) == key_len);
81
82
2.85k
#ifdef MHD_SUPPORT_HTTP2
83
2.85k
  if (mhd_REQ_IS_HTTP2 (request))
84
0
    return mhd_h2_request_get_value_n (request,
85
0
                                       kind,
86
0
                                       key_len,
87
0
                                       key,
88
0
                                       value_out);
89
2.85k
#endif /* MHD_SUPPORT_HTTP2 */
90
91
2.85k
  if (MHD_VK_POSTDATA != kind)
92
2.85k
  {
93
2.85k
    struct mhd_RequestField *f;
94
95
5.96k
    for (f = mhd_DLINKEDL_GET_FIRST (request, fields); NULL != f;
96
3.10k
         f = mhd_DLINKEDL_GET_NEXT (f, fields))
97
5.54k
    {
98
5.54k
      if ((key_len == f->field.nv.name.len) &&
99
2.44k
          (0 != (kind & f->field.kind)) &&
100
2.44k
          mhd_str_equal_caseless_bin_n (key,
101
2.44k
                                        f->field.nv.name.cstr,
102
2.44k
                                        key_len))
103
2.44k
      {
104
2.44k
        *value_out = f->field.nv.value;
105
2.44k
        return true;
106
2.44k
      }
107
5.54k
    }
108
2.85k
  }
109
110
417
#if MHD_SUPPORT_POST_PARSER
111
417
  if (0 != (MHD_VK_POSTDATA & kind))
112
0
  {
113
0
    struct mhd_RequestPostField *f;
114
0
    char *const buf = request->cntn.lbuf.data; // TODO: support processing in connection buffer
115
0
    for (f = mhd_DLINKEDL_GET_FIRST (request, post_fields); NULL != f;
116
0
         f = mhd_DLINKEDL_GET_NEXT (f, post_fields))
117
0
    {
118
0
      if ((key_len == f->field.name.len) &&
119
0
          mhd_str_equal_caseless_bin_n (key,
120
0
                                        buf + f->field.name.pos,
121
0
                                        key_len))
122
0
      {
123
0
        value_out->cstr =
124
0
          (0 == f->field.value.pos) ?
125
0
          NULL : (buf + f->field.value.pos);
126
0
        value_out->len = f->field.value.len;
127
128
0
        mhd_assert ((NULL != value_out->cstr) || \
129
0
                    (0 == value_out->len));
130
131
0
        return true;
132
0
      }
133
0
    }
134
0
  }
135
417
#endif /* MHD_SUPPORT_POST_PARSER */
136
137
417
  return false;
138
417
}
139
140
141
MHD_EXTERN_
142
MHD_FN_PAR_NONNULL_ (1)
143
MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_CSTR_ (3)
144
MHD_FN_PAR_OUT_ (4) enum MHD_Bool
145
MHD_request_get_value (struct MHD_Request *MHD_RESTRICT request,
146
                       enum MHD_ValueKind kind,
147
                       const char *MHD_RESTRICT key,
148
                       struct MHD_StringNullable *MHD_RESTRICT value_out)
149
0
{
150
0
  size_t len;
151
0
  len = strlen (key);
152
0
  return mhd_request_get_value_n (request,
153
0
                                  kind,
154
0
                                  len,
155
0
                                  key,
156
0
                                  value_out) ? MHD_YES : MHD_NO;
157
0
}
158
159
160
MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
161
MHD_FN_PAR_CSTR_ (3)
162
MHD_FN_PAR_CSTR_ (5) bool
163
mhd_stream_has_header_token (const struct MHD_Connection *restrict c,
164
                             size_t header_len,
165
                             const char *restrict header,
166
                             size_t token_len,
167
                             const char *restrict token)
168
0
{
169
0
  struct mhd_RequestField *f;
170
171
0
  mhd_assert (mhd_HTTP_STAGE_START_REPLY >= c->stage);
172
173
0
  for (f = mhd_DLINKEDL_GET_FIRST (&(c->rq), fields);
174
0
       NULL != f;
175
0
       f = mhd_DLINKEDL_GET_NEXT (f, fields))
176
0
  {
177
0
    if ((MHD_VK_HEADER == f->field.kind) &&
178
0
        (header_len == f->field.nv.name.len) &&
179
0
        (mhd_str_equal_caseless_bin_n (header,
180
0
                                       f->field.nv.name.cstr,
181
0
                                       header_len)) &&
182
0
        (mhd_str_has_token_caseless (f->field.nv.value.cstr,
183
0
                                     token,
184
0
                                     token_len)))
185
0
      return true;
186
0
  }
187
188
0
  return false;
189
0
}
190
191
192
MHD_EXTERN_
193
MHD_FN_PAR_NONNULL_ (1) size_t
194
MHD_request_get_values_cb (struct MHD_Request *request,
195
                           enum MHD_ValueKind kind,
196
                           MHD_NameValueIterator iterator,
197
                           void *iterator_cls)
198
0
{
199
0
  size_t count;
200
201
0
  #ifdef MHD_SUPPORT_HTTP2
202
0
  if (mhd_REQ_IS_HTTP2 (request))
203
0
    return mhd_h2_request_get_values_cb (request,
204
0
                                         kind,
205
0
                                         iterator,
206
0
                                         iterator_cls);
207
0
#endif /* MHD_SUPPORT_HTTP2 */
208
209
0
  count = 0;
210
0
  if (MHD_VK_POSTDATA != kind)
211
0
  {
212
0
    struct mhd_RequestField *f;
213
214
0
    for (f = mhd_DLINKEDL_GET_FIRST (request, fields); NULL != f;
215
0
         f = mhd_DLINKEDL_GET_NEXT (f, fields))
216
0
    {
217
0
      if (0 == (kind & f->field.kind))
218
0
        continue;
219
220
0
      ++count;
221
0
      if (NULL != iterator)
222
0
      {
223
0
        if (MHD_NO ==
224
0
            iterator (iterator_cls,
225
0
                      f->field.kind,
226
0
                      &(f->field.nv)))
227
0
          return count;
228
0
      }
229
0
    }
230
0
  }
231
232
0
#if MHD_SUPPORT_POST_PARSER
233
0
  if (0 != (MHD_VK_POSTDATA & kind))
234
0
  {
235
0
    struct mhd_RequestPostField *f;
236
0
    char *const buf = request->cntn.lbuf.data; // TODO: support processing in connection buffer
237
0
    for (f = mhd_DLINKEDL_GET_FIRST (request, post_fields); NULL != f;
238
0
         f = mhd_DLINKEDL_GET_NEXT (f, post_fields))
239
0
    {
240
0
      ++count;
241
0
      if (NULL != iterator)
242
0
      {
243
0
        struct MHD_NameAndValue field;
244
245
0
        field.name.cstr = buf + f->field.name.pos;
246
0
        field.name.len = f->field.name.len;
247
0
        field.value.cstr =
248
0
          (0 == f->field.value.pos) ? NULL : (buf + f->field.value.pos);
249
0
        field.value.len = f->field.value.len;
250
251
0
        if (MHD_NO ==
252
0
            iterator (iterator_cls,
253
0
                      MHD_VK_POSTDATA,
254
0
                      &field))
255
0
          return count;
256
0
      }
257
0
    }
258
0
  }
259
0
#endif /* MHD_SUPPORT_POST_PARSER */
260
261
0
  return count;
262
0
}
263
264
265
#if MHD_SUPPORT_POST_PARSER
266
267
MHD_EXTERN_
268
MHD_FN_PAR_NONNULL_ (1) size_t
269
MHD_request_get_post_data_cb (struct MHD_Request *request,
270
                              MHD_PostDataIterator iterator,
271
                              void *iterator_cls)
272
0
{
273
0
  struct mhd_RequestPostField *f;
274
0
  char *const buf = request->cntn.lbuf.data; // TODO: support processing in connection buffer
275
0
  size_t count;
276
277
0
  count = 0;
278
0
  for (f = mhd_DLINKEDL_GET_FIRST (request, post_fields); NULL != f;
279
0
       f = mhd_DLINKEDL_GET_NEXT (f, post_fields))
280
0
  {
281
0
    ++count;
282
0
    if (NULL != iterator)
283
0
    {
284
0
      struct MHD_PostField field;
285
286
0
      field.name.cstr = buf + f->field.name.pos;
287
0
      field.name.len = f->field.name.len;
288
0
      if (0 == f->field.value.pos)
289
0
        field.value.cstr = NULL;
290
0
      else
291
0
        field.value.cstr = buf + f->field.value.pos;
292
0
      field.value.len = f->field.value.len;
293
294
0
      if (0 == f->field.filename.pos)
295
0
        field.filename.cstr = NULL;
296
0
      else
297
0
        field.filename.cstr = buf + f->field.filename.pos;
298
0
      field.filename.len = f->field.filename.len;
299
300
0
      if (0 == f->field.content_type.pos)
301
0
        field.content_type.cstr = NULL;
302
0
      else
303
0
        field.content_type.cstr = buf + f->field.content_type.pos;
304
0
      field.content_type.len = f->field.content_type.len;
305
306
0
      if (0 == f->field.transfer_encoding.pos)
307
0
        field.transfer_encoding.cstr = NULL;
308
0
      else
309
0
        field.transfer_encoding.cstr = buf + f->field.transfer_encoding.pos;
310
0
      field.transfer_encoding.len = f->field.transfer_encoding.len;
311
312
0
      mhd_assert ((NULL != field.value.cstr) || (0 == field.value.len));
313
0
      mhd_assert ((NULL != field.filename.cstr) || (0 == field.filename.len));
314
0
      mhd_assert ((NULL != field.content_type.cstr) || \
315
0
                  (0 == field.content_type.len));
316
0
      mhd_assert ((NULL != field.transfer_encoding.cstr) || \
317
0
                  (0 == field.transfer_encoding.len));
318
319
0
      if (MHD_NO ==
320
0
          iterator (iterator_cls,
321
0
                    &field))
322
0
        return count;
323
0
    }
324
0
  }
325
0
  return count;
326
0
}
327
328
329
#endif /* MHD_SUPPORT_POST_PARSER */