summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.sources6
-rw-r--r--content/content_factory.c46
-rw-r--r--content/content_factory.h2
-rw-r--r--content/hlcache.c11
-rw-r--r--css/css.c26
-rw-r--r--desktop/download.c54
-rw-r--r--render/box_construct.c47
-rw-r--r--render/html.c21
-rw-r--r--render/textplain.c53
-rw-r--r--utils/http.c423
-rw-r--r--utils/http.h60
-rw-r--r--utils/http/challenge.c140
-rw-r--r--utils/http/challenge.h47
-rw-r--r--utils/http/challenge_internal.h27
-rw-r--r--utils/http/content-disposition.c78
-rw-r--r--utils/http/content-disposition.h49
-rw-r--r--utils/http/content-type.c128
-rw-r--r--utils/http/content-type.h49
-rw-r--r--utils/http/generics.c99
-rw-r--r--utils/http/generics.h54
-rw-r--r--utils/http/parameter.c153
-rw-r--r--utils/http/parameter.h59
-rw-r--r--utils/http/parameter_internal.h27
-rw-r--r--utils/http/primitives.c146
-rw-r--r--utils/http/primitives.h32
-rw-r--r--utils/http/www-authenticate.c75
-rw-r--r--utils/http/www-authenticate.h48
27 files changed, 1380 insertions, 580 deletions
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,
- &params);
+ 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,
- &params);
+ 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, &params);
+ 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, &params);
+ &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 <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;
- }
- } 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, &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 == ';') {
- 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_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, &params);
- 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 <libwapcaplet/libwapcaplet.h>
-/**
- * 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 <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/>.
+ */
+
+#include <stdlib.h>
+
+#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, &params);
+ 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 <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/>.
+ */
+
+#ifndef NETSURF_UTILS_HTTP_CHALLENGE_H_
+#define NETSURF_UTILS_HTTP_CHALLENGE_H_
+
+#include <libwapcaplet/libwapcaplet.h>
+
+#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 <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/>.
+ */
+
+#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 <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/>.
+ */
+
+#include <stdlib.h>
+
+#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, &params);
+ 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 <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/>.
+ */
+
+#ifndef NETSURF_UTILS_HTTP_CONTENT_DISPOSITION_H_
+#define NETSURF_UTILS_HTTP_CONTENT_DISPOSITION_H_
+
+#include <libwapcaplet/libwapcaplet.h>
+
+#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 <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/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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, &params);
+ if (error != NSERROR_OK && error != NSERROR_NOT_FOUND) {
+ lwc_string_unref(subtype);
+ lwc_string_unref(type);
+ return error;
+ }
+ }
+
+ /* <type> + <subtype> + '/' */
+ 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 <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/>.
+ */
+
+#ifndef NETSURF_UTILS_HTTP_CONTENT_TYPE_H_
+#define NETSURF_UTILS_HTTP_CONTENT_TYPE_H_
+
+#include <libwapcaplet/libwapcaplet.h>
+
+#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 <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/>.
+ */
+
+#include <stdlib.h>
+
+#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*( <separator> <item> ) */
+
+ 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 <separator> LWS <separator> */
+ 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 <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/>.
+ */
+
+#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 <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/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#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 <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/>.
+ */
+
+#ifndef NETSURF_UTILS_HTTP_PARAMETER_H_
+#define NETSURF_UTILS_HTTP_PARAMETER_H_
+
+#include <libwapcaplet/libwapcaplet.h>
+
+#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 <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/>.
+ */
+
+#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 <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/>.
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <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/>.
+ */
+
+#ifndef NETSURF_UTILS_HTTP_PRIMITIVES_H_
+#define NETSURF_UTILS_HTTP_PRIMITIVES_H_
+
+#include <libwapcaplet/libwapcaplet.h>
+
+#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 <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/>.
+ */
+
+#include <stdlib.h>
+
+#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 <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/>.
+ */
+
+#ifndef NETSURF_UTILS_HTTP_WWW_AUTHENTICATE_H_
+#define NETSURF_UTILS_HTTP_WWW_AUTHENTICATE_H_
+
+#include <libwapcaplet/libwapcaplet.h>
+
+#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