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