source: mainline/uspace/lib/http/src/headers.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 8.4 KB
Line 
1/*
2 * Copyright (c) 2013 Martin Sucha
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup http
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <errno.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <str.h>
40#include <macros.h>
41
42#include <http/http.h>
43#include <http/ctype.h>
44
45#define HTTP_HEADER_LINE "%s: %s\r\n"
46
47void http_header_init(http_header_t *header)
48{
49 link_initialize(&header->link);
50 header->name = NULL;
51 header->value = NULL;
52}
53
54http_header_t *http_header_create(const char *name, const char *value)
55{
56 http_header_t *header = malloc(sizeof(http_header_t));
57 if (header == NULL)
58 return NULL;
59 http_header_init(header);
60
61 header->name = str_dup(name);
62 if (header->name == NULL) {
63 free(header);
64 return NULL;
65 }
66
67 header->value = str_dup(value);
68 if (header->value == NULL) {
69 free(header->name);
70 free(header);
71 return NULL;
72 }
73
74 return header;
75}
76
77void http_header_destroy(http_header_t *header)
78{
79 free(header->name);
80 free(header->value);
81 free(header);
82}
83
84ssize_t http_header_encode(http_header_t *header, char *buf, size_t buf_size)
85{
86 /* TODO properly split long header values */
87 if (buf == NULL) {
88 return printf_size(HTTP_HEADER_LINE, header->name, header->value);
89 }
90 else {
91 return snprintf(buf, buf_size,
92 HTTP_HEADER_LINE, header->name, header->value);
93 }
94}
95
96errno_t http_header_receive_name(receive_buffer_t *rb,
97 receive_buffer_mark_t *name_end)
98{
99 char c = 0;
100 do {
101 if (name_end)
102 recv_mark_update(rb, name_end);
103
104 errno_t rc = recv_char(rb, &c, true);
105 if (rc != EOK)
106 return rc;
107 } while (is_token(c));
108
109 if (c != ':')
110 return EINVAL;
111
112 return EOK;
113}
114
115errno_t http_header_receive_value(receive_buffer_t *rb,
116 receive_buffer_mark_t *value_start, receive_buffer_mark_t *value_end)
117{
118 errno_t rc = EOK;
119 char c = 0;
120
121 /* Ignore any inline LWS */
122 while (true) {
123 if (value_start)
124 recv_mark_update(rb, value_start);
125
126 rc = recv_char(rb, &c, false);
127 if (rc != EOK)
128 return rc;
129
130 if (c != ' ' && c != '\t')
131 break;
132
133 rc = recv_char(rb, &c, true);
134 if (rc != EOK)
135 return rc;
136 }
137
138 while (true) {
139 recv_mark_update(rb, value_end);
140
141 rc = recv_char(rb, &c, true);
142 if (rc != EOK)
143 return rc;
144
145 if (c != '\r' && c != '\n')
146 continue;
147
148 size_t nrecv;
149 rc = recv_discard(rb, (c == '\r' ? '\n' : '\r'), &nrecv);
150 if (rc != EOK)
151 return rc;
152
153 rc = recv_char(rb, &c, false);
154 if (rc != EOK)
155 return rc;
156
157 if (c != ' ' && c != '\t')
158 break;
159
160 /* Ignore the char */
161 rc = recv_char(rb, &c, true);
162 if (rc != EOK)
163 return rc;
164 }
165
166 return EOK;
167}
168
169errno_t http_header_receive(receive_buffer_t *rb, http_header_t *header,
170 size_t size_limit, size_t *out_bytes_used)
171{
172 receive_buffer_mark_t mark_start;
173 receive_buffer_mark_t mark_end;
174
175 recv_mark(rb, &mark_start);
176 recv_mark(rb, &mark_end);
177
178 errno_t rc = http_header_receive_name(rb, &mark_end);
179 if (rc != EOK)
180 goto end;
181
182 size_t name_size = mark_end.offset - mark_start.offset;
183 if (size_limit > 0 && name_size > size_limit) {
184 rc = ELIMIT;
185 goto end;
186 }
187
188 char *name = NULL;
189 rc = recv_cut_str(rb, &mark_start, &mark_end, &name);
190 if (rc != EOK)
191 goto end;
192
193 rc = http_header_receive_value(rb, &mark_start, &mark_end);
194 if (rc != EOK)
195 goto end_with_name;
196
197 size_t value_size = mark_end.offset - mark_start.offset;
198 if (size_limit > 0 && (name_size + value_size) > size_limit) {
199 rc = ELIMIT;
200 goto end_with_name;
201 }
202
203 char *value = NULL;
204 rc = recv_cut_str(rb, &mark_start, &mark_end, &value);
205 if (rc != EOK)
206 goto end_with_name;
207
208 if (out_bytes_used)
209 *out_bytes_used = name_size + value_size;
210
211 header->name = name;
212 header->value = value;
213 goto end;
214end_with_name:
215 free(name);
216end:
217 recv_unmark(rb, &mark_start);
218 recv_unmark(rb, &mark_end);
219 return rc;
220}
221
222/** Normalize HTTP header value
223 *
224 * @see RFC2616 section 4.2
225 */
226void http_header_normalize_value(char *value)
227{
228 size_t read_index = 0;
229 size_t write_index = 0;
230
231 while (is_lws(value[read_index])) read_index++;
232
233 while (value[read_index] != 0) {
234 if (is_lws(value[read_index])) {
235 while (is_lws(value[read_index])) read_index++;
236
237 if (value[read_index] != 0)
238 value[write_index++] = ' ';
239
240 continue;
241 }
242
243 value[write_index++] = value[read_index++];
244 }
245
246 value[write_index] = 0;
247}
248
249/** Test if two header names are equivalent
250 *
251 */
252bool http_header_name_match(const char *name_a, const char *name_b)
253{
254 return str_casecmp(name_a, name_b) == 0;
255}
256
257void http_headers_init(http_headers_t *headers) {
258 list_initialize(&headers->list);
259}
260
261errno_t http_headers_find_single(http_headers_t *headers, const char *name,
262 http_header_t **out_header)
263{
264 http_header_t *found = NULL;
265 http_headers_foreach(*headers, header) {
266 if (!http_header_name_match(header->name, name))
267 continue;
268
269 if (found == NULL) {
270 found = header;
271 }
272 else {
273 return HTTP_EMULTIPLE_HEADERS;
274 }
275 }
276
277 if (found == NULL)
278 return HTTP_EMISSING_HEADER;
279
280 *out_header = found;
281 return EOK;
282}
283
284errno_t http_headers_append(http_headers_t *headers, const char *name,
285 const char *value)
286{
287 http_header_t *header = http_header_create(name, value);
288 if (header == NULL)
289 return ENOMEM;
290
291 http_headers_append_header(headers, header);
292 return EOK;
293}
294
295errno_t http_headers_set(http_headers_t *headers, const char *name,
296 const char *value)
297{
298 http_header_t *header = NULL;
299 errno_t rc = http_headers_find_single(headers, name, &header);
300 if (rc != EOK && rc != HTTP_EMISSING_HEADER)
301 return rc;
302
303 if (rc == HTTP_EMISSING_HEADER)
304 return http_headers_append(headers, name, value);
305
306 char *new_value = str_dup(value);
307 if (new_value == NULL)
308 return ENOMEM;
309
310 free(header->value);
311 header->value = new_value;
312 return EOK;
313}
314
315errno_t http_headers_get(http_headers_t *headers, const char *name, char **value)
316{
317 http_header_t *header = NULL;
318 errno_t rc = http_headers_find_single(headers, name, &header);
319 if (rc != EOK)
320 return rc;
321
322 *value = header->value;
323 return EOK;
324}
325
326errno_t http_headers_receive(receive_buffer_t *rb, http_headers_t *headers,
327 size_t limit_alloc, unsigned limit_count)
328{
329 errno_t rc = EOK;
330 unsigned added = 0;
331
332 while (true) {
333 char c = 0;
334 rc = recv_char(rb, &c, false);
335 if (rc != EOK)
336 goto error;
337
338 if (c == '\n' || c == '\r')
339 break;
340
341 if (limit_count > 0 && added >= limit_count) {
342 rc = ELIMIT;
343 goto error;
344 }
345
346 http_header_t *header = malloc(sizeof(http_header_t));
347 if (header == NULL) {
348 rc = ENOMEM;
349 goto error;
350 }
351 http_header_init(header);
352
353 size_t header_size;
354 rc = http_header_receive(rb, header, limit_alloc, &header_size);
355 if (rc != EOK) {
356 free(header);
357 goto error;
358 }
359 limit_alloc -= header_size;
360
361 http_headers_append_header(headers, header);
362 added++;
363 }
364
365 return EOK;
366error:
367 while (added-- > 0) {
368 link_t *link = list_last(&headers->list);
369 http_header_t *header = list_get_instance(link, http_header_t, link);
370 http_headers_remove(headers, header);
371 http_header_destroy(header);
372 }
373 return rc;
374}
375
376void http_headers_clear(http_headers_t *headers)
377{
378 link_t *link = list_first(&headers->list);
379 while (link != NULL) {
380 link_t *next = list_next(link, &headers->list);
381 http_header_t *header = list_get_instance(link, http_header_t, link);
382 list_remove(link);
383 http_header_destroy(header);
384 link = next;
385 }
386}
387
388/** @}
389 */
Note: See TracBrowser for help on using the repository browser.