From b34502af8247606ae3b5693cd3046566b16a3e6d Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Fri, 8 Jul 2011 08:38:17 +0000 Subject: Refactor http utilities svn path=/trunk/netsurf/; revision=12595 --- Makefile.sources | 6 +- content/content_factory.c | 46 +---- content/content_factory.h | 2 +- content/hlcache.c | 11 +- css/css.c | 26 ++- desktop/download.c | 54 ++--- render/box_construct.c | 47 ++++- render/html.c | 21 +- render/textplain.c | 53 +++-- utils/http.c | 423 --------------------------------------- utils/http.h | 60 +----- utils/http/challenge.c | 140 +++++++++++++ utils/http/challenge.h | 47 +++++ utils/http/challenge_internal.h | 27 +++ utils/http/content-disposition.c | 78 ++++++++ utils/http/content-disposition.h | 49 +++++ utils/http/content-type.c | 128 ++++++++++++ utils/http/content-type.h | 49 +++++ utils/http/generics.c | 99 +++++++++ utils/http/generics.h | 54 +++++ utils/http/parameter.c | 153 ++++++++++++++ utils/http/parameter.h | 59 ++++++ utils/http/parameter_internal.h | 27 +++ utils/http/primitives.c | 146 ++++++++++++++ utils/http/primitives.h | 32 +++ utils/http/www-authenticate.c | 75 +++++++ utils/http/www-authenticate.h | 48 +++++ 27 files changed, 1380 insertions(+), 580 deletions(-) delete mode 100644 utils/http.c create mode 100644 utils/http/challenge.c create mode 100644 utils/http/challenge.h create mode 100644 utils/http/challenge_internal.h create mode 100644 utils/http/content-disposition.c create mode 100644 utils/http/content-disposition.h create mode 100644 utils/http/content-type.c create mode 100644 utils/http/content-type.h create mode 100644 utils/http/generics.c create mode 100644 utils/http/generics.h create mode 100644 utils/http/parameter.c create mode 100644 utils/http/parameter.h create mode 100644 utils/http/parameter_internal.h create mode 100644 utils/http/primitives.c create mode 100644 utils/http/primitives.h create mode 100644 utils/http/www-authenticate.c create mode 100644 utils/http/www-authenticate.h diff --git a/Makefile.sources b/Makefile.sources index 85f7624f6..34ca72604 100644 --- a/Makefile.sources +++ b/Makefile.sources @@ -16,9 +16,12 @@ S_RENDER := box.c box_construct.c box_normalise.c \ hubbub_binding.c imagemap.c layout.c list.c table.c textinput.c \ textplain.c -S_UTILS := base64.c filename.c hashtable.c http.c locale.c messages.c \ +S_UTILS := base64.c filename.c hashtable.c locale.c messages.c \ talloc.c url.c utf8.c utils.c useragent.c filepath.c log.c +S_HTTP := challenge.c generics.c primitives.c parameter.c \ + content-disposition.c content-type.c www-authenticate.c + S_DESKTOP := cookies.c history_global_core.c hotlist.c knockout.c \ mouse.c options.c plot_style.c print.c search.c searchweb.c \ scrollbar.c sslcert.c textarea.c thumbnail.c tree.c \ @@ -30,6 +33,7 @@ S_COMMON := $(addprefix content/,$(S_CONTENT)) \ $(addprefix css/,$(S_CSS)) \ $(addprefix render/,$(S_RENDER)) \ $(addprefix utils/,$(S_UTILS)) \ + $(addprefix utils/http/,$(S_HTTP)) \ $(addprefix desktop/,$(S_DESKTOP)) # S_IMAGE are sources related to image management diff --git a/content/content_factory.c b/content/content_factory.c index ae226a4d1..0b9d44b7d 100644 --- a/content/content_factory.c +++ b/content/content_factory.c @@ -128,24 +128,16 @@ static const content_handler *content_lookup(lwc_string *mime_type) * \param mime_type MIME type to consider * \return Generic content type */ -content_type content_factory_type_from_mime_type(const char *mime_type) +content_type content_factory_type_from_mime_type(lwc_string *mime_type) { const content_handler *handler; - lwc_string *imime_type; - lwc_error lerror; content_type type = CONTENT_NONE; - lerror = lwc_intern_string(mime_type, strlen(mime_type), &imime_type); - if (lerror != lwc_error_ok) - return CONTENT_NONE; - - handler = content_lookup(imime_type); + handler = content_lookup(mime_type); if (handler != NULL) { - type = handler->type(imime_type); + type = handler->type(mime_type); } - lwc_string_unref(imime_type); - return type; } @@ -163,10 +155,7 @@ struct content *content_factory_create_content(llcache_handle *llcache, struct content *c; const char *content_type_header; const content_handler *handler; - char *mime_type; - http_parameter *params; - lwc_string *imime_type; - lwc_error lerr; + http_content_type *ct; nserror error; content_type_header = @@ -174,39 +163,26 @@ struct content *content_factory_create_content(llcache_handle *llcache, if (content_type_header == NULL) content_type_header = "text/plain"; - error = http_parse_content_type(content_type_header, &mime_type, - ¶ms); + error = http_parse_content_type(content_type_header, &ct); if (error != NSERROR_OK) return NULL; - lerr = lwc_intern_string(mime_type, strlen(mime_type), &imime_type); - if (lerr != lwc_error_ok) { - http_parameter_list_destroy(params); - free(mime_type); - return NULL; - } - - free(mime_type); - - handler = content_lookup(imime_type); + handler = content_lookup(ct->media_type); if (handler == NULL) { - lwc_string_unref(imime_type); - http_parameter_list_destroy(params); + http_content_type_destroy(ct); return NULL; } assert(handler->create != NULL); - error = handler->create(handler, imime_type, params, llcache, - fallback_charset, quirks, &c); + error = handler->create(handler, ct->media_type, ct->parameters, + llcache, fallback_charset, quirks, &c); if (error != NSERROR_OK) { - lwc_string_unref(imime_type); - http_parameter_list_destroy(params); + http_content_type_destroy(ct); return NULL; } - lwc_string_unref(imime_type); - http_parameter_list_destroy(params); + http_content_type_destroy(ct); return c; } diff --git a/content/content_factory.h b/content/content_factory.h index aff7a64ac..f6ea3ce49 100644 --- a/content/content_factory.h +++ b/content/content_factory.h @@ -39,6 +39,6 @@ nserror content_factory_register_handler(lwc_string *mime_type, struct content *content_factory_create_content(struct llcache_handle *llcache, const char *fallback_charset, bool quirks); -content_type content_factory_type_from_mime_type(const char *mime_type); +content_type content_factory_type_from_mime_type(lwc_string *mime_type); #endif diff --git a/content/hlcache.c b/content/hlcache.c index b684ed01c..40b6486c9 100644 --- a/content/hlcache.c +++ b/content/hlcache.c @@ -541,8 +541,7 @@ bool hlcache_type_is_acceptable(llcache_handle *llcache, content_type accepted_types, content_type *computed_type) { const char *content_type_header; - char *mime_type; - http_parameter *params; + http_content_type *ct; content_type type; nserror error; @@ -551,15 +550,13 @@ bool hlcache_type_is_acceptable(llcache_handle *llcache, if (content_type_header == NULL) content_type_header = "text/plain"; - error = http_parse_content_type(content_type_header, &mime_type, - ¶ms); + error = http_parse_content_type(content_type_header, &ct); if (error != NSERROR_OK) return false; - type = content_factory_type_from_mime_type(mime_type); + type = content_factory_type_from_mime_type(ct->media_type); - free(mime_type); - http_parameter_list_destroy(params); + http_content_type_destroy(ct); *computed_type = type; diff --git a/css/css.c b/css/css.c index 63862c720..9fc656848 100644 --- a/css/css.c +++ b/css/css.c @@ -90,6 +90,7 @@ static const content_handler css_content_handler = { }; static lwc_string *css_mime_type; +static lwc_string *css_charset; static css_stylesheet *blank_import; /** @@ -105,10 +106,18 @@ nserror css_init(void) if (lerror != lwc_error_ok) return NSERROR_NOMEM; + lerror = lwc_intern_string("charset", SLEN("charset"), &css_charset); + if (lerror != lwc_error_ok) { + lwc_string_unref(css_mime_type); + return NSERROR_NOMEM; + } + error = content_factory_register_handler(css_mime_type, &css_content_handler); - if (error != NSERROR_OK) + if (error != NSERROR_OK) { + lwc_string_unref(css_charset); lwc_string_unref(css_mime_type); + } return error; } @@ -118,6 +127,8 @@ nserror css_init(void) */ void css_fini(void) { + lwc_string_unref(css_charset); + lwc_string_unref(css_mime_type); if (blank_import != NULL) @@ -138,6 +149,7 @@ nserror nscss_create(const content_handler *handler, { nscss_content *result; const char *charset = NULL; + lwc_string *charset_value = NULL; union content_msg_data msg_data; nserror error; @@ -153,11 +165,14 @@ nserror nscss_create(const content_handler *handler, } /* Find charset specified on HTTP layer, if any */ - error = http_parameter_list_find_item(params, "charset", &charset); - if (error != NSERROR_OK || *charset == '\0') { + error = http_parameter_list_find_item(params, css_charset, + &charset_value); + if (error != NSERROR_OK || lwc_string_length(charset_value) == 0) { /* No charset specified, use fallback, if any */ /** \todo libcss will take this as gospel, which is wrong */ charset = fallback_charset; + } else { + charset = lwc_string_data(charset_value); } error = nscss_create_css_data(&result->data, @@ -167,10 +182,15 @@ nserror nscss_create(const content_handler *handler, if (error != NSERROR_OK) { msg_data.error = messages_get("NoMemory"); content_broadcast(&result->base, CONTENT_MSG_ERROR, msg_data); + if (charset_value != NULL) + lwc_string_unref(charset_value); talloc_free(result); return error; } + if (charset_value != NULL) + lwc_string_unref(charset_value); + *c = (struct content *) result; return NSERROR_OK; diff --git a/desktop/download.c b/desktop/download.c index 28493ad3b..f90f3200e 100644 --- a/desktop/download.c +++ b/desktop/download.c @@ -28,6 +28,7 @@ #include "desktop/gui.h" #include "utils/http.h" #include "utils/url.h" +#include "utils/utils.h" /** * A context for a download @@ -36,7 +37,7 @@ struct download_context { llcache_handle *llcache; /**< Low-level cache handle */ struct gui_window *parent; /**< Parent window */ - char *mime_type; /**< MIME type of download */ + lwc_string *mime_type; /**< MIME type of download */ unsigned long total_length; /**< Length of data, in bytes */ char *filename; /**< Suggested filename */ @@ -87,8 +88,7 @@ static char *download_default_filename(const char *url) static nserror download_context_process_headers(download_context *ctx) { const char *http_header; - char *mime_type; - http_parameter *params; + http_content_type *content_type; unsigned long length; nserror error; @@ -97,13 +97,10 @@ static nserror download_context_process_headers(download_context *ctx) if (http_header == NULL) http_header = "text/plain"; - error = http_parse_content_type(http_header, &mime_type, ¶ms); + error = http_parse_content_type(http_header, &content_type); if (error != NSERROR_OK) return error; - /* Don't care about parameters */ - http_parameter_list_destroy(params); - /* Retrieve and parse Content-Length */ http_header = llcache_handle_get_header(ctx->llcache, "Content-Length"); if (http_header == NULL) @@ -115,35 +112,46 @@ static nserror download_context_process_headers(download_context *ctx) http_header = llcache_handle_get_header(ctx->llcache, "Content-Disposition"); if (http_header != NULL) { - const char *filename; - char *disposition; + lwc_string *filename; + lwc_string *filename_value; + http_content_disposition *disposition; + + if (lwc_intern_string("filename", SLEN("filename"), + &filename) != lwc_error_ok) { + http_content_type_destroy(content_type); + return NSERROR_NOMEM; + } error = http_parse_content_disposition(http_header, - &disposition, ¶ms); + &disposition); if (error != NSERROR_OK) { - free(mime_type); + lwc_string_unref(filename); + http_content_type_destroy(content_type); return error; } - free(disposition); - - error = http_parameter_list_find_item(params, - "filename", &filename); + error = http_parameter_list_find_item(disposition->parameters, + filename, &filename_value); if (error == NSERROR_OK) - ctx->filename = download_parse_filename(filename); + ctx->filename = download_parse_filename( + lwc_string_data(filename_value)); - http_parameter_list_destroy(params); + http_content_disposition_destroy(disposition); + lwc_string_unref(filename_value); + lwc_string_unref(filename); } - ctx->mime_type = mime_type; + ctx->mime_type = lwc_string_ref(content_type->media_type); ctx->total_length = length; if (ctx->filename == NULL) { ctx->filename = download_default_filename( llcache_handle_get_url(ctx->llcache)); } + http_content_type_destroy(content_type); + if (ctx->filename == NULL) { - free(ctx->mime_type); + lwc_string_unref(ctx->mime_type); ctx->mime_type = NULL; return NSERROR_NOMEM; } @@ -152,9 +160,7 @@ static nserror download_context_process_headers(download_context *ctx) ctx->window = gui_download_window_create(ctx, ctx->parent); if (ctx->window == NULL) { free(ctx->filename); - ctx->filename = NULL; - free(ctx->mime_type); - ctx->mime_type = NULL; + lwc_string_unref(ctx->mime_type); return NSERROR_NOMEM; } @@ -259,7 +265,7 @@ void download_context_destroy(download_context *ctx) { llcache_handle_release(ctx->llcache); - free(ctx->mime_type); + lwc_string_unref(ctx->mime_type); free(ctx->filename); @@ -283,7 +289,7 @@ const char *download_context_get_url(const download_context *ctx) /* See download.h for documentation */ const char *download_context_get_mime_type(const download_context *ctx) { - return ctx->mime_type; + return lwc_string_data(ctx->mime_type); } /* See download.h for documentation */ diff --git a/render/box_construct.c b/render/box_construct.c index 5fdb23b5a..990fa380c 100644 --- a/render/box_construct.c +++ b/render/box_construct.c @@ -1257,17 +1257,44 @@ bool box_object(BOX_SPECIAL_PARAMS) * (classid || !classid) && data => data is used (consult type) * !classid && !data => invalid; ignored */ - if (params->classid && !params->data && params->codetype && - content_factory_type_from_mime_type(params->codetype) == - CONTENT_NONE) - /* can't handle this MIME type */ - return true; + if (params->classid != NULL && params->data == NULL && + params->codetype != NULL) { + lwc_string *icodetype; + lwc_error lerror; + + lerror = lwc_intern_string(params->codetype, + strlen(params->codetype), &icodetype); + if (lerror != lwc_error_ok) + return false; - if (params->data && params->type && - content_factory_type_from_mime_type(params->type) == - CONTENT_NONE) - /* can't handle this MIME type */ - return true; + if (content_factory_type_from_mime_type(icodetype) == + CONTENT_NONE) { + /* can't handle this MIME type */ + lwc_string_unref(icodetype); + return true; + } + + lwc_string_unref(icodetype); + } + + if (params->data != NULL && params->type != NULL) { + lwc_string *itype; + lwc_error lerror; + + lerror = lwc_intern_string(params->type, strlen(params->type), + &itype); + if (lerror != lwc_error_ok) + return false; + + if (content_factory_type_from_mime_type(itype) == + CONTENT_NONE) { + /* can't handle this MIME type */ + lwc_string_unref(itype); + return true; + } + + lwc_string_unref(itype); + } /* add parameters to linked list */ for (c = n->children; c; c = c->next) { diff --git a/render/html.c b/render/html.c index 9e2b4c338..6f76bf6ac 100644 --- a/render/html.c +++ b/render/html.c @@ -138,6 +138,7 @@ static const char *html_types[] = { }; static lwc_string *html_mime_types[NOF_ELEMENTS(html_types)]; +static lwc_string *html_charset; nserror html_init(void) { @@ -145,6 +146,12 @@ nserror html_init(void) lwc_error lerror; nserror error; + lerror = lwc_intern_string("charset", SLEN("charset"), &html_charset); + if (lerror != lwc_error_ok) { + error = NSERROR_NOMEM; + goto error; + } + for (i = 0; i < NOF_ELEMENTS(html_mime_types); i++) { lerror = lwc_intern_string(html_types[i], strlen(html_types[i]), @@ -176,6 +183,9 @@ void html_fini(void) if (html_mime_types[i] != NULL) lwc_string_unref(html_mime_types[i]); } + + if (html_charset != NULL) + lwc_string_unref(html_charset); } /** @@ -217,7 +227,7 @@ nserror html_create(const content_handler *handler, nserror html_create_html_data(html_content *c, const http_parameter *params) { - const char *charset; + lwc_string *charset; union content_msg_data msg_data; binding_error error; nserror nerror; @@ -245,10 +255,13 @@ nserror html_create_html_data(html_content *c, const http_parameter *params) c->font_func = &nsfont; c->scrollbar = NULL; - nerror = http_parameter_list_find_item(params, "charset", &charset); + nerror = http_parameter_list_find_item(params, html_charset, &charset); if (nerror == NSERROR_OK) { - c->encoding = talloc_strdup(c, charset); - if (!c->encoding) { + c->encoding = talloc_strdup(c, lwc_string_data(charset)); + + lwc_string_unref(charset); + + if (c->encoding == NULL) { error = BINDING_NOMEM; goto error; } diff --git a/render/textplain.c b/render/textplain.c index 873f277aa..247afc90d 100644 --- a/render/textplain.c +++ b/render/textplain.c @@ -58,7 +58,7 @@ struct textplain_line { typedef struct textplain_content { struct content base; - char *encoding; + lwc_string *encoding; void *inputstream; char *utf8_data; size_t utf8_data_size; @@ -93,7 +93,7 @@ static nserror textplain_create(const content_handler *handler, llcache_handle *llcache, const char *fallback_charset, bool quirks, struct content **c); static nserror textplain_create_internal(textplain_content *c, - const char *charset); + lwc_string *charset); static bool textplain_process_data(struct content *c, const char *data, unsigned int size); static bool textplain_convert(struct content *c); @@ -140,6 +140,8 @@ static const content_handler textplain_content_handler = { }; static lwc_string *textplain_mime_type; +static lwc_string *textplain_charset; +static lwc_string *textplain_default_charset; /** * Initialise the text content handler @@ -154,10 +156,28 @@ nserror textplain_init(void) if (lerror != lwc_error_ok) return NSERROR_NOMEM; + lerror = lwc_intern_string("charset", SLEN("charset"), + &textplain_charset); + if (lerror != lwc_error_ok) { + lwc_string_unref(textplain_mime_type); + return NSERROR_NOMEM; + } + + lerror = lwc_intern_string("Windows-1252", SLEN("Windows-1252"), + &textplain_default_charset); + if (lerror != lwc_error_ok) { + lwc_string_unref(textplain_charset); + lwc_string_unref(textplain_mime_type); + return NSERROR_NOMEM; + } + error = content_factory_register_handler(textplain_mime_type, &textplain_content_handler); - if (error != NSERROR_OK) + if (error != NSERROR_OK) { + lwc_string_unref(textplain_default_charset); + lwc_string_unref(textplain_charset); lwc_string_unref(textplain_mime_type); + } return error; } @@ -167,6 +187,8 @@ nserror textplain_init(void) */ void textplain_fini(void) { + lwc_string_unref(textplain_default_charset); + lwc_string_unref(textplain_charset); lwc_string_unref(textplain_mime_type); } @@ -181,7 +203,7 @@ nserror textplain_create(const content_handler *handler, { textplain_content *text; nserror error; - const char *encoding; + lwc_string *encoding; text = talloc_zero(0, textplain_content); if (text == NULL) @@ -194,17 +216,21 @@ nserror textplain_create(const content_handler *handler, return error; } - error = http_parameter_list_find_item(params, "charset", &encoding); + error = http_parameter_list_find_item(params, textplain_charset, + &encoding); if (error != NSERROR_OK) { - encoding = "Windows-1252"; + encoding = lwc_string_ref(textplain_default_charset); } error = textplain_create_internal(text, encoding); if (error != NSERROR_OK) { + lwc_string_unref(encoding); talloc_free(text); return error; } + lwc_string_unref(encoding); + *c = (struct content *) text; return NSERROR_OK; @@ -226,7 +252,7 @@ parserutils_error textplain_charset_hack(const uint8_t *data, size_t len, return PARSERUTILS_OK; } -nserror textplain_create_internal(textplain_content *c, const char *encoding) +nserror textplain_create_internal(textplain_content *c, lwc_string *encoding) { char *utf8_data; parserutils_inputstream *stream; @@ -239,7 +265,7 @@ nserror textplain_create_internal(textplain_content *c, const char *encoding) if (utf8_data == NULL) goto no_memory; - error = parserutils_inputstream_create(encoding, 0, + error = parserutils_inputstream_create(lwc_string_data(encoding), 0, textplain_charset_hack, ns_realloc, NULL, &stream); if (error == PARSERUTILS_BADENCODING) { /* Fall back to Windows-1252 */ @@ -252,13 +278,7 @@ nserror textplain_create_internal(textplain_content *c, const char *encoding) goto no_memory; } - c->encoding = strdup(encoding); - if (c->encoding == NULL) { - talloc_free(utf8_data); - parserutils_inputstream_destroy(stream); - goto no_memory; - } - + c->encoding = lwc_string_ref(encoding); c->inputstream = stream; c->utf8_data = utf8_data; c->utf8_data_size = 0; @@ -527,8 +547,7 @@ void textplain_destroy(struct content *c) { textplain_content *text = (textplain_content *) c; - if (text->encoding != NULL) - free(text->encoding); + lwc_string_unref(text->encoding); if (text->inputstream != NULL) parserutils_inputstream_destroy(text->inputstream); diff --git a/utils/http.c b/utils/http.c deleted file mode 100644 index 7ae2fb386..000000000 --- a/utils/http.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright 2010 John-Mark Bell - * - * 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 . - */ - -/** \file - * HTTP header parsing functions - */ - -#include -#include -#include -#include -#include -#include - -#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; - } - } else { - 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 == ';') { - error = http_parse_parameter_list(&pos, ¶ms); - if (error != NSERROR_OK) { - free(subtype); - free(type); - return error; - } - } - } - - /* + + '/' */ - 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_parse_content_disposition(const char *header_value, - char **disposition_type, http_parameter **parameters) -{ - const char *pos = header_value; - char *type; - http_parameter *params = NULL; - nserror error; - - /* disposition-type *( ";" 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 == ';') { - error = http_parse_parameter_list(&pos, ¶ms); - if (error != NSERROR_OK) { - free(type); - return error; - } - } - - *disposition_type = type; - *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 index f15a10218..173604fb4 100644 --- a/utils/http.h +++ b/utils/http.h @@ -23,63 +23,13 @@ #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); - -/** - * Parse an HTTP Content-Disposition header value - * - * \param header_value Header value to parse - * \param disposition_type Pointer to location to receive disposition type - * \param parameters Pointer to location to receive parameter list - * \return NSERROR_OK on success, - * NSERROR_NOMEM on memory exhaustion - */ -nserror http_parse_content_disposition(const char *header_value, - char **disposition_type, http_parameter **parameters); +#include -/** - * 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); +#include "utils/errors.h" -/** - * Destroy a list of HTTP parameters - * - * \param list List to destroy - */ -void http_parameter_list_destroy(http_parameter *list); +#include "utils/http/content-disposition.h" +#include "utils/http/content-type.h" +#include "utils/http/www-authenticate.h" #endif diff --git a/utils/http/challenge.c b/utils/http/challenge.c new file mode 100644 index 000000000..578532e97 --- /dev/null +++ b/utils/http/challenge.c @@ -0,0 +1,140 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#include + +#include "utils/http.h" + +#include "utils/http/challenge_internal.h" +#include "utils/http/generics.h" +#include "utils/http/parameter_internal.h" +#include "utils/http/primitives.h" + +/** + * Representation of an HTTP challenge + */ +struct http_challenge { + http__item base; + + lwc_string *scheme; /**< Challenge scheme */ + http_parameter *params; /**< Challenge parameters */ +}; + +/** + * Destroy an HTTP challenge + * + * \param self Challenge to destroy + */ +static void http_destroy_challenge(http_challenge *self) +{ + lwc_string_unref(self->scheme); + http_parameter_list_destroy(self->params); + free(self); +} + +/** + * Parse an HTTP challenge + * + * \param input Pointer to current input byte. Updated on exit. + * \param challenge Pointer to location to receive challenge + * \return NSERROR_OK on success, + * NSERROR_NOMEM on memory exhaustion, + * NSERROR_NOT_FOUND if no parameter could be parsed + * + * The returned challenge is owned by the caller. + */ +nserror http__parse_challenge(const char **input, http_challenge **challenge) +{ + const char *pos = *input; + http_challenge *result; + lwc_string *scheme; + http_parameter *first = NULL; + http_parameter *params = NULL; + nserror error; + + /* challenge = auth-scheme 1*SP 1#auth-param + * auth-scheme = token + * auth-param = parameter + */ + + error = http__parse_token(&pos, &scheme); + if (error != NSERROR_OK) + return error; + + if (*pos != ' ' && *pos != '\t') { + lwc_string_unref(scheme); + return NSERROR_NOT_FOUND; + } + + http__skip_LWS(&pos); + + error = http__parse_parameter(&pos, &first); + if (error != NSERROR_OK) { + lwc_string_unref(scheme); + return error; + } + + http__skip_LWS(&pos); + + if (*pos == ',') { + error = http__item_list_parse(&pos, + http__parse_parameter, first, ¶ms); + if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) { + lwc_string_unref(scheme); + return error; + } + } else { + params = first; + } + + result = malloc(sizeof(*result)); + if (result == NULL) { + http_parameter_list_destroy(params); + lwc_string_unref(scheme); + return NSERROR_NOMEM; + } + + HTTP__ITEM_INIT(result, NULL, http_destroy_challenge); + result->scheme = scheme; + result->params = params; + + *challenge = result; + *input = pos; + + return NSERROR_OK; +} + +/* See challenge.h for documentation */ +const http_challenge *http_challenge_list_iterate(const http_challenge *cur, + lwc_string **scheme, http_parameter **parameters) +{ + if (cur == NULL) + return NULL; + + *scheme = lwc_string_ref(cur->scheme); + *parameters = cur->params; + + return (http_challenge *) cur->base.next; +} + +/* See challenge.h for documentation */ +void http_challenge_list_destroy(http_challenge *list) +{ + http__item_list_destroy(list); +} + diff --git a/utils/http/challenge.h b/utils/http/challenge.h new file mode 100644 index 000000000..1e34bb3fa --- /dev/null +++ b/utils/http/challenge.h @@ -0,0 +1,47 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_UTILS_HTTP_CHALLENGE_H_ +#define NETSURF_UTILS_HTTP_CHALLENGE_H_ + +#include + +#include "utils/http/parameter.h" + +typedef struct http_challenge http_challenge; + +/** + * Iterate over a challenge list + * + * \param cur Pointer to current iteration position, list head to start + * \param scheme Pointer to location to receive challenge scheme + * \param parameters Pointer to location to receive challenge parameters + * \return Pointer to next iteration position, or NULL for end of iteration + */ +const http_challenge *http_challenge_list_iterate(const http_challenge *cur, + lwc_string **scheme, http_parameter **parameters); + +/** + * Destroy a list of HTTP challenges + * + * \param list List to destroy + */ +void http_challenge_list_destroy(http_challenge *list); + +#endif + diff --git a/utils/http/challenge_internal.h b/utils/http/challenge_internal.h new file mode 100644 index 000000000..55027648b --- /dev/null +++ b/utils/http/challenge_internal.h @@ -0,0 +1,27 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_UTILS_HTTP_CHALLENGE_INTERNAL_H_ +#define NETSURF_UTILS_HTTP_CHALLENGE_INTERNAL_H_ + +#include "utils/errors.h" +#include "utils/http/challenge.h" + +nserror http__parse_challenge(const char **input, http_challenge **parameter); + +#endif diff --git a/utils/http/content-disposition.c b/utils/http/content-disposition.c new file mode 100644 index 000000000..5d5e94c26 --- /dev/null +++ b/utils/http/content-disposition.c @@ -0,0 +1,78 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#include + +#include "utils/http.h" + +#include "utils/http/generics.h" +#include "utils/http/parameter_internal.h" +#include "utils/http/primitives.h" + +/* See content-disposition.h for documentation */ +nserror http_parse_content_disposition(const char *header_value, + http_content_disposition **result) +{ + const char *pos = header_value; + lwc_string *mtype; + http_parameter *params = NULL; + http_content_disposition *cd; + nserror error; + + /* disposition-type *( ";" parameter ) */ + + http__skip_LWS(&pos); + + error = http__parse_token(&pos, &mtype); + if (error != NSERROR_OK) + return error; + + http__skip_LWS(&pos); + + if (*pos == ';') { + error = http__item_list_parse(&pos, + http__parse_parameter, NULL, ¶ms); + if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) { + lwc_string_unref(mtype); + return error; + } + } + + cd = malloc(sizeof(*cd)); + if (cd == NULL) { + http_parameter_list_destroy(params); + lwc_string_unref(mtype); + return NSERROR_NOMEM; + } + + cd->disposition_type = mtype; + cd->parameters = params; + + *result = cd; + + return NSERROR_OK; +} + +/* See content-disposition.h for documentation */ +void http_content_disposition_destroy(http_content_disposition *victim) +{ + lwc_string_unref(victim->disposition_type); + http_parameter_list_destroy(victim->parameters); + free(victim); +} + diff --git a/utils/http/content-disposition.h b/utils/http/content-disposition.h new file mode 100644 index 000000000..ae2b52030 --- /dev/null +++ b/utils/http/content-disposition.h @@ -0,0 +1,49 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_UTILS_HTTP_CONTENT_DISPOSITION_H_ +#define NETSURF_UTILS_HTTP_CONTENT_DISPOSITION_H_ + +#include + +#include "utils/http/parameter.h" + +typedef struct http_content_disposition { + lwc_string *disposition_type; + http_parameter *parameters; +} http_content_disposition; + +/** + * Parse an HTTP Content-Disposition header value + * + * \param header_value Header value to parse + * \param result Pointer to location to receive result + * \return NSERROR_OK on success, + * NSERROR_NOMEM on memory exhaustion + */ +nserror http_parse_content_disposition(const char *header_value, + http_content_disposition **result); + +/** + * Destroy a content disposition object + * + * \param victim Object to destroy + */ +void http_content_disposition_destroy(http_content_disposition *victim); + +#endif diff --git a/utils/http/content-type.c b/utils/http/content-type.c new file mode 100644 index 000000000..f84da8c8e --- /dev/null +++ b/utils/http/content-type.c @@ -0,0 +1,128 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#include +#include +#include + +#include "utils/http.h" + +#include "utils/http/generics.h" +#include "utils/http/parameter_internal.h" +#include "utils/http/primitives.h" + +/* See content-type.h for documentation */ +nserror http_parse_content_type(const char *header_value, + http_content_type **result) +{ + const char *pos = header_value; + lwc_string *type; + lwc_string *subtype = NULL; + http_parameter *params = NULL; + char *mime; + size_t mime_len; + lwc_string *imime; + http_content_type *ct; + nserror error; + + /* type "/" subtype *( ";" parameter ) */ + + http__skip_LWS(&pos); + + error = http__parse_token(&pos, &type); + if (error != NSERROR_OK) + return error; + + http__skip_LWS(&pos); + + if (*pos != '/') { + lwc_string_unref(type); + return NSERROR_NOT_FOUND; + } + + pos++; + + http__skip_LWS(&pos); + + error = http__parse_token(&pos, &subtype); + if (error != NSERROR_OK) { + lwc_string_unref(type); + return error; + } + + http__skip_LWS(&pos); + + if (*pos == ';') { + error = http__item_list_parse(&pos, + http__parse_parameter, NULL, ¶ms); + if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) { + lwc_string_unref(subtype); + lwc_string_unref(type); + return error; + } + } + + /* + + '/' */ + mime_len = lwc_string_length(type) + lwc_string_length(subtype) + 1; + + mime = malloc(mime_len + 1); + if (mime == NULL) { + http_parameter_list_destroy(params); + lwc_string_unref(subtype); + lwc_string_unref(type); + return NSERROR_NOMEM; + } + + sprintf(mime, "%.*s/%.*s", + (int) lwc_string_length(type), lwc_string_data(type), + (int) lwc_string_length(subtype), lwc_string_data(subtype)); + + lwc_string_unref(subtype); + lwc_string_unref(type); + + if (lwc_intern_string(mime, mime_len, &imime) != lwc_error_ok) { + http_parameter_list_destroy(params); + free(mime); + return NSERROR_NOMEM; + } + + free(mime); + + ct = malloc(sizeof(*ct)); + if (ct == NULL) { + lwc_string_unref(imime); + http_parameter_list_destroy(params); + return NSERROR_NOMEM; + } + + ct->media_type = imime; + ct->parameters = params; + + *result = ct; + + return NSERROR_OK; +} + +/* See content-type.h for documentation */ +void http_content_type_destroy(http_content_type *victim) +{ + lwc_string_unref(victim->media_type); + http_parameter_list_destroy(victim->parameters); + free(victim); +} + diff --git a/utils/http/content-type.h b/utils/http/content-type.h new file mode 100644 index 000000000..840871bb7 --- /dev/null +++ b/utils/http/content-type.h @@ -0,0 +1,49 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_UTILS_HTTP_CONTENT_TYPE_H_ +#define NETSURF_UTILS_HTTP_CONTENT_TYPE_H_ + +#include + +#include "utils/http/parameter.h" + +typedef struct http_content_type { + lwc_string *media_type; + http_parameter *parameters; +} http_content_type; + +/** + * Parse an HTTP Content-Type header value + * + * \param header_value Header value to parse + * \param result Pointer to location to receive result + * \return NSERROR_OK on success, + * NSERROR_NOMEM on memory exhaustion + */ +nserror http_parse_content_type(const char *header_value, + http_content_type **result); + +/** + * Destroy a content type object + * + * \param victim Object to destroy + */ +void http_content_type_destroy(http_content_type *victim); + +#endif diff --git a/utils/http/generics.c b/utils/http/generics.c new file mode 100644 index 000000000..129a56f69 --- /dev/null +++ b/utils/http/generics.c @@ -0,0 +1,99 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#include + +#include "utils/http/generics.h" +#include "utils/http/primitives.h" + +/** + * Destructor for an item list + * + * \param list List to destroy + */ +void http___item_list_destroy(http__item *list) +{ + while (list != NULL) { + http__item *victim = list; + + list = victim->next; + + victim->free(victim); + } +} + +/** + * Parse a list of items + * + * \param input Pointer to current input byte. Updated on exit. + * \param itemparser Pointer to function to parse list items + * \param first Pointer to first item, or NULL. + * \param parameters Pointer to location to receive on-heap parameter list. + * \return NSERROR_OK on success, + * NSERROR_NOMEM on memory exhaustion, + * NSERROR_NOT_FOUND if no items could be parsed + * + * The returned list is owned by the caller + * + * \note Ownership of the \a first item is passed to this function. + */ +nserror http___item_list_parse(const char **input, + http__itemparser itemparser, http__item *first, + http__item **items) +{ + const char *pos = *input; + const char separator = *pos; + http__item *item; + http__item *list = first; + nserror error = NSERROR_OK; + + /* 1*( ) */ + + while (*pos == separator) { + pos++; + + http__skip_LWS(&pos); + + error = itemparser(&pos, &item); + if (error == NSERROR_OK) { + if (list != NULL) + item->next = list; + + list = item; + + http__skip_LWS(&pos); + } else if (error != NSERROR_NOT_FOUND) { + /* Permit LWS */ + break; + } + } + + if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) { + http__item_list_destroy(list); + } else if (list == NULL) { + error = NSERROR_NOT_FOUND; + } else { + error = NSERROR_OK; + *items = list; + *input = pos; + } + + return error; +} + + diff --git a/utils/http/generics.h b/utils/http/generics.h new file mode 100644 index 000000000..3fa498a29 --- /dev/null +++ b/utils/http/generics.h @@ -0,0 +1,54 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_UTILS_HTTP_GENERICS_H_ +#define NETSURF_UTILS_HTTP_GENERICS_H_ + +#include "utils/errors.h" + +/** + * Representation of an item + */ +typedef struct http__item { + struct http__item *next; /**< Next item in list, or NULL */ + + void (*free)(struct http__item *self); /**< Item destructor */ +} http__item; + +#define HTTP__ITEM_INIT(item, n, f) \ + ((http__item *) (item))->next = (http__item *) (n); \ + ((http__item *) (item))->free = (void (*)(http__item *)) (f) + +/** + * Type of an item parser + */ +typedef nserror (*http__itemparser)(const char **input, http__item **item); + + +void http___item_list_destroy(http__item *list); +#define http__item_list_destroy(l) \ + http___item_list_destroy((http__item *) (l)) + +nserror http___item_list_parse(const char **input, + http__itemparser itemparser, http__item *first, + http__item **items); +#define http__item_list_parse(i, p, f, r) \ + http___item_list_parse((i), (http__itemparser) (p), \ + (http__item *) (f), (http__item **) (r)) + +#endif diff --git a/utils/http/parameter.c b/utils/http/parameter.c new file mode 100644 index 000000000..968879d80 --- /dev/null +++ b/utils/http/parameter.c @@ -0,0 +1,153 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#include +#include + +#include "utils/http.h" + +#include "utils/http/generics.h" +#include "utils/http/parameter_internal.h" +#include "utils/http/primitives.h" + +/** + * Representation of an HTTP parameter + */ +struct http_parameter { + http__item base; + + lwc_string *name; /**< Parameter name */ + lwc_string *value; /**< Parameter value */ +}; + +/** + * Destructor for an HTTP parameter + * + * \param self Parameter to destroy + */ +static void http_destroy_parameter(http_parameter *self) +{ + lwc_string_unref(self->name); + lwc_string_unref(self->value); + free(self); +} + +/** + * 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, + * NSERROR_NOT_FOUND if no parameter could be parsed + * + * The returned parameter is owned by the caller. + */ +nserror http__parse_parameter(const char **input, http_parameter **parameter) +{ + const char *pos = *input; + lwc_string *name; + lwc_string *value; + http_parameter *param; + nserror error; + + /* token "=" ( token | quoted-string ) */ + + error = http__parse_token(&pos, &name); + if (error != NSERROR_OK) + return error; + + http__skip_LWS(&pos); + + if (*pos != '=') { + lwc_string_unref(name); + return NSERROR_NOT_FOUND; + } + + pos++; + + http__skip_LWS(&pos); + + if (*pos == '"') + error = http__parse_quoted_string(&pos, &value); + else + error = http__parse_token(&pos, &value); + + if (error != NSERROR_OK) { + lwc_string_unref(name); + return error; + } + + param = malloc(sizeof(*param)); + if (param == NULL) { + lwc_string_unref(value); + lwc_string_unref(name); + return NSERROR_NOMEM; + } + + HTTP__ITEM_INIT(param, NULL, http_destroy_parameter); + param->name = name; + param->value = value; + + *parameter = param; + *input = pos; + + return NSERROR_OK; +} + +/* See parameter.h for documentation */ +nserror http_parameter_list_find_item(const http_parameter *list, + lwc_string *name, lwc_string **value) +{ + bool match; + + while (list != NULL) { + if (lwc_string_caseless_isequal(name, list->name, + &match) == lwc_error_ok && match) + break; + + list = (http_parameter *) list->base.next; + } + + if (list == NULL) + return NSERROR_NOT_FOUND; + + *value = lwc_string_ref(list->value); + + return NSERROR_OK; +} + +/* See parameter.h for documentation */ +const http_parameter *http_parameter_list_iterate(const http_parameter *cur, + lwc_string **name, lwc_string **value) +{ + if (cur == NULL) + return NULL; + + *name = lwc_string_ref(cur->name); + *value = lwc_string_ref(cur->value); + + return (http_parameter *) cur->base.next; +} + +/* See parameter.h for documentation */ +void http_parameter_list_destroy(http_parameter *list) +{ + http__item_list_destroy(list); +} + diff --git a/utils/http/parameter.h b/utils/http/parameter.h new file mode 100644 index 000000000..2f5d41a54 --- /dev/null +++ b/utils/http/parameter.h @@ -0,0 +1,59 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_UTILS_HTTP_PARAMETER_H_ +#define NETSURF_UTILS_HTTP_PARAMETER_H_ + +#include + +#include "utils/errors.h" + +typedef struct http_parameter http_parameter; + +/** + * 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, + lwc_string *name, lwc_string **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, + lwc_string **name, lwc_string **value); + +/** + * Destroy a list of HTTP parameters + * + * \param list List to destroy + */ +void http_parameter_list_destroy(http_parameter *list); + +#endif + diff --git a/utils/http/parameter_internal.h b/utils/http/parameter_internal.h new file mode 100644 index 000000000..a3ab0a02f --- /dev/null +++ b/utils/http/parameter_internal.h @@ -0,0 +1,27 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_UTILS_HTTP_PARAMETER_INTERNAL_H_ +#define NETSURF_UTILS_HTTP_PARAMETER_INTERNAL_H_ + +#include "utils/errors.h" +#include "utils/http/parameter.h" + +nserror http__parse_parameter(const char **input, http_parameter **parameter); + +#endif diff --git a/utils/http/primitives.c b/utils/http/primitives.c new file mode 100644 index 000000000..f4c4e056e --- /dev/null +++ b/utils/http/primitives.c @@ -0,0 +1,146 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#include +#include +#include +#include + +#include "utils/http/primitives.h" + +/** + * Skip past linear whitespace in input + * + * \param input Pointer to current input byte. Updated on exit. + */ +void http__skip_LWS(const char **input) +{ + const char *pos = *input; + + while (*pos == ' ' || *pos == '\t') + pos++; + + *input = pos; +} + +/** + * 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, + * NSERROR_NOT_FOUND if no token could be parsed + * + * The returned value is owned by the caller + */ +nserror http__parse_token(const char **input, lwc_string **value) +{ + const uint8_t *start = (const uint8_t *) *input; + const uint8_t *end; + lwc_string *token; + + end = start; + while (http_is_token_char(*end)) + end++; + + if (end == start) + return NSERROR_NOT_FOUND; + + if (lwc_intern_string((const char *) start, + end - start, &token) != lwc_error_ok) + return NSERROR_NOMEM; + + *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, + * NSERROR_NOT_FOUND if no string could be parsed + * + * The returned value is owned by the caller + */ +nserror http__parse_quoted_string(const char **input, lwc_string **value) +{ + const uint8_t *start = (const uint8_t *) *input; + const uint8_t *end; + uint8_t c; + lwc_string *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 != '"') + return NSERROR_NOT_FOUND; + + 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 != '"') + return NSERROR_NOT_FOUND; + + if (lwc_intern_string((const char *) start, end - start, + &string_value) != lwc_error_ok) + return NSERROR_NOMEM; + + *value = string_value; + + *input = (const char *) end + 1; + + return NSERROR_OK; +} + + diff --git a/utils/http/primitives.h b/utils/http/primitives.h new file mode 100644 index 000000000..b8b6abbc0 --- /dev/null +++ b/utils/http/primitives.h @@ -0,0 +1,32 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_UTILS_HTTP_PRIMITIVES_H_ +#define NETSURF_UTILS_HTTP_PRIMITIVES_H_ + +#include + +#include "utils/errors.h" + +void http__skip_LWS(const char **input); + +nserror http__parse_token(const char **input, lwc_string **value); + +nserror http__parse_quoted_string(const char **input, lwc_string **value); + +#endif diff --git a/utils/http/www-authenticate.c b/utils/http/www-authenticate.c new file mode 100644 index 000000000..b263fdf31 --- /dev/null +++ b/utils/http/www-authenticate.c @@ -0,0 +1,75 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#include + +#include "utils/http/challenge_internal.h" +#include "utils/http/generics.h" +#include "utils/http/parameter_internal.h" +#include "utils/http/primitives.h" +#include "utils/http/www-authenticate.h" + +/* See www-authenticate.h for documentation */ +nserror http_parse_www_authenticate(const char *header_value, + http_www_authenticate **result) +{ + const char *pos = header_value; + http_challenge *first = NULL; + http_challenge *list = NULL; + http_www_authenticate *wa; + nserror error; + + /* 1#challenge */ + + http__skip_LWS(&pos); + + error = http__parse_challenge(&pos, &first); + if (error != NSERROR_OK) + return error; + + http__skip_LWS(&pos); + + if (*pos == ',') { + error = http__item_list_parse(&pos, + http__parse_challenge, first, &list); + if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) + return error; + } else { + list = first; + } + + wa = malloc(sizeof(*wa)); + if (wa == NULL) { + http_challenge_list_destroy(list); + return NSERROR_NOMEM; + } + + wa->challenges = list; + + *result = wa; + + return NSERROR_OK; +} + +/* See www-authenticate.h for documentation */ +void http_www_authenticate_destroy(http_www_authenticate *victim) +{ + http_challenge_list_destroy(victim->challenges); + free(victim); +} + diff --git a/utils/http/www-authenticate.h b/utils/http/www-authenticate.h new file mode 100644 index 000000000..105ca385a --- /dev/null +++ b/utils/http/www-authenticate.h @@ -0,0 +1,48 @@ +/* + * Copyright 2010 John-Mark Bell + * + * 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 . + */ + +#ifndef NETSURF_UTILS_HTTP_WWW_AUTHENTICATE_H_ +#define NETSURF_UTILS_HTTP_WWW_AUTHENTICATE_H_ + +#include + +#include "utils/http/challenge.h" + +typedef struct http_www_authenticate { + http_challenge *challenges; +} http_www_authenticate; + +/** + * Parse an HTTP WWW-Authenticate header value + * + * \param header_value Header value to parse + * \param result Pointer to location to receive result + * \return NSERROR_OK on success, + * NSERROR_NOMEM on memory exhaustion + */ +nserror http_parse_www_authenticate(const char *header_value, + http_www_authenticate **result); + +/** + * Destroy a www authenticate object + * + * \param victim Object to destroy + */ +void http_www_authenticate_destroy(http_www_authenticate *victim); + +#endif -- cgit v1.2.3