Coverage Report

Created: 2024-05-21 06:52

/src/curl/lib/dynhds.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
25
#include "curl_setup.h"
26
#include "dynhds.h"
27
#include "strcase.h"
28
29
/* The last 3 #include files should be in this order */
30
#ifdef USE_NGHTTP2
31
#include <stdint.h>
32
#include <nghttp2/nghttp2.h>
33
#endif /* USE_NGHTTP2 */
34
#include "curl_printf.h"
35
#include "curl_memory.h"
36
#include "memdebug.h"
37
38
39
static struct dynhds_entry *
40
entry_new(const char *name, size_t namelen,
41
          const char *value, size_t valuelen, int opts)
42
692k
{
43
692k
  struct dynhds_entry *e;
44
692k
  char *p;
45
46
692k
  DEBUGASSERT(name);
47
692k
  DEBUGASSERT(value);
48
692k
  e = calloc(1, sizeof(*e) + namelen + valuelen + 2);
49
692k
  if(!e)
50
0
    return NULL;
51
692k
  e->name = p = ((char *)e) + sizeof(*e);
52
692k
  memcpy(p, name, namelen);
53
692k
  e->namelen = namelen;
54
692k
  e->value = p += namelen + 1; /* leave a \0 at the end of name */
55
692k
  memcpy(p, value, valuelen);
56
692k
  e->valuelen = valuelen;
57
692k
  if(opts & DYNHDS_OPT_LOWERCASE)
58
363k
    Curl_strntolower(e->name, e->name, e->namelen);
59
692k
  return e;
60
692k
}
61
62
static struct dynhds_entry *
63
entry_append(struct dynhds_entry *e,
64
             const char *value, size_t valuelen)
65
7.71k
{
66
7.71k
  struct dynhds_entry *e2;
67
7.71k
  size_t valuelen2 = e->valuelen + 1 + valuelen;
68
7.71k
  char *p;
69
70
7.71k
  DEBUGASSERT(value);
71
7.71k
  e2 = calloc(1, sizeof(*e) + e->namelen + valuelen2 + 2);
72
7.71k
  if(!e2)
73
0
    return NULL;
74
7.71k
  e2->name = p = ((char *)e2) + sizeof(*e2);
75
7.71k
  memcpy(p, e->name, e->namelen);
76
7.71k
  e2->namelen = e->namelen;
77
7.71k
  e2->value = p += e->namelen + 1; /* leave a \0 at the end of name */
78
7.71k
  memcpy(p, e->value, e->valuelen);
79
7.71k
  p += e->valuelen;
80
7.71k
  p[0] = ' ';
81
7.71k
  memcpy(p + 1, value, valuelen);
82
7.71k
  e2->valuelen = valuelen2;
83
7.71k
  return e2;
84
7.71k
}
85
86
static void entry_free(struct dynhds_entry *e)
87
699k
{
88
699k
  free(e);
89
699k
}
90
91
void Curl_dynhds_init(struct dynhds *dynhds, size_t max_entries,
92
                      size_t max_strs_size)
93
54.1k
{
94
54.1k
  DEBUGASSERT(dynhds);
95
54.1k
  DEBUGASSERT(max_strs_size);
96
54.1k
  dynhds->hds = NULL;
97
54.1k
  dynhds->hds_len = dynhds->hds_allc = dynhds->strs_len = 0;
98
54.1k
  dynhds->max_entries = max_entries;
99
54.1k
  dynhds->max_strs_size = max_strs_size;
100
54.1k
  dynhds->opts = 0;
101
54.1k
}
102
103
void Curl_dynhds_free(struct dynhds *dynhds)
104
54.1k
{
105
54.1k
  DEBUGASSERT(dynhds);
106
54.1k
  if(dynhds->hds && dynhds->hds_len) {
107
26.6k
    size_t i;
108
26.6k
    DEBUGASSERT(dynhds->hds);
109
718k
    for(i = 0; i < dynhds->hds_len; ++i) {
110
692k
      entry_free(dynhds->hds[i]);
111
692k
    }
112
26.6k
  }
113
54.1k
  Curl_safefree(dynhds->hds);
114
54.1k
  dynhds->hds_len = dynhds->hds_allc = dynhds->strs_len = 0;
115
54.1k
}
116
117
void Curl_dynhds_reset(struct dynhds *dynhds)
118
13.3k
{
119
13.3k
  DEBUGASSERT(dynhds);
120
13.3k
  if(dynhds->hds_len) {
121
0
    size_t i;
122
0
    DEBUGASSERT(dynhds->hds);
123
0
    for(i = 0; i < dynhds->hds_len; ++i) {
124
0
      entry_free(dynhds->hds[i]);
125
0
      dynhds->hds[i] = NULL;
126
0
    }
127
0
  }
128
13.3k
  dynhds->hds_len = dynhds->strs_len = 0;
129
13.3k
}
130
131
size_t Curl_dynhds_count(struct dynhds *dynhds)
132
339k
{
133
339k
  return dynhds->hds_len;
134
339k
}
135
136
void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts)
137
13.3k
{
138
13.3k
  dynhds->opts = opts;
139
13.3k
}
140
141
struct dynhds_entry *Curl_dynhds_getn(struct dynhds *dynhds, size_t n)
142
325k
{
143
325k
  DEBUGASSERT(dynhds);
144
325k
  return (n < dynhds->hds_len)? dynhds->hds[n] : NULL;
145
325k
}
146
147
struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds, const char *name,
148
                                     size_t namelen)
149
13.2k
{
150
13.2k
  size_t i;
151
20.9k
  for(i = 0; i < dynhds->hds_len; ++i) {
152
20.7k
    if(dynhds->hds[i]->namelen == namelen &&
153
20.7k
       strncasecompare(dynhds->hds[i]->name, name, namelen)) {
154
13.0k
      return dynhds->hds[i];
155
13.0k
    }
156
20.7k
  }
157
198
  return NULL;
158
13.2k
}
159
160
struct dynhds_entry *Curl_dynhds_cget(struct dynhds *dynhds, const char *name)
161
0
{
162
0
  return Curl_dynhds_get(dynhds, name, strlen(name));
163
0
}
164
165
CURLcode Curl_dynhds_add(struct dynhds *dynhds,
166
                         const char *name, size_t namelen,
167
                         const char *value, size_t valuelen)
168
692k
{
169
692k
  struct dynhds_entry *entry = NULL;
170
692k
  CURLcode result = CURLE_OUT_OF_MEMORY;
171
172
692k
  DEBUGASSERT(dynhds);
173
692k
  if(dynhds->max_entries && dynhds->hds_len >= dynhds->max_entries)
174
0
    return CURLE_OUT_OF_MEMORY;
175
692k
  if(dynhds->strs_len + namelen + valuelen > dynhds->max_strs_size)
176
2
    return CURLE_OUT_OF_MEMORY;
177
178
692k
entry = entry_new(name, namelen, value, valuelen, dynhds->opts);
179
692k
  if(!entry)
180
0
    goto out;
181
182
692k
  if(dynhds->hds_len + 1 >= dynhds->hds_allc) {
183
64.1k
    size_t nallc = dynhds->hds_len + 16;
184
64.1k
    struct dynhds_entry **nhds;
185
186
64.1k
    if(dynhds->max_entries && nallc > dynhds->max_entries)
187
0
      nallc = dynhds->max_entries;
188
189
64.1k
    nhds = calloc(nallc, sizeof(struct dynhds_entry *));
190
64.1k
    if(!nhds)
191
0
      goto out;
192
64.1k
    if(dynhds->hds) {
193
37.5k
      memcpy(nhds, dynhds->hds,
194
37.5k
             dynhds->hds_len * sizeof(struct dynhds_entry *));
195
37.5k
      Curl_safefree(dynhds->hds);
196
37.5k
    }
197
64.1k
    dynhds->hds = nhds;
198
64.1k
    dynhds->hds_allc = nallc;
199
64.1k
  }
200
692k
  dynhds->hds[dynhds->hds_len++] = entry;
201
692k
  entry = NULL;
202
692k
  dynhds->strs_len += namelen + valuelen;
203
692k
  result = CURLE_OK;
204
205
692k
out:
206
692k
  if(entry)
207
0
    entry_free(entry);
208
692k
  return result;
209
692k
}
210
211
CURLcode Curl_dynhds_cadd(struct dynhds *dynhds,
212
                          const char *name, const char *value)
213
0
{
214
0
  return Curl_dynhds_add(dynhds, name, strlen(name), value, strlen(value));
215
0
}
216
217
CURLcode Curl_dynhds_h1_add_line(struct dynhds *dynhds,
218
                                 const char *line, size_t line_len)
219
334k
{
220
334k
  const char *p;
221
334k
  const char *name;
222
334k
  size_t namelen;
223
334k
  const char *value;
224
334k
  size_t valuelen, i;
225
226
334k
  if(!line || !line_len)
227
0
    return CURLE_OK;
228
229
334k
  if((line[0] == ' ') || (line[0] == '\t')) {
230
7.74k
    struct dynhds_entry *e, *e2;
231
    /* header continuation, yikes! */
232
7.74k
    if(!dynhds->hds_len)
233
13
      return CURLE_BAD_FUNCTION_ARGUMENT;
234
235
23.1k
    while(line_len && ISBLANK(line[0])) {
236
15.4k
      ++line;
237
15.4k
      --line_len;
238
15.4k
    }
239
7.72k
    if(!line_len)
240
11
      return CURLE_BAD_FUNCTION_ARGUMENT;
241
7.71k
    e = dynhds->hds[dynhds->hds_len-1];
242
7.71k
    e2 = entry_append(e, line, line_len);
243
7.71k
    if(!e2)
244
0
      return CURLE_OUT_OF_MEMORY;
245
7.71k
    dynhds->hds[dynhds->hds_len-1] = e2;
246
7.71k
    entry_free(e);
247
7.71k
    return CURLE_OK;
248
7.71k
  }
249
327k
  else {
250
327k
    p = memchr(line, ':', line_len);
251
327k
    if(!p)
252
24
      return CURLE_BAD_FUNCTION_ARGUMENT;
253
327k
    name = line;
254
327k
    namelen = p - line;
255
327k
    p++; /* move past the colon */
256
389k
    for(i = namelen + 1; i < line_len; ++i, ++p) {
257
300k
      if(!ISBLANK(*p))
258
238k
        break;
259
300k
    }
260
327k
    value = p;
261
327k
    valuelen = line_len - i;
262
263
327k
    p = memchr(value, '\r', valuelen);
264
327k
    if(!p)
265
312k
      p = memchr(value, '\n', valuelen);
266
327k
    if(p)
267
15.0k
      valuelen = (size_t)(p - value);
268
269
327k
    return Curl_dynhds_add(dynhds, name, namelen, value, valuelen);
270
327k
  }
271
334k
}
272
273
CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line)
274
0
{
275
0
  return Curl_dynhds_h1_add_line(dynhds, line, line? strlen(line) : 0);
276
0
}
277
278
#ifdef DEBUGBUILD
279
/* used by unit2602.c */
280
281
bool Curl_dynhds_contains(struct dynhds *dynhds,
282
                          const char *name, size_t namelen)
283
0
{
284
0
  return !!Curl_dynhds_get(dynhds, name, namelen);
285
0
}
286
287
bool Curl_dynhds_ccontains(struct dynhds *dynhds, const char *name)
288
0
{
289
0
  return Curl_dynhds_contains(dynhds, name, strlen(name));
290
0
}
291
292
size_t Curl_dynhds_count_name(struct dynhds *dynhds,
293
                              const char *name, size_t namelen)
294
0
{
295
0
  size_t n = 0;
296
0
  if(dynhds->hds_len) {
297
0
    size_t i;
298
0
    for(i = 0; i < dynhds->hds_len; ++i) {
299
0
      if((namelen == dynhds->hds[i]->namelen) &&
300
0
         strncasecompare(name, dynhds->hds[i]->name, namelen))
301
0
        ++n;
302
0
    }
303
0
  }
304
0
  return n;
305
0
}
306
307
size_t Curl_dynhds_ccount_name(struct dynhds *dynhds, const char *name)
308
0
{
309
0
  return Curl_dynhds_count_name(dynhds, name, strlen(name));
310
0
}
311
312
CURLcode Curl_dynhds_set(struct dynhds *dynhds,
313
                         const char *name, size_t namelen,
314
                         const char *value, size_t valuelen)
315
0
{
316
0
  Curl_dynhds_remove(dynhds, name, namelen);
317
0
  return Curl_dynhds_add(dynhds, name, namelen, value, valuelen);
318
0
}
319
320
size_t Curl_dynhds_remove(struct dynhds *dynhds,
321
                          const char *name, size_t namelen)
322
0
{
323
0
  size_t n = 0;
324
0
  if(dynhds->hds_len) {
325
0
    size_t i, len;
326
0
    for(i = 0; i < dynhds->hds_len; ++i) {
327
0
      if((namelen == dynhds->hds[i]->namelen) &&
328
0
         strncasecompare(name, dynhds->hds[i]->name, namelen)) {
329
0
        ++n;
330
0
        --dynhds->hds_len;
331
0
        dynhds->strs_len -= (dynhds->hds[i]->namelen +
332
0
                             dynhds->hds[i]->valuelen);
333
0
        entry_free(dynhds->hds[i]);
334
0
        len = dynhds->hds_len - i; /* remaining entries */
335
0
        if(len) {
336
0
          memmove(&dynhds->hds[i], &dynhds->hds[i + 1],
337
0
                  len * sizeof(dynhds->hds[i]));
338
0
        }
339
0
        --i; /* do this index again */
340
0
      }
341
0
    }
342
0
  }
343
0
  return n;
344
0
}
345
346
size_t Curl_dynhds_cremove(struct dynhds *dynhds, const char *name)
347
0
{
348
0
  return Curl_dynhds_remove(dynhds, name, strlen(name));
349
0
}
350
351
#endif
352
353
CURLcode Curl_dynhds_h1_dprint(struct dynhds *dynhds, struct dynbuf *dbuf)
354
0
{
355
0
  CURLcode result = CURLE_OK;
356
0
  size_t i;
357
358
0
  if(!dynhds->hds_len)
359
0
    return result;
360
361
0
  for(i = 0; i < dynhds->hds_len; ++i) {
362
0
    result = Curl_dyn_addf(dbuf, "%.*s: %.*s\r\n",
363
0
               (int)dynhds->hds[i]->namelen, dynhds->hds[i]->name,
364
0
               (int)dynhds->hds[i]->valuelen, dynhds->hds[i]->value);
365
0
    if(result)
366
0
      break;
367
0
  }
368
369
0
  return result;
370
0
}
371
372
#ifdef USE_NGHTTP2
373
374
nghttp2_nv *Curl_dynhds_to_nva(struct dynhds *dynhds, size_t *pcount)
375
13.3k
{
376
13.3k
  nghttp2_nv *nva = calloc(1, sizeof(nghttp2_nv) * dynhds->hds_len);
377
13.3k
  size_t i;
378
379
13.3k
  *pcount = 0;
380
13.3k
  if(!nva)
381
0
    return NULL;
382
383
376k
  for(i = 0; i < dynhds->hds_len; ++i) {
384
363k
    struct dynhds_entry *e = dynhds->hds[i];
385
363k
    DEBUGASSERT(e);
386
363k
    nva[i].name = (unsigned char *)e->name;
387
363k
    nva[i].namelen = e->namelen;
388
363k
    nva[i].value = (unsigned char *)e->value;
389
363k
    nva[i].valuelen = e->valuelen;
390
363k
    nva[i].flags = NGHTTP2_NV_FLAG_NONE;
391
363k
  }
392
13.3k
  *pcount = dynhds->hds_len;
393
13.3k
  return nva;
394
13.3k
}
395
396
#endif /* USE_NGHTTP2 */