Coverage Report

Created: 2023-06-07 07:02

/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
#include "curl_printf.h"
31
#include "curl_memory.h"
32
#include "memdebug.h"
33
34
35
static struct dynhds_entry *
36
entry_new(const char *name, size_t namelen,
37
          const char *value, size_t valuelen, int opts)
38
0
{
39
0
  struct dynhds_entry *e;
40
0
  char *p;
41
42
0
  DEBUGASSERT(name);
43
0
  DEBUGASSERT(value);
44
0
  e = calloc(1, sizeof(*e) + namelen + valuelen + 2);
45
0
  if(!e)
46
0
    return NULL;
47
0
  e->name = p = ((char *)e) + sizeof(*e);
48
0
  memcpy(p, name, namelen);
49
0
  e->namelen = namelen;
50
0
  e->value = p += namelen + 1; /* leave a \0 at the end of name */
51
0
  memcpy(p, value, valuelen);
52
0
  e->valuelen = valuelen;
53
0
  if(opts & DYNHDS_OPT_LOWERCASE)
54
0
    Curl_strntolower(e->name, e->name, e->namelen);
55
0
  return e;
56
0
}
57
58
static struct dynhds_entry *
59
entry_append(struct dynhds_entry *e,
60
             const char *value, size_t valuelen)
61
0
{
62
0
  struct dynhds_entry *e2;
63
0
  size_t valuelen2 = e->valuelen + 1 + valuelen;
64
0
  char *p;
65
66
0
  DEBUGASSERT(value);
67
0
  e2 = calloc(1, sizeof(*e) + e->namelen + valuelen2 + 2);
68
0
  if(!e2)
69
0
    return NULL;
70
0
  e2->name = p = ((char *)e2) + sizeof(*e2);
71
0
  memcpy(p, e->name, e->namelen);
72
0
  e2->namelen = e->namelen;
73
0
  e2->value = p += e->namelen + 1; /* leave a \0 at the end of name */
74
0
  memcpy(p, e->value, e->valuelen);
75
0
  p += e->valuelen;
76
0
  p[0] = ' ';
77
0
  memcpy(p + 1, value, valuelen);
78
0
  e2->valuelen = valuelen2;
79
0
  return e2;
80
0
}
81
82
static void entry_free(struct dynhds_entry *e)
83
0
{
84
0
  free(e);
85
0
}
86
87
void Curl_dynhds_init(struct dynhds *dynhds, size_t max_entries,
88
                      size_t max_strs_size)
89
0
{
90
0
  DEBUGASSERT(dynhds);
91
0
  DEBUGASSERT(max_strs_size);
92
0
  dynhds->hds = NULL;
93
0
  dynhds->hds_len = dynhds->hds_allc = dynhds->strs_len = 0;
94
0
  dynhds->max_entries = max_entries;
95
0
  dynhds->max_strs_size = max_strs_size;
96
0
  dynhds->opts = 0;
97
0
}
98
99
void Curl_dynhds_free(struct dynhds *dynhds)
100
0
{
101
0
  DEBUGASSERT(dynhds);
102
0
  if(dynhds->hds && dynhds->hds_len) {
103
0
    size_t i;
104
0
    DEBUGASSERT(dynhds->hds);
105
0
    for(i = 0; i < dynhds->hds_len; ++i) {
106
0
      entry_free(dynhds->hds[i]);
107
0
    }
108
0
  }
109
0
  Curl_safefree(dynhds->hds);
110
0
  dynhds->hds_len = dynhds->hds_allc = dynhds->strs_len = 0;
111
0
}
112
113
void Curl_dynhds_reset(struct dynhds *dynhds)
114
0
{
115
0
  DEBUGASSERT(dynhds);
116
0
  if(dynhds->hds_len) {
117
0
    size_t i;
118
0
    DEBUGASSERT(dynhds->hds);
119
0
    for(i = 0; i < dynhds->hds_len; ++i) {
120
0
      entry_free(dynhds->hds[i]);
121
0
      dynhds->hds[i] = NULL;
122
0
    }
123
0
  }
124
0
  dynhds->hds_len = dynhds->strs_len = 0;
125
0
}
126
127
size_t Curl_dynhds_count(struct dynhds *dynhds)
128
0
{
129
0
  return dynhds->hds_len;
130
0
}
131
132
void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts)
133
0
{
134
0
  dynhds->opts = opts;
135
0
}
136
137
struct dynhds_entry *Curl_dynhds_getn(struct dynhds *dynhds, size_t n)
138
0
{
139
0
  DEBUGASSERT(dynhds);
140
0
  return (n < dynhds->hds_len)? dynhds->hds[n] : NULL;
141
0
}
142
143
struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds, const char *name,
144
                                     size_t namelen)
145
0
{
146
0
  size_t i;
147
0
  for(i = 0; i < dynhds->hds_len; ++i) {
148
0
    if(dynhds->hds[i]->namelen == namelen &&
149
0
       strncasecompare(dynhds->hds[i]->name, name, namelen)) {
150
0
      return dynhds->hds[i];
151
0
    }
152
0
  }
153
0
  return NULL;
154
0
}
155
156
struct dynhds_entry *Curl_dynhds_cget(struct dynhds *dynhds, const char *name)
157
0
{
158
0
  return Curl_dynhds_get(dynhds, name, strlen(name));
159
0
}
160
161
CURLcode Curl_dynhds_add(struct dynhds *dynhds,
162
                         const char *name, size_t namelen,
163
                         const char *value, size_t valuelen)
164
0
{
165
0
  struct dynhds_entry *entry = NULL;
166
0
  CURLcode result = CURLE_OUT_OF_MEMORY;
167
168
0
  DEBUGASSERT(dynhds);
169
0
  if(dynhds->max_entries && dynhds->hds_len >= dynhds->max_entries)
170
0
    return CURLE_OUT_OF_MEMORY;
171
0
  if(dynhds->strs_len + namelen + valuelen > dynhds->max_strs_size)
172
0
    return CURLE_OUT_OF_MEMORY;
173
174
0
entry = entry_new(name, namelen, value, valuelen, dynhds->opts);
175
0
  if(!entry)
176
0
    goto out;
177
178
0
  if(dynhds->hds_len + 1 >= dynhds->hds_allc) {
179
0
    size_t nallc = dynhds->hds_len + 16;
180
0
    struct dynhds_entry **nhds;
181
182
0
    if(dynhds->max_entries && nallc > dynhds->max_entries)
183
0
      nallc = dynhds->max_entries;
184
185
0
    nhds = calloc(nallc, sizeof(struct dynhds_entry *));
186
0
    if(!nhds)
187
0
      goto out;
188
0
    if(dynhds->hds) {
189
0
      memcpy(nhds, dynhds->hds,
190
0
             dynhds->hds_len * sizeof(struct dynhds_entry *));
191
0
      Curl_safefree(dynhds->hds);
192
0
    }
193
0
    dynhds->hds = nhds;
194
0
    dynhds->hds_allc = nallc;
195
0
  }
196
0
  dynhds->hds[dynhds->hds_len++] = entry;
197
0
  entry = NULL;
198
0
  dynhds->strs_len += namelen + valuelen;
199
0
  result = CURLE_OK;
200
201
0
out:
202
0
  if(entry)
203
0
    entry_free(entry);
204
0
  return result;
205
0
}
206
207
CURLcode Curl_dynhds_cadd(struct dynhds *dynhds,
208
                          const char *name, const char *value)
209
0
{
210
0
  return Curl_dynhds_add(dynhds, name, strlen(name), value, strlen(value));
211
0
}
212
213
CURLcode Curl_dynhds_h1_add_line(struct dynhds *dynhds,
214
                                 const char *line, size_t line_len)
215
0
{
216
0
  const char *p;
217
0
  const char *name;
218
0
  size_t namelen;
219
0
  const char *value;
220
0
  size_t valuelen, i;
221
222
0
  if(!line || !line_len)
223
0
    return CURLE_OK;
224
225
0
  if((line[0] == ' ') || (line[0] == '\t')) {
226
0
    struct dynhds_entry *e, *e2;
227
    /* header continuation, yikes! */
228
0
    if(!dynhds->hds_len)
229
0
      return CURLE_BAD_FUNCTION_ARGUMENT;
230
231
0
    while(line_len && ISBLANK(line[0])) {
232
0
      ++line;
233
0
      --line_len;
234
0
    }
235
0
    if(!line_len)
236
0
      return CURLE_BAD_FUNCTION_ARGUMENT;
237
0
    e = dynhds->hds[dynhds->hds_len-1];
238
0
    e2 = entry_append(e, line, line_len);
239
0
    if(!e2)
240
0
      return CURLE_OUT_OF_MEMORY;
241
0
    dynhds->hds[dynhds->hds_len-1] = e2;
242
0
    entry_free(e);
243
0
    return CURLE_OK;
244
0
  }
245
0
  else {
246
0
    p = memchr(line, ':', line_len);
247
0
    if(!p)
248
0
      return CURLE_BAD_FUNCTION_ARGUMENT;
249
0
    name = line;
250
0
    namelen = p - line;
251
0
    p++; /* move past the colon */
252
0
    for(i = namelen + 1; i < line_len; ++i, ++p) {
253
0
      if(!ISBLANK(*p))
254
0
        break;
255
0
    }
256
0
    value = p;
257
0
    valuelen = line_len - i;
258
259
0
    p = memchr(value, '\r', valuelen);
260
0
    if(!p)
261
0
      p = memchr(value, '\n', valuelen);
262
0
    if(p)
263
0
      valuelen = (size_t)(p - value);
264
265
0
    return Curl_dynhds_add(dynhds, name, namelen, value, valuelen);
266
0
  }
267
0
}
268
269
CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line)
270
0
{
271
0
  return Curl_dynhds_h1_add_line(dynhds, line, line? strlen(line) : 0);
272
0
}
273
274
#ifdef DEBUGBUILD
275
/* used by unit2602.c */
276
277
bool Curl_dynhds_contains(struct dynhds *dynhds,
278
                          const char *name, size_t namelen)
279
0
{
280
0
  return !!Curl_dynhds_get(dynhds, name, namelen);
281
0
}
282
283
bool Curl_dynhds_ccontains(struct dynhds *dynhds, const char *name)
284
0
{
285
0
  return Curl_dynhds_contains(dynhds, name, strlen(name));
286
0
}
287
288
size_t Curl_dynhds_count_name(struct dynhds *dynhds,
289
                              const char *name, size_t namelen)
290
0
{
291
0
  size_t n = 0;
292
0
  if(dynhds->hds_len) {
293
0
    size_t i;
294
0
    for(i = 0; i < dynhds->hds_len; ++i) {
295
0
      if((namelen == dynhds->hds[i]->namelen) &&
296
0
         strncasecompare(name, dynhds->hds[i]->name, namelen))
297
0
        ++n;
298
0
    }
299
0
  }
300
0
  return n;
301
0
}
302
303
size_t Curl_dynhds_ccount_name(struct dynhds *dynhds, const char *name)
304
0
{
305
0
  return Curl_dynhds_count_name(dynhds, name, strlen(name));
306
0
}
307
308
CURLcode Curl_dynhds_set(struct dynhds *dynhds,
309
                         const char *name, size_t namelen,
310
                         const char *value, size_t valuelen)
311
0
{
312
0
  Curl_dynhds_remove(dynhds, name, namelen);
313
0
  return Curl_dynhds_add(dynhds, name, namelen, value, valuelen);
314
0
}
315
316
size_t Curl_dynhds_remove(struct dynhds *dynhds,
317
                          const char *name, size_t namelen)
318
0
{
319
0
  size_t n = 0;
320
0
  if(dynhds->hds_len) {
321
0
    size_t i, len;
322
0
    for(i = 0; i < dynhds->hds_len; ++i) {
323
0
      if((namelen == dynhds->hds[i]->namelen) &&
324
0
         strncasecompare(name, dynhds->hds[i]->name, namelen)) {
325
0
        ++n;
326
0
        --dynhds->hds_len;
327
0
        dynhds->strs_len -= (dynhds->hds[i]->namelen +
328
0
                             dynhds->hds[i]->valuelen);
329
0
        entry_free(dynhds->hds[i]);
330
0
        len = dynhds->hds_len - i; /* remaining entries */
331
0
        if(len) {
332
0
          memmove(&dynhds->hds[i], &dynhds->hds[i + 1],
333
0
                  len * sizeof(dynhds->hds[i]));
334
0
        }
335
0
        --i; /* do this index again */
336
0
      }
337
0
    }
338
0
  }
339
0
  return n;
340
0
}
341
342
size_t Curl_dynhds_cremove(struct dynhds *dynhds, const char *name)
343
0
{
344
0
  return Curl_dynhds_remove(dynhds, name, strlen(name));
345
0
}
346
347
CURLcode Curl_dynhds_h1_dprint(struct dynhds *dynhds, struct dynbuf *dbuf)
348
0
{
349
0
  CURLcode result = CURLE_OK;
350
0
  size_t i;
351
352
0
  if(!dynhds->hds_len)
353
0
    return result;
354
355
0
  for(i = 0; i < dynhds->hds_len; ++i) {
356
0
    result = Curl_dyn_addf(dbuf, "%.*s: %.*s\r\n",
357
0
               (int)dynhds->hds[i]->namelen, dynhds->hds[i]->name,
358
0
               (int)dynhds->hds[i]->valuelen, dynhds->hds[i]->value);
359
0
    if(result)
360
0
      break;
361
0
  }
362
363
0
  return result;
364
0
}
365
366
#endif