diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/errors.h | 40 | ||||
-rw-r--r-- | utils/http.c | 390 | ||||
-rw-r--r-- | utils/http.h | 73 |
3 files changed, 503 insertions, 0 deletions
diff --git a/utils/errors.h b/utils/errors.h new file mode 100644 index 000000000..7aa486569 --- /dev/null +++ b/utils/errors.h @@ -0,0 +1,40 @@ +/* + * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** \file + * Error codes + */ + +#ifndef NETSURF_UTILS_ERRORS_H_ +#define NETSURF_UTILS_ERRORS_H_ + +/** + * Enumeration of error codes + */ +typedef enum { + NSERROR_OK, /**< No error */ + + NSERROR_NOMEM, /**< Memory exhaustion */ + + NSERROR_NO_FETCH_HANDLER, /**< No fetch handler for URL scheme */ + + NSERROR_NOT_FOUND, /**< Requested item not found */ +} nserror; + +#endif + diff --git a/utils/http.c b/utils/http.c new file mode 100644 index 000000000..12672261d --- /dev/null +++ b/utils/http.c @@ -0,0 +1,390 @@ +/* + * Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** \file + * HTTP header parsing functions + */ + +#include <inttypes.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "utils/http.h" + +/** + * Representation of an HTTP parameter + */ +struct http_parameter { + struct http_parameter *next; /**< Next parameter in list, or NULL */ + + char *name; /**< Parameter name */ + char *value; /**< Parameter value */ +}; + +/** + * Determine if a character is valid for an HTTP token + * + * \param c Character to consider + * \return True if character is valid, false otherwise + */ +static bool http_is_token_char(uint8_t c) +{ + /* [ 32 - 126 ] except ()<>@,;:\"/[]?={} SP HT */ + + if (c <= ' ' || 126 < c) + return false; + + return (strchr("()<>@,;:\\\"/[]?={}", c) == NULL); +} + +/** + * Parse an HTTP token + * + * \param input Pointer to current input byte. Updated on exit. + * \param value Pointer to location to receive on-heap token value. + * \return NSERROR_OK on success, + * NSERROR_NOMEM on memory exhaustion + * + * The returned value is owned by the caller + */ +static nserror http_parse_token(const char **input, char **value) +{ + const uint8_t *start = (const uint8_t *) *input; + const uint8_t *end; + char *token; + + end = start; + while (http_is_token_char(*end)) + end++; + + token = malloc(end - start + 1); + if (token == NULL) + return NSERROR_NOMEM; + + memcpy(token, start, end - start); + token[end - start] = '\0'; + + *value = token; + *input = (const char *) end; + + return NSERROR_OK; +} + +/** + * Parse an HTTP quoted-string + * + * \param input Pointer to current input byte. Updated on exit. + * \param value Pointer to location to receive on-heap string value. + * \return NSERROR_OK on success, + * NSERROR_NOMEM on memory exhaustion + * + * The returned value is owned by the caller + */ +static nserror http_parse_quoted_string(const char **input, char **value) +{ + const uint8_t *start = (const uint8_t *) *input; + const uint8_t *end; + uint8_t c; + char *string_value; + + /* <"> *( qdtext | quoted-pair ) <"> + * qdtext = any TEXT except <"> + * quoted-pair = "\" CHAR + * TEXT = [ HT, CR, LF, 32-126, 128-255 ] + * CHAR = [ 0 - 127 ] + * + * \todo TEXT may contain non 8859-1 chars encoded per RFC 2047 + * \todo Support quoted-pairs + */ + + if (*start == '"') { + end = start = start + 1; + + c = *end; + while (c == '\t' || c == '\r' || c == '\n' || + c == ' ' || c == '!' || + ('#' <= c && c <= 126) || c > 127) { + end++; + c = *end; + } + + if (*end != '"') { + start--; + end = start; + } + } + + string_value = malloc(end - start + 1); + if (string_value == NULL) + return NSERROR_NOMEM; + + memcpy(string_value, start, end - start); + string_value[end - start] = '\0'; + + *value = string_value; + + if (end != start) + *input = (const char *) end + 1; + + return NSERROR_OK; +} + +/** + * Parse an HTTP parameter + * + * \param input Pointer to current input byte. Updated on exit. + * \param parameter Pointer to location to receive on-heap parameter. + * \return NSERROR_OK on success, + * NSERROR_NOMEM on memory exhaustion + * + * The returned parameter is owned by the caller. + */ +static nserror http_parse_parameter(const char **input, + http_parameter **parameter) +{ + const char *pos = *input; + char *name; + char *value; + http_parameter *param; + nserror error; + + /* token "=" ( token | quoted-string ) */ + + error = http_parse_token(&pos, &name); + if (error != NSERROR_OK) + return error; + + while (*pos == ' ' || *pos == '\t') + pos++; + + if (*pos != '=') { + value = strdup(""); + if (value == NULL) { + free(name); + return NSERROR_NOMEM; + } + } else { + pos++; + + while (*pos == ' ' || *pos == '\t') + pos++; + + if (*pos == '"') + error = http_parse_quoted_string(&pos, &value); + else + error = http_parse_token(&pos, &value); + + if (error != NSERROR_OK) { + free(name); + return error; + } + } + + param = malloc(sizeof(*param)); + if (param == NULL) { + free(value); + free(name); + return NSERROR_NOMEM; + } + + param->next = NULL; + param->name = name; + param->value = value; + + *parameter = param; + *input = pos; + + return NSERROR_OK; +} + +/** + * Parse an HTTP parameter list + * + * \param input Pointer to current input byte. Updated on exit. + * \param parameters Pointer to location to receive on-heap parameter list. + * \return NSERROR_OK on success, + * NSERROR_NOMEM on memory exhaustion + * + * The returned parameter list is owned by the caller + */ +static nserror http_parse_parameter_list(const char **input, + http_parameter **parameters) +{ + const char *pos = *input; + http_parameter *param; + http_parameter *list = NULL; + nserror error; + + /* 1*( ";" parameter ) */ + + while (*pos == ';') { + pos++; + + while (*pos == ' ' || *pos == '\t') + pos++; + + error = http_parse_parameter(&pos, ¶m); + if (error != NSERROR_OK) { + while (list != NULL) { + param = list; + + list = param->next; + + free(param->name); + free(param->value); + free(param); + } + return error; + } + + if (list != NULL) + param->next = list; + + list = param; + + while (*pos == ' ' || *pos == '\t') + pos++; + } + + *parameters = list; + *input = pos; + + return NSERROR_OK; +} + +/* See http.h for documentation */ +nserror http_parse_content_type(const char *header_value, char **media_type, + http_parameter **parameters) +{ + const char *pos = header_value; + char *type; + char *subtype = NULL; + http_parameter *params = NULL; + char *mime; + size_t mime_len; + nserror error; + + /* type "/" subtype *( ";" parameter ) */ + + while (*pos == ' ' || *pos == '\t') + pos++; + + error = http_parse_token(&pos, &type); + if (error != NSERROR_OK) + return error; + + while (*pos == ' ' || *pos == '\t') + pos++; + + if (*pos == '/') { + pos++; + + while (*pos == ' ' || *pos == '\t') + pos++; + + error = http_parse_token(&pos, &subtype); + if (error != NSERROR_OK) { + free(type); + return error; + } + + while (*pos == ' ' || *pos == '\t') + pos++; + + if (*pos == ';') { + pos++; + + while (*pos == ' ' || *pos == '\t') + pos++; + + error = http_parse_parameter_list(&pos, ¶ms); + if (error != NSERROR_OK) { + free(subtype); + free(type); + return error; + } + } + } + + /* <type> + <subtype> + '/' */ + mime_len = strlen(type) + (subtype != NULL ? strlen(subtype) : 0) + 1; + + mime = malloc(mime_len + 1); + if (mime == NULL) { + http_parameter_list_destroy(params); + free(subtype); + free(type); + return NSERROR_OK; + } + + sprintf(mime, "%s/%s", type, subtype != NULL ? subtype : ""); + + free(subtype); + free(type); + + *media_type = mime; + *parameters = params; + + return NSERROR_OK; +} + +/* See http.h for documentation */ +nserror http_parameter_list_find_item(const http_parameter *list, + const char *name, const char **value) +{ + while (list != NULL && strcasecmp(name, list->name) != 0) + list = list->next; + + if (list == NULL) + return NSERROR_NOT_FOUND; + + *value = list->value; + + return NSERROR_OK; +} + +/* See http.h for documentation */ +const http_parameter *http_parameter_list_iterate(const http_parameter *cur, + const char **name, const char **value) +{ + if (cur == NULL) + return NULL; + + *name = cur->name; + *value = cur->value; + + return cur->next; +} + +/* See http.h for documentation */ +void http_parameter_list_destroy(http_parameter *list) +{ + while (list != NULL) { + http_parameter *victim = list; + + list = victim->next; + + free(victim->name); + free(victim->value); + free(victim); + } +} + diff --git a/utils/http.h b/utils/http.h new file mode 100644 index 000000000..1d8b4de6c --- /dev/null +++ b/utils/http.h @@ -0,0 +1,73 @@ +/* + * Copyright 2010 John-Mark Bell <jmb@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** \file + * HTTP header parsing functions + */ + +#ifndef NETSURF_UTILS_HTTP_H_ +#define NETSURF_UTILS_HTTP_H_ + +#include "utils/errors.h" + +typedef struct http_parameter http_parameter; + +/** + * Parse an HTTP Content-Type header value + * + * \param header_value Header value to parse + * \param media_type Pointer to location to receive media type + * \param parameters Pointer to location to receive parameter list + * \return NSERROR_OK on success, + * NSERROR_NOMEM on memory exhaustion + */ +nserror http_parse_content_type(const char *header_value, char **media_type, + http_parameter **parameters); + +/** + * Find a named item in an HTTP parameter list + * + * \param list List to search + * \param name Name of item to search for + * \param value Pointer to location to receive value + * \return NSERROR_OK on success, + * NSERROR_NOT_FOUND if requested item does not exist + */ +nserror http_parameter_list_find_item(const http_parameter *list, + const char *name, const char **value); + +/** + * Iterate over a parameter list + * + * \param cur Pointer to current iteration position, list head to start + * \param name Pointer to location to receive item name + * \param value Pointer to location to receive item value + * \return Pointer to next iteration position, or NULL for end of iteration + */ +const http_parameter *http_parameter_list_iterate(const http_parameter *cur, + const char **name, const char **value); + +/** + * Destroy a list of HTTP parameters + * + * \param list List to destroy + */ +void http_parameter_list_destroy(http_parameter *list); + +#endif + |