summaryrefslogtreecommitdiff
path: root/utils/http.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/http.c')
-rw-r--r--utils/http.c390
1 files changed, 390 insertions, 0 deletions
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, &param);
+ 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, &params);
+ 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);
+ }
+}
+