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
RevLine 
[f9a2831]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
[10de842]36#include <errno.h>
[f9a2831]37#include <stdio.h>
38#include <stdlib.h>
39#include <str.h>
40#include <macros.h>
41
[b623b68]42#include <http/http.h>
43#include <http/ctype.h>
[f9a2831]44
45#define HTTP_HEADER_LINE "%s: %s\r\n"
46
[0005b63]47void http_header_init(http_header_t *header)
[f9a2831]48{
[0005b63]49 link_initialize(&header->link);
50 header->name = NULL;
51 header->value = NULL;
[f9a2831]52}
53
[0005b63]54http_header_t *http_header_create(const char *name, const char *value)
[f9a2831]55{
56 http_header_t *header = malloc(sizeof(http_header_t));
57 if (header == NULL)
58 return NULL;
[0005b63]59 http_header_init(header);
60
61 header->name = str_dup(name);
62 if (header->name == NULL) {
63 free(header);
64 return NULL;
65 }
[a35b458]66
[0005b63]67 header->value = str_dup(value);
68 if (header->value == NULL) {
69 free(header->name);
70 free(header);
71 return NULL;
72 }
73
[f9a2831]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
[0005b63]84ssize_t http_header_encode(http_header_t *header, char *buf, size_t buf_size)
[f9a2831]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
[b7fd2a0]96errno_t http_header_receive_name(receive_buffer_t *rb,
[cbfc8b7]97 receive_buffer_mark_t *name_end)
[f9a2831]98{
[3ce68b7]99 char c = 0;
100 do {
[cbfc8b7]101 if (name_end)
102 recv_mark_update(rb, name_end);
[a35b458]103
[b7fd2a0]104 errno_t rc = recv_char(rb, &c, true);
[cbfc8b7]105 if (rc != EOK)
[3ce68b7]106 return rc;
107 } while (is_token(c));
[a35b458]108
[cbfc8b7]109 if (c != ':')
[f9a2831]110 return EINVAL;
[a35b458]111
[3ce68b7]112 return EOK;
113}
114
[b7fd2a0]115errno_t http_header_receive_value(receive_buffer_t *rb,
[cbfc8b7]116 receive_buffer_mark_t *value_start, receive_buffer_mark_t *value_end)
[3ce68b7]117{
[b7fd2a0]118 errno_t rc = EOK;
[3ce68b7]119 char c = 0;
[a35b458]120
[3ce68b7]121 /* Ignore any inline LWS */
122 while (true) {
[cbfc8b7]123 if (value_start)
124 recv_mark_update(rb, value_start);
[a35b458]125
[3ce68b7]126 rc = recv_char(rb, &c, false);
127 if (rc != EOK)
[cbfc8b7]128 return rc;
[a35b458]129
[3ce68b7]130 if (c != ' ' && c != '\t')
131 break;
[a35b458]132
[3ce68b7]133 rc = recv_char(rb, &c, true);
134 if (rc != EOK)
[cbfc8b7]135 return rc;
[3ce68b7]136 }
[a35b458]137
[3ce68b7]138 while (true) {
[cbfc8b7]139 recv_mark_update(rb, value_end);
[a35b458]140
[3ce68b7]141 rc = recv_char(rb, &c, true);
142 if (rc != EOK)
[cbfc8b7]143 return rc;
[a35b458]144
[3ce68b7]145 if (c != '\r' && c != '\n')
146 continue;
[a35b458]147
[9a09212]148 size_t nrecv;
149 rc = recv_discard(rb, (c == '\r' ? '\n' : '\r'), &nrecv);
150 if (rc != EOK)
[cbfc8b7]151 return rc;
[a35b458]152
[3ce68b7]153 rc = recv_char(rb, &c, false);
154 if (rc != EOK)
[cbfc8b7]155 return rc;
[a35b458]156
[3ce68b7]157 if (c != ' ' && c != '\t')
158 break;
[a35b458]159
[3ce68b7]160 /* Ignore the char */
161 rc = recv_char(rb, &c, true);
162 if (rc != EOK)
[cbfc8b7]163 return rc;
[3ce68b7]164 }
[a35b458]165
[3ce68b7]166 return EOK;
167}
168
[b7fd2a0]169errno_t http_header_receive(receive_buffer_t *rb, http_header_t *header,
[cbfc8b7]170 size_t size_limit, size_t *out_bytes_used)
[3ce68b7]171{
[cbfc8b7]172 receive_buffer_mark_t mark_start;
173 receive_buffer_mark_t mark_end;
[a35b458]174
[cbfc8b7]175 recv_mark(rb, &mark_start);
176 recv_mark(rb, &mark_end);
[a35b458]177
[b7fd2a0]178 errno_t rc = http_header_receive_name(rb, &mark_end);
[cbfc8b7]179 if (rc != EOK)
180 goto end;
[a35b458]181
[cbfc8b7]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 }
[a35b458]187
[3ce68b7]188 char *name = NULL;
[cbfc8b7]189 rc = recv_cut_str(rb, &mark_start, &mark_end, &name);
190 if (rc != EOK)
191 goto end;
[a35b458]192
[cbfc8b7]193 rc = http_header_receive_value(rb, &mark_start, &mark_end);
194 if (rc != EOK)
195 goto end_with_name;
[a35b458]196
[cbfc8b7]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;
[3ce68b7]201 }
[a35b458]202
[3ce68b7]203 char *value = NULL;
[cbfc8b7]204 rc = recv_cut_str(rb, &mark_start, &mark_end, &value);
205 if (rc != EOK)
206 goto end_with_name;
[a35b458]207
[cbfc8b7]208 if (out_bytes_used)
209 *out_bytes_used = name_size + value_size;
[a35b458]210
[0005b63]211 header->name = name;
212 header->value = value;
[cbfc8b7]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;
[f9a2831]220}
221
[3ce68b7]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;
[a35b458]230
[3ce68b7]231 while (is_lws(value[read_index])) read_index++;
[a35b458]232
[3ce68b7]233 while (value[read_index] != 0) {
234 if (is_lws(value[read_index])) {
235 while (is_lws(value[read_index])) read_index++;
[a35b458]236
[3ce68b7]237 if (value[read_index] != 0)
238 value[write_index++] = ' ';
[a35b458]239
[3ce68b7]240 continue;
241 }
[a35b458]242
[3ce68b7]243 value[write_index++] = value[read_index++];
244 }
[a35b458]245
[3ce68b7]246 value[write_index] = 0;
247}
248
[4d4f656]249/** Test if two header names are equivalent
250 *
251 */
252bool http_header_name_match(const char *name_a, const char *name_b)
253{
[0e7c3d9]254 return str_casecmp(name_a, name_b) == 0;
[4d4f656]255}
256
257void http_headers_init(http_headers_t *headers) {
258 list_initialize(&headers->list);
259}
260
[b7fd2a0]261errno_t http_headers_find_single(http_headers_t *headers, const char *name,
[4d4f656]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;
[a35b458]268
[4d4f656]269 if (found == NULL) {
270 found = header;
271 }
272 else {
273 return HTTP_EMULTIPLE_HEADERS;
274 }
275 }
[a35b458]276
[4d4f656]277 if (found == NULL)
278 return HTTP_EMISSING_HEADER;
[a35b458]279
[4d4f656]280 *out_header = found;
281 return EOK;
282}
283
[b7fd2a0]284errno_t http_headers_append(http_headers_t *headers, const char *name,
[4d4f656]285 const char *value)
286{
287 http_header_t *header = http_header_create(name, value);
288 if (header == NULL)
289 return ENOMEM;
[a35b458]290
[4d4f656]291 http_headers_append_header(headers, header);
292 return EOK;
293}
294
[b7fd2a0]295errno_t http_headers_set(http_headers_t *headers, const char *name,
[4d4f656]296 const char *value)
297{
298 http_header_t *header = NULL;
[b7fd2a0]299 errno_t rc = http_headers_find_single(headers, name, &header);
[4d4f656]300 if (rc != EOK && rc != HTTP_EMISSING_HEADER)
301 return rc;
[a35b458]302
[4d4f656]303 if (rc == HTTP_EMISSING_HEADER)
304 return http_headers_append(headers, name, value);
[a35b458]305
[4d4f656]306 char *new_value = str_dup(value);
307 if (new_value == NULL)
308 return ENOMEM;
[a35b458]309
[4d4f656]310 free(header->value);
311 header->value = new_value;
312 return EOK;
313}
314
[b7fd2a0]315errno_t http_headers_get(http_headers_t *headers, const char *name, char **value)
[4d4f656]316{
317 http_header_t *header = NULL;
[b7fd2a0]318 errno_t rc = http_headers_find_single(headers, name, &header);
[4d4f656]319 if (rc != EOK)
320 return rc;
[a35b458]321
[4d4f656]322 *value = header->value;
323 return EOK;
324}
325
[b7fd2a0]326errno_t http_headers_receive(receive_buffer_t *rb, http_headers_t *headers,
[cbfc8b7]327 size_t limit_alloc, unsigned limit_count)
[4d4f656]328{
[b7fd2a0]329 errno_t rc = EOK;
[4d4f656]330 unsigned added = 0;
[a35b458]331
[4d4f656]332 while (true) {
333 char c = 0;
334 rc = recv_char(rb, &c, false);
335 if (rc != EOK)
336 goto error;
[a35b458]337
[4d4f656]338 if (c == '\n' || c == '\r')
339 break;
[a35b458]340
[cbfc8b7]341 if (limit_count > 0 && added >= limit_count) {
342 rc = ELIMIT;
343 goto error;
344 }
[a35b458]345
[4d4f656]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);
[a35b458]352
[cbfc8b7]353 size_t header_size;
354 rc = http_header_receive(rb, header, limit_alloc, &header_size);
[4d4f656]355 if (rc != EOK) {
356 free(header);
357 goto error;
358 }
[cbfc8b7]359 limit_alloc -= header_size;
[a35b458]360
[4d4f656]361 http_headers_append_header(headers, header);
362 added++;
363 }
[a35b458]364
[4d4f656]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
[f9a2831]388/** @}
389 */
Note: See TracBrowser for help on using the repository browser.