Coverage Report

Created: 2024-02-25 06:14

/src/PROJ/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
0
{
43
0
  struct dynhds_entry *e;
44
0
  char *p;
45
46
0
  DEBUGASSERT(name);
47
0
  DEBUGASSERT(value);
48
0
  e = calloc(1, sizeof(*e) + namelen + valuelen + 2);
49
0
  if(!e)
50
0
    return NULL;
51
0
  e->name = p = ((char *)e) + sizeof(*e);
52
0
  memcpy(p, name, namelen);
53
0
  e->namelen = namelen;
54
0
  e->value = p += namelen + 1; /* leave a \0 at the end of name */
55
0
  memcpy(p, value, valuelen);
56
0
  e->valuelen = valuelen;
57
0
  if(opts & DYNHDS_OPT_LOWERCASE)
58
0
    Curl_strntolower(e->name, e->name, e->namelen);
59
0
  return e;
60
0
}
61
62
static struct dynhds_entry *
63
entry_append(struct dynhds_entry *e,
64
             const char *value, size_t valuelen)
65
0
{
66
0
  struct dynhds_entry *e2;
67
0
  size_t valuelen2 = e->valuelen + 1 + valuelen;
68
0
  char *p;
69
70
0
  DEBUGASSERT(value);
71
0
  e2 = calloc(1, sizeof(*e) + e->namelen + valuelen2 + 2);
72
0
  if(!e2)
73
0
    return NULL;
74
0
  e2->name = p = ((char *)e2) + sizeof(*e2);
75
0
  memcpy(p, e->name, e->namelen);
76
0
  e2->namelen = e->namelen;
77
0
  e2->value = p += e->namelen + 1; /* leave a \0 at the end of name */
78
0
  memcpy(p, e->value, e->valuelen);
79
0
  p += e->valuelen;
80
0
  p[0] = ' ';
81
0
  memcpy(p + 1, value, valuelen);
82
0
  e2->valuelen = valuelen2;
83
0
  return e2;
84
0
}
85
86
static void entry_free(struct dynhds_entry *e)
87
0
{
88
0
  free(e);
89
0
}
90
91
void Curl_dynhds_init(struct dynhds *dynhds, size_t max_entries,
92
                      size_t max_strs_size)
93
0
{
94
0
  DEBUGASSERT(dynhds);
95
0
  DEBUGASSERT(max_strs_size);
96
0
  dynhds->hds = NULL;
97
0
  dynhds->hds_len = dynhds->hds_allc = dynhds->strs_len = 0;
98
0
  dynhds->max_entries = max_entries;
99
0
  dynhds->max_strs_size = max_strs_size;
100
0
  dynhds->opts = 0;
101
0
}
102
103
void Curl_dynhds_free(struct dynhds *dynhds)
104
0
{
105
0
  DEBUGASSERT(dynhds);
106
0
  if(dynhds->hds && dynhds->hds_len) {
107
0
    size_t i;
108
0
    DEBUGASSERT(dynhds->hds);
109
0
    for(i = 0; i < dynhds->hds_len; ++i) {
110
0
      entry_free(dynhds->hds[i]);
111
0
    }
112
0
  }
113
0
  Curl_safefree(dynhds->hds);
114
0
  dynhds->hds_len = dynhds->hds_allc = dynhds->strs_len = 0;
115
0
}
116
117
void Curl_dynhds_reset(struct dynhds *dynhds)
118
0
{
119
0
  DEBUGASSERT(dynhds);
120
0
  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
0
  dynhds->hds_len = dynhds->strs_len = 0;
129
0
}
130
131
size_t Curl_dynhds_count(struct dynhds *dynhds)
132
0
{
133
0
  return dynhds->hds_len;
134
0
}
135
136
void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts)
137
0
{
138
0
  dynhds->opts = opts;
139
0
}
140
141
struct dynhds_entry *Curl_dynhds_getn(struct dynhds *dynhds, size_t n)
142
0
{
143
0
  DEBUGASSERT(dynhds);
144
0
  return (n < dynhds->hds_len)? dynhds->hds[n] : NULL;
145
0
}
146
147
struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds, const char *name,
148
                                     size_t namelen)
149
0
{
150
0
  size_t i;
151
0
  for(i = 0; i < dynhds->hds_len; ++i) {
152
0
    if(dynhds->hds[i]->namelen == namelen &&
153
0
       strncasecompare(dynhds->hds[i]->name, name, namelen)) {
154
0
      return dynhds->hds[i];
155
0
    }
156
0
  }
157
0
  return NULL;
158
0
}
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
0
{
169
0
  struct dynhds_entry *entry = NULL;
170
0
  CURLcode result = CURLE_OUT_OF_MEMORY;
171
172
0
  DEBUGASSERT(dynhds);
173
0
  if(dynhds->max_entries && dynhds->hds_len >= dynhds->max_entries)
174
0
    return CURLE_OUT_OF_MEMORY;
175
0
  if(dynhds->strs_len + namelen + valuelen > dynhds->max_strs_size)
176
0
    return CURLE_OUT_OF_MEMORY;
177
178
0
entry = entry_new(name, namelen, value, valuelen, dynhds->opts);
179
0
  if(!entry)
180
0
    goto out;
181
182
0
  if(dynhds->hds_len + 1 >= dynhds->hds_allc) {
183
0
    size_t nallc = dynhds->hds_len + 16;
184
0
    struct dynhds_entry **nhds;
185
186
0
    if(dynhds->max_entries && nallc > dynhds->max_entries)
187
0
      nallc = dynhds->max_entries;
188
189
0
    nhds = calloc(nallc, sizeof(struct dynhds_entry *));
190
0
    if(!nhds)
191
0
      goto out;
192
0
    if(dynhds->hds) {
193
0
      memcpy(nhds, dynhds->hds,
194
0
             dynhds->hds_len * sizeof(struct dynhds_entry *));
195
0
      Curl_safefree(dynhds->hds);
196
0
    }
197
0
    dynhds->hds = nhds;
198
0
    dynhds->hds_allc = nallc;
199
0
  }
200
0
  dynhds->hds[dynhds->hds_len++] = entry;
201
0
  entry = NULL;
202
0
  dynhds->strs_len += namelen + valuelen;
203
0
  result = CURLE_OK;
204
205
0
out:
206
0
  if(entry)
207
0
    entry_free(entry);
208
0
  return result;
209
0
}
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
0
{
220
0
  const char *p;
221
0
  const char *name;
222
0
  size_t namelen;
223
0
  const char *value;
224
0
  size_t valuelen, i;
225
226
0
  if(!line || !line_len)
227
0
    return CURLE_OK;
228
229
0
  if((line[0] == ' ') || (line[0] == '\t')) {
230
0
    struct dynhds_entry *e, *e2;
231
    /* header continuation, yikes! */
232
0
    if(!dynhds->hds_len)
233
0
      return CURLE_BAD_FUNCTION_ARGUMENT;
234
235
0
    while(line_len && ISBLANK(line[0])) {
236
0
      ++line;
237
0
      --line_len;
238
0
    }
239
0
    if(!line_len)
240
0
      return CURLE_BAD_FUNCTION_ARGUMENT;
241
0
    e = dynhds->hds[dynhds->hds_len-1];
242
0
    e2 = entry_append(e, line, line_len);
243
0
    if(!e2)
244
0
      return CURLE_OUT_OF_MEMORY;
245
0
    dynhds->hds[dynhds->hds_len-1] = e2;
246
0
    entry_free(e);
247
0
    return CURLE_OK;
248
0
  }
249
0
  else {
250
0
    p = memchr(line, ':', line_len);
251
0
    if(!p)
252
0
      return CURLE_BAD_FUNCTION_ARGUMENT;
253
0
    name = line;
254
0
    namelen = p - line;
255
0
    p++; /* move past the colon */
256
0
    for(i = namelen + 1; i < line_len; ++i, ++p) {
257
0
      if(!ISBLANK(*p))
258
0
        break;
259
0
    }
260
0
    value = p;
261
0
    valuelen = line_len - i;
262
263
0
    p = memchr(value, '\r', valuelen);
264
0
    if(!p)
265
0
      p = memchr(value, '\n', valuelen);
266
0
    if(p)
267
0
      valuelen = (size_t)(p - value);
268
269
0
    return Curl_dynhds_add(dynhds, name, namelen, value, valuelen);
270
0
  }
271
0
}
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
{
284
  return !!Curl_dynhds_get(dynhds, name, namelen);
285
}
286
287
bool Curl_dynhds_ccontains(struct dynhds *dynhds, const char *name)
288
{
289
  return Curl_dynhds_contains(dynhds, name, strlen(name));
290
}
291
292
size_t Curl_dynhds_count_name(struct dynhds *dynhds,
293
                              const char *name, size_t namelen)
294
{
295
  size_t n = 0;
296
  if(dynhds->hds_len) {
297
    size_t i;
298
    for(i = 0; i < dynhds->hds_len; ++i) {
299
      if((namelen == dynhds->hds[i]->namelen) &&
300
         strncasecompare(name, dynhds->hds[i]->name, namelen))
301
        ++n;
302
    }
303
  }
304
  return n;
305
}
306
307
size_t Curl_dynhds_ccount_name(struct dynhds *dynhds, const char *name)
308
{
309
  return Curl_dynhds_count_name(dynhds, name, strlen(name));
310
}
311
312
CURLcode Curl_dynhds_set(struct dynhds *dynhds,
313
                         const char *name, size_t namelen,
314
                         const char *value, size_t valuelen)
315
{
316
  Curl_dynhds_remove(dynhds, name, namelen);
317
  return Curl_dynhds_add(dynhds, name, namelen, value, valuelen);
318
}
319
320
size_t Curl_dynhds_remove(struct dynhds *dynhds,
321
                          const char *name, size_t namelen)
322
{
323
  size_t n = 0;
324
  if(dynhds->hds_len) {
325
    size_t i, len;
326
    for(i = 0; i < dynhds->hds_len; ++i) {
327
      if((namelen == dynhds->hds[i]->namelen) &&
328
         strncasecompare(name, dynhds->hds[i]->name, namelen)) {
329
        ++n;
330
        --dynhds->hds_len;
331
        dynhds->strs_len -= (dynhds->hds[i]->namelen +
332
                             dynhds->hds[i]->valuelen);
333
        entry_free(dynhds->hds[i]);
334
        len = dynhds->hds_len - i; /* remaining entries */
335
        if(len) {
336
          memmove(&dynhds->hds[i], &dynhds->hds[i + 1],
337
                  len * sizeof(dynhds->hds[i]));
338
        }
339
        --i; /* do this index again */
340
      }
341
    }
342
  }
343
  return n;
344
}
345
346
size_t Curl_dynhds_cremove(struct dynhds *dynhds, const char *name)
347
{
348
  return Curl_dynhds_remove(dynhds, name, strlen(name));
349
}
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
{
376
  nghttp2_nv *nva = calloc(1, sizeof(nghttp2_nv) * dynhds->hds_len);
377
  size_t i;
378
379
  *pcount = 0;
380
  if(!nva)
381
    return NULL;
382
383
  for(i = 0; i < dynhds->hds_len; ++i) {
384
    struct dynhds_entry *e = dynhds->hds[i];
385
    DEBUGASSERT(e);
386
    nva[i].name = (unsigned char *)e->name;
387
    nva[i].namelen = e->namelen;
388
    nva[i].value = (unsigned char *)e->value;
389
    nva[i].valuelen = e->valuelen;
390
    nva[i].flags = NGHTTP2_NV_FLAG_NONE;
391
  }
392
  *pcount = dynhds->hds_len;
393
  return nva;
394
}
395
396
#endif /* USE_NGHTTP2 */