summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@src.gnome.org>2007-11-30 02:27:10 +0000
committerDan Winship <danw@src.gnome.org>2007-11-30 02:27:10 +0000
commita283ae769f481518a2be9da17c718b3d7a6ea24b (patch)
treeef5e20c87fddae1f2f5f6b06f719846b705bc20f
parenta3b3d382c0b5ff6978b9437bd2fe607681d718ba (diff)
downloadlibsoup-bindings.tar.gz
new opaque type for message headers. Currently still a GHashTablelibsoup-bindings
* libsoup/soup-message-headers.c: new opaque type for message headers. Currently still a GHashTable underneath, for backward-compatibility, but that will change in the future. * libsoup/soup-message.c: Use SoupMessageHeaders. Deprecate the old header methods * ...: use SoupMessageHeaders * python/libsoup.defs: update for SoupMessageHeaders, add fields to SoupMessage svn path=/branches/libsoup-bindings/; revision=967
-rw-r--r--ChangeLog14
-rw-r--r--libsoup/Makefile.am2
-rw-r--r--libsoup/soup-auth.c22
-rw-r--r--libsoup/soup-auth.h4
-rw-r--r--libsoup/soup-connection-ntlm.c26
-rw-r--r--libsoup/soup-headers.c44
-rw-r--r--libsoup/soup-headers.h36
-rw-r--r--libsoup/soup-message-client-io.c21
-rw-r--r--libsoup/soup-message-handlers.c4
-rw-r--r--libsoup/soup-message-headers.c221
-rw-r--r--libsoup/soup-message-headers.h44
-rw-r--r--libsoup/soup-message-io.c4
-rw-r--r--libsoup/soup-message-server-io.c17
-rw-r--r--libsoup/soup-message.c219
-rw-r--r--libsoup/soup-message.h33
-rw-r--r--libsoup/soup-server-auth.c83
-rw-r--r--libsoup/soup-server-auth.h2
-rw-r--r--libsoup/soup-server.c8
-rw-r--r--libsoup/soup-session.c29
-rw-r--r--libsoup/soup.h1
-rw-r--r--python/libsoup.defs141
-rw-r--r--tests/auth-test.c4
-rw-r--r--tests/dict.c4
-rw-r--r--tests/get.c10
-rw-r--r--tests/header-parsing.c63
-rw-r--r--tests/ntlm-test.c31
-rw-r--r--tests/simple-httpd.c10
-rw-r--r--tests/simple-proxy.c19
28 files changed, 604 insertions, 512 deletions
diff --git a/ChangeLog b/ChangeLog
index 72c0fcab..a4658f5e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
2007-11-29 Dan Winship <danw@gnome.org>
+ * libsoup/soup-message-headers.c: new opaque type for message
+ headers. Currently still a GHashTable underneath, for
+ backward-compatibility, but that will change in the future.
+
+ * libsoup/soup-message.c: Use SoupMessageHeaders. Deprecate the
+ old header methods
+
+ * ...: use SoupMessageHeaders
+
+ * python/libsoup.defs: update for SoupMessageHeaders, add fields
+ to SoupMessage
+
+2007-11-29 Dan Winship <danw@gnome.org>
+
* libsoup/soup-message.c:
* libsoup/soup-session.c: Make SoupMessage's uri property and
SoupSession's proxy_uri property use a boxed pspec
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
index f36bb954..e477f85f 100644
--- a/libsoup/Makefile.am
+++ b/libsoup/Makefile.am
@@ -62,6 +62,7 @@ soup_headers = \
soup-headers.h \
soup-message.h \
soup-message-filter.h \
+ soup-message-headers.h \
soup-message-queue.h \
soup-method.h \
soup-misc.h \
@@ -122,6 +123,7 @@ libsoup_2_2_la_SOURCES = \
soup-message-client-io.c \
soup-message-filter.c \
soup-message-handlers.c \
+ soup-message-headers.c \
soup-message-io.c \
soup-message-private.h \
soup-message-queue.c \
diff --git a/libsoup/soup-auth.c b/libsoup/soup-auth.c
index 51ad491a..03ad437a 100644
--- a/libsoup/soup-auth.c
+++ b/libsoup/soup-auth.c
@@ -59,27 +59,29 @@ static AuthScheme known_auth_schemes [] = {
/* FIXME: it should be possible to register new auth schemes! */
/**
- * soup_auth_new_from_header_list:
- * @vals: a list of WWW-Authenticate headers from a server response
+ * soup_auth_new_from_headers:
+ * @hdrs: the response headers from a message
+ * @header_name: the name of the header to look for
+ * ("WWW-Authenticate" or "Proxy-Authenticate")
*
* Creates a #SoupAuth value based on the strongest available
- * supported auth type in @vals.
+ * supported auth type in @headers.
*
* Return value: the new #SoupAuth, or %NULL if none could be created.
**/
SoupAuth *
-soup_auth_new_from_header_list (const GSList *vals)
+soup_auth_new_from_headers (SoupMessageHeaders *hdrs, const char *header_name)
{
- char *header = NULL, *realm;
+ const char *tryheader, *header = NULL;
AuthScheme *scheme = NULL, *iter;
SoupAuth *auth = NULL;
GHashTable *params;
+ char *realm;
+ int i;
- g_return_val_if_fail (vals != NULL, NULL);
-
- while (vals) {
- char *tryheader = vals->data;
+ g_return_val_if_fail (hdrs != NULL, NULL);
+ for (i = 0; (tryheader = soup_message_headers_find_nth (hdrs, header_name, i)); i++) {
for (iter = known_auth_schemes; iter->name; iter++) {
if (!g_ascii_strncasecmp (tryheader, iter->name,
iter->len) &&
@@ -94,8 +96,6 @@ soup_auth_new_from_header_list (const GSList *vals)
break;
}
}
-
- vals = vals->next;
}
if (!scheme)
diff --git a/libsoup/soup-auth.h b/libsoup/soup-auth.h
index 0feda0c7..2f58a99b 100644
--- a/libsoup/soup-auth.h
+++ b/libsoup/soup-auth.h
@@ -7,6 +7,7 @@
#define SOUP_AUTH_H 1
#include <libsoup/soup-types.h>
+#include <libsoup/soup-headers.h>
#define SOUP_TYPE_AUTH (soup_auth_get_type ())
#define SOUP_AUTH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_AUTH, SoupAuth))
@@ -44,7 +45,8 @@ typedef struct {
GType soup_auth_get_type (void);
-SoupAuth *soup_auth_new_from_header_list (const GSList *vals);
+SoupAuth *soup_auth_new_from_headers (SoupMessageHeaders *hdrs,
+ const char *header_name);
const char *soup_auth_get_scheme_name (SoupAuth *auth);
const char *soup_auth_get_realm (SoupAuth *auth);
diff --git a/libsoup/soup-connection-ntlm.c b/libsoup/soup-connection-ntlm.c
index 1ffb66b0..e03275d3 100644
--- a/libsoup/soup-connection-ntlm.c
+++ b/libsoup/soup-connection-ntlm.c
@@ -79,11 +79,11 @@ ntlm_authorize_pre (SoupMessage *msg, gpointer user_data)
{
SoupConnectionNTLM *ntlm = user_data;
SoupConnectionNTLMPrivate *priv = SOUP_CONNECTION_NTLM_GET_PRIVATE (ntlm);
- const GSList *headers;
const char *val;
char *nonce, *header;
char *username, *domain_username = NULL, *password = NULL;
char *slash, *domain;
+ int i;
if (priv->state > SOUP_CONNECTION_NTLM_SENT_REQUEST) {
/* We already authenticated, but then got another 401.
@@ -94,15 +94,13 @@ ntlm_authorize_pre (SoupMessage *msg, gpointer user_data)
goto done;
}
- headers = soup_message_get_header_list (msg->response_headers,
- "WWW-Authenticate");
- while (headers) {
- val = headers->data;
+ i = 0;
+ while ((val = soup_message_headers_find_nth (msg->response_headers,
+ "WWW-Authenticate", i))) {
if (!strncmp (val, "NTLM ", 5))
break;
- headers = headers->next;
}
- if (!headers) {
+ if (!val) {
priv->state = SOUP_CONNECTION_NTLM_FAILED;
goto done;
}
@@ -139,9 +137,7 @@ ntlm_authorize_pre (SoupMessage *msg, gpointer user_data)
g_free (domain);
g_free (nonce);
- soup_message_remove_header (msg->request_headers, "Authorization");
- soup_message_add_header (msg->request_headers,
- "Authorization", header);
+ soup_message_headers_replace (msg->request_headers, "Authorization", header);
g_free (header);
priv->state = SOUP_CONNECTION_NTLM_RECEIVED_CHALLENGE;
@@ -149,7 +145,7 @@ ntlm_authorize_pre (SoupMessage *msg, gpointer user_data)
/* Remove the WWW-Authenticate headers so the session won't try
* to do Basic auth too.
*/
- soup_message_remove_header (msg->response_headers, "WWW-Authenticate");
+ soup_message_headers_remove (msg->response_headers, "WWW-Authenticate");
}
static void
@@ -158,7 +154,7 @@ ntlm_authorize_post (SoupMessage *msg, gpointer conn)
SoupConnectionNTLMPrivate *priv = SOUP_CONNECTION_NTLM_GET_PRIVATE (conn);
if (priv->state == SOUP_CONNECTION_NTLM_RECEIVED_CHALLENGE &&
- soup_message_get_header (msg->request_headers, "Authorization")) {
+ soup_message_headers_find (msg->request_headers, "Authorization")) {
/* We just added the last Auth header, so restart it. */
priv->state = SOUP_CONNECTION_NTLM_SENT_RESPONSE;
@@ -196,10 +192,8 @@ send_request (SoupConnection *conn, SoupMessage *req)
if (priv->state == SOUP_CONNECTION_NTLM_NEW) {
char *header = soup_ntlm_request ();
- soup_message_remove_header (req->request_headers,
- "Authorization");
- soup_message_add_header (req->request_headers,
- "Authorization", header);
+ soup_message_headers_replace (req->request_headers,
+ "Authorization", header);
g_free (header);
priv->state = SOUP_CONNECTION_NTLM_SENT_REQUEST;
}
diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c
index dd7b5162..2bf4593c 100644
--- a/libsoup/soup-headers.c
+++ b/libsoup/soup-headers.c
@@ -14,14 +14,11 @@
#include "soup-misc.h"
static gboolean
-soup_headers_parse (const char *str,
- int len,
- GHashTable *dest)
+soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest)
{
const char *end = str + len;
const char *name_start, *name_end, *value_start, *value_end;
char *name, *value, *eol, *sol;
- GSList *hdrs;
/* Technically, the grammar does allow NUL bytes in the
* headers, but this is probably a bug, and if it's not, we
@@ -91,12 +88,7 @@ soup_headers_parse (const char *str,
eol--;
*eol = '\0';
- hdrs = g_hash_table_lookup (dest, name);
- hdrs = g_slist_append (hdrs, value);
- if (!hdrs->next)
- g_hash_table_insert (dest, name, hdrs);
- else
- g_free (name);
+ soup_message_headers_append (dest, name, value);
}
return TRUE;
@@ -106,7 +98,7 @@ soup_headers_parse (const char *str,
* soup_headers_parse_request:
* @str: the header string (including the trailing blank line)
* @len: length of @str up to (but not including) the terminating blank line.
- * @dest: #GHashTable to store the header values in
+ * @req_headers: #SoupMessageHeaders to store the header values in
* @req_method: if non-%NULL, will be filled in with the request method
* @req_path: if non-%NULL, will be filled in with the request path
* @ver: if non-%NULL, will be filled in with the HTTP version
@@ -119,12 +111,12 @@ soup_headers_parse (const char *str,
* Return value: success or failure.
**/
gboolean
-soup_headers_parse_request (const char *str,
- int len,
- GHashTable *dest,
- char **req_method,
- char **req_path,
- SoupHttpVersion *ver)
+soup_headers_parse_request (const char *str,
+ int len,
+ SoupMessageHeaders *req_headers,
+ char **req_method,
+ char **req_path,
+ SoupHttpVersion *ver)
{
const char *method, *method_end, *path, *path_end, *version, *headers;
int minor_version;
@@ -183,7 +175,7 @@ soup_headers_parse_request (const char *str,
if (headers >= str + len || *headers != '\n')
return FALSE;
- if (!soup_headers_parse (str, len, dest))
+ if (!soup_headers_parse (str, len, req_headers))
return FALSE;
if (req_method)
@@ -258,7 +250,7 @@ soup_headers_parse_status_line (const char *status_line,
* soup_headers_parse_response:
* @str: the header string (including the trailing blank line)
* @len: length of @str up to (but not including) the terminating blank line.
- * @dest: #GHashTable to store the header values in
+ * @headers: #SoupMessageheaders to store the header values in
* @ver: if non-%NULL, will be filled in with the HTTP version
* @status_code: if non-%NULL, will be filled in with the status code
* @reason_phrase: if non-%NULL, will be filled in with the reason
@@ -272,17 +264,17 @@ soup_headers_parse_status_line (const char *status_line,
* Return value: success or failure.
**/
gboolean
-soup_headers_parse_response (const char *str,
- int len,
- GHashTable *dest,
- SoupHttpVersion *ver,
- guint *status_code,
- char **reason_phrase)
+soup_headers_parse_response (const char *str,
+ int len,
+ SoupMessageHeaders *headers,
+ SoupHttpVersion *ver,
+ guint *status_code,
+ char **reason_phrase)
{
if (!str || !*str)
return FALSE;
- if (!soup_headers_parse (str, len, dest))
+ if (!soup_headers_parse (str, len, headers))
return FALSE;
if (!soup_headers_parse_status_line (str,
diff --git a/libsoup/soup-headers.h b/libsoup/soup-headers.h
index 428ab940..1e2649f2 100644
--- a/libsoup/soup-headers.h
+++ b/libsoup/soup-headers.h
@@ -13,24 +13,24 @@ G_BEGIN_DECLS
/* HTTP Header Parsing */
-gboolean soup_headers_parse_request (const char *str,
- int len,
- GHashTable *dest,
- char **req_method,
- char **req_path,
- SoupHttpVersion *ver);
-
-gboolean soup_headers_parse_status_line (const char *status_line,
- SoupHttpVersion *ver,
- guint *status_code,
- char **reason_phrase);
-
-gboolean soup_headers_parse_response (const char *str,
- int len,
- GHashTable *dest,
- SoupHttpVersion *ver,
- guint *status_code,
- char **reason_phrase);
+gboolean soup_headers_parse_request (const char *str,
+ int len,
+ SoupMessageHeaders *req_headers,
+ char **req_method,
+ char **req_path,
+ SoupHttpVersion *ver);
+
+gboolean soup_headers_parse_status_line (const char *status_line,
+ SoupHttpVersion *ver,
+ guint *status_code,
+ char **reason_phrase);
+
+gboolean soup_headers_parse_response (const char *str,
+ int len,
+ SoupMessageHeaders *headers,
+ SoupHttpVersion *ver,
+ guint *status_code,
+ char **reason_phrase);
/* HTTP parameterized header parsing */
diff --git a/libsoup/soup-message-client-io.c b/libsoup/soup-message-client-io.c
index 109d976c..e89d0850 100644
--- a/libsoup/soup-message-client-io.c
+++ b/libsoup/soup-message-client-io.c
@@ -26,7 +26,6 @@ parse_response_headers (SoupMessage *req,
{
SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (req);
SoupHttpVersion version;
- GHashTable *resp_hdrs;
g_free((char*)req->reason_phrase);
req->reason_phrase = NULL;
@@ -40,8 +39,6 @@ parse_response_headers (SoupMessage *req,
if (version < priv->http_version)
priv->http_version = version;
- resp_hdrs = req->response_headers;
-
*encoding = soup_message_get_response_encoding (req, content_len);
if (*encoding == SOUP_TRANSFER_NONE) {
*encoding = SOUP_TRANSFER_CONTENT_LENGTH;
@@ -53,12 +50,10 @@ parse_response_headers (SoupMessage *req,
}
static void
-add_header (gpointer name, gpointer value, gpointer data)
+add_header (const char *name, const char *value, gpointer data)
{
GString *headers = data;
-
- g_string_append_printf (headers, "%s: %s\r\n",
- (char *)name, (char *)value);
+ g_string_append_printf (headers, "%s: %s\r\n", name, value);
}
static void
@@ -99,21 +94,17 @@ get_request_headers (SoupMessage *req, GString *header,
g_free (uri_string);
if (req->request.length > 0) {
- if (!soup_message_get_header (req->request_headers,
- "Content-Type")) {
- g_string_append (header, "Content-Type: text/xml; "
- "charset=utf-8\r\n");
- }
g_string_append_printf (header, "Content-Length: %d\r\n",
req->request.length);
*encoding = SOUP_TRANSFER_CONTENT_LENGTH;
}
- soup_message_foreach_header (req->request_headers, add_header, header);
+ soup_message_headers_foreach (req->request_headers, add_header, header);
g_string_append (header, "\r\n");
- expect = soup_message_get_header (req->request_headers, "Expect");
- if (expect && !strcmp (expect, "100-continue"))
+ /* FIXME: parsing */
+ expect = soup_message_headers_find (req->request_headers, "Expect");
+ if (expect && !g_ascii_strcasecmp (expect, "100-continue"))
priv->msg_flags |= SOUP_MESSAGE_EXPECT_CONTINUE;
}
diff --git a/libsoup/soup-message-handlers.c b/libsoup/soup-message-handlers.c
index 3d598213..3295d08d 100644
--- a/libsoup/soup-message-handlers.c
+++ b/libsoup/soup-message-handlers.c
@@ -41,8 +41,8 @@ run_handler (SoupMessage *msg,
switch (data->kind) {
case SOUP_HANDLER_HEADER:
- if (!soup_message_get_header (msg->response_headers,
- data->data.header))
+ if (!soup_message_headers_find (msg->response_headers,
+ data->data.header))
return;
break;
case SOUP_HANDLER_STATUS_CODE:
diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
new file mode 100644
index 00000000..a4a2e834
--- /dev/null
+++ b/libsoup/soup-message-headers.c
@@ -0,0 +1,221 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-message-headers.c: HTTP message header arrays
+ *
+ * Copyright (C) 2005 Novell, Inc.
+ */
+
+#include "soup-message-headers.h"
+#include "soup-misc.h"
+
+GType
+soup_message_headers_get_type (void)
+{
+ static GType type = 0;
+
+ if (type == 0)
+ type = g_pointer_type_register_static ("SoupMessageHeaders");
+ return type;
+}
+
+/**
+ * soup_message_headers_new:
+ *
+ * Creates a #SoupMessageHeaders
+ *
+ * Return value: a new #SoupMessageHeaders
+ **/
+SoupMessageHeaders *
+soup_message_headers_new (void)
+{
+ GHashTable *hdrs = g_hash_table_new (soup_str_case_hash,
+ soup_str_case_equal);
+
+ return (SoupMessageHeaders *)hdrs;
+}
+
+/**
+ * soup_message_headers_free:
+ * @hdrs: a #SoupMessageHeaders
+ *
+ * Frees @hdrs.
+ **/
+void
+soup_message_headers_free (SoupMessageHeaders *hdrs)
+{
+ soup_message_headers_clear (hdrs);
+ g_hash_table_destroy ((GHashTable *)hdrs);
+}
+
+static gboolean
+free_header_list (gpointer name, gpointer vals, gpointer user_data)
+{
+ g_free (name);
+ g_slist_foreach (vals, (GFunc) g_free, NULL);
+ g_slist_free (vals);
+
+ return TRUE;
+}
+
+/**
+ * soup_message_headers_clear:
+ * @hdrs: a #SoupMessageHeaders
+ *
+ * Clears @hdrs.
+ **/
+void
+soup_message_headers_clear (SoupMessageHeaders *hdrs)
+{
+ g_hash_table_foreach_remove ((GHashTable *)hdrs,
+ free_header_list, NULL);
+}
+
+/**
+ * soup_message_headers_append:
+ * @hdrs: a #SoupMessageHeaders
+ * @name: the header name to add
+ * @value: the new value of @name
+ *
+ * Appends a new header with name @name and value @value to @hdrs. If
+ * there were already other instances of header @name in @hdrs, they
+ * are preserved.
+ **/
+void
+soup_message_headers_append (SoupMessageHeaders *hdrs,
+ const char *name, const char *value)
+{
+ GHashTable *hash = (GHashTable *)hdrs;
+ GSList *old_value;
+
+ g_return_if_fail (hash != NULL);
+ g_return_if_fail (name != NULL && name [0] != '\0');
+ g_return_if_fail (value != NULL);
+
+ old_value = g_hash_table_lookup (hash, name);
+
+ if (old_value)
+ old_value = g_slist_append (old_value, g_strdup (value));
+ else {
+ g_hash_table_insert (hash, g_strdup (name),
+ g_slist_append (NULL, g_strdup (value)));
+ }
+}
+
+/**
+ * soup_message_headers_replace:
+ * @hdrs: a #SoupMessageHeaders
+ * @name: the header name to replace
+ * @value: the new value of @name
+ *
+ * Replaces the value of the header @name in @hdrs with @value. If
+ * there were previously multiple values for @name, all of the other
+ * values are removed.
+ **/
+void
+soup_message_headers_replace (SoupMessageHeaders *hdrs,
+ const char *name, const char *value)
+{
+ soup_message_headers_remove (hdrs, name);
+ soup_message_headers_append (hdrs, name, value);
+}
+
+/**
+ * soup_message_headers_remove:
+ * @hdrs: a #SoupMessageHeaders
+ * @name: the header name to remove
+ *
+ * Removes @name from @hdrs. If there are multiple values for @name,
+ * they are all removed.
+ **/
+void
+soup_message_headers_remove (SoupMessageHeaders *hdrs, const char *name)
+{
+ GHashTable *hash = (GHashTable *)hdrs;
+ gpointer old_key, old_vals;
+
+ g_return_if_fail (hash != NULL);
+ g_return_if_fail (name != NULL && name[0] != '\0');
+
+ if (g_hash_table_lookup_extended (hash, name, &old_key, &old_vals)) {
+ g_hash_table_remove (hash, name);
+ free_header_list (old_key, old_vals, NULL);
+ }
+}
+
+/**
+ * soup_message_headers_find:
+ * @hdrs: a #SoupMessageHeaders
+ * @name: header name
+ *
+ * Finds the first header in @hdrs with name @name.
+ *
+ * Return value: the header's value or %NULL if not found.
+ **/
+
+/**
+ * soup_message_headers_find_nth:
+ * @hdrs: a #SoupMessageHeaders
+ * @name: header name
+ * @nth: which instance of header @name to find
+ *
+ * Finds the @nth header in @hdrs with name @name (counting from 0).
+ *
+ * Return value: the header's value or %NULL if not found.
+ **/
+const char *
+soup_message_headers_find_nth (SoupMessageHeaders *hdrs,
+ const char *name, int nth)
+{
+ GHashTable *hash = (GHashTable *)hdrs;
+ GList *vals;
+
+ g_return_val_if_fail (hash != NULL, NULL);
+ g_return_val_if_fail (name != NULL && name [0] != '\0', NULL);
+
+ vals = g_hash_table_lookup (hash, name);
+ vals = g_list_nth (vals, nth);
+ return vals ? vals->data : NULL;
+}
+
+typedef struct {
+ SoupMessageHeadersForeachFunc func;
+ gpointer user_data;
+} SoupMessageHeadersForeachData;
+
+static void
+foreach_value_in_list (gpointer name, gpointer value, gpointer user_data)
+{
+ GSList *vals = value;
+ SoupMessageHeadersForeachData *data = user_data;
+
+ while (vals) {
+ (*data->func) (name, vals->data, data->user_data);
+ vals = vals->next;
+ }
+}
+
+/**
+ * soup_message_headers_foreach:
+ * @hdrs: a #SoupMessageHeaders
+ * @func: callback function to run for each header
+ * @user_data: data to pass to @func
+ *
+ * Calls @func once for each header value in @hdrs. (If there are
+ * headers with multiple values, @func will be called once on each
+ * value.)
+ **/
+void
+soup_message_headers_foreach (SoupMessageHeaders *hdrs,
+ SoupMessageHeadersForeachFunc func,
+ gpointer user_data)
+{
+ GHashTable *hash = (GHashTable *)hdrs;
+ SoupMessageHeadersForeachData data;
+
+ g_return_if_fail (hash != NULL);
+ g_return_if_fail (func != NULL);
+
+ data.func = func;
+ data.user_data = user_data;
+ g_hash_table_foreach (hash, foreach_value_in_list, &data);
+}
diff --git a/libsoup/soup-message-headers.h b/libsoup/soup-message-headers.h
new file mode 100644
index 00000000..6a03f7d9
--- /dev/null
+++ b/libsoup/soup-message-headers.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005 Novell, Inc.
+ */
+
+#ifndef SOUP_MESSAGE_HEADERS_H
+#define SOUP_MESSAGE_HEADERS_H 1
+
+#include <libsoup/soup-types.h>
+
+typedef struct SoupMessageHeaders SoupMessageHeaders;
+
+GType soup_message_headers_get_type (void);
+#define SOUP_TYPE_MESSAGE_HEADERS (soup_message_headers_get_type ())
+
+SoupMessageHeaders *soup_message_headers_new (void);
+
+void soup_message_headers_free (SoupMessageHeaders *hdrs);
+
+void soup_message_headers_append (SoupMessageHeaders *hdrs,
+ const char *name,
+ const char *value);
+void soup_message_headers_replace (SoupMessageHeaders *hdrs,
+ const char *name,
+ const char *value);
+
+void soup_message_headers_remove (SoupMessageHeaders *hdrs,
+ const char *name);
+void soup_message_headers_clear (SoupMessageHeaders *hdrs);
+
+const char *soup_message_headers_find_nth (SoupMessageHeaders *hdrs,
+ const char *name,
+ int index);
+#define soup_message_headers_find(hdrs, name) (soup_message_headers_find_nth (hdrs, name, 0))
+
+typedef void (*SoupMessageHeadersForeachFunc)(const char *name,
+ const char *value,
+ gpointer user_data);
+
+void soup_message_headers_foreach (SoupMessageHeaders *hdrs,
+ SoupMessageHeadersForeachFunc func,
+ gpointer user_data);
+
+#endif /* SOUP_MESSAGE_HEADERS_H */
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c
index 7c089e87..7995e652 100644
--- a/libsoup/soup-message-io.c
+++ b/libsoup/soup-message-io.c
@@ -597,8 +597,8 @@ io_read (SoupSocket *sock, SoupMessage *msg)
* closed when we're done.
*/
soup_message_set_status (msg, status);
- soup_message_add_header (msg->request_headers,
- "Connection", "close");
+ soup_message_headers_append (msg->request_headers,
+ "Connection", "close");
io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
break;
}
diff --git a/libsoup/soup-message-server-io.c b/libsoup/soup-message-server-io.c
index 44373e4f..45881782 100644
--- a/libsoup/soup-message-server-io.c
+++ b/libsoup/soup-message-server-io.c
@@ -43,7 +43,7 @@ parse_request_headers (SoupMessage *msg, char *headers, guint headers_len,
NULL);
g_free (req_method);
- expect = soup_message_get_header (msg->request_headers, "Expect");
+ expect = soup_message_headers_find (msg->request_headers, "Expect");
if (expect && !strcmp (expect, "100-continue"))
priv->msg_flags |= SOUP_MESSAGE_EXPECT_CONTINUE;
@@ -53,7 +53,7 @@ parse_request_headers (SoupMessage *msg, char *headers, guint headers_len,
*encoding = SOUP_TRANSFER_CONTENT_LENGTH;
*content_len = 0;
} else if (*encoding == SOUP_TRANSFER_UNKNOWN) {
- if (soup_message_get_header (msg->request_headers, "Transfer-Encoding"))
+ if (soup_message_headers_find (msg->request_headers, "Transfer-Encoding"))
return SOUP_STATUS_NOT_IMPLEMENTED;
else
return SOUP_STATUS_BAD_REQUEST;
@@ -61,7 +61,7 @@ parse_request_headers (SoupMessage *msg, char *headers, guint headers_len,
/* Generate correct context for request */
server = soup_server_message_get_server (SOUP_SERVER_MESSAGE (msg));
- req_host = soup_message_get_header (msg->request_headers, "Host");
+ req_host = soup_message_headers_find (msg->request_headers, "Host");
if (*req_path != '/') {
/* Check for absolute URI */
@@ -107,10 +107,9 @@ parse_request_headers (SoupMessage *msg, char *headers, guint headers_len,
}
static void
-write_header (gpointer name, gpointer value, gpointer headers)
+write_header (const char *name, const char *value, gpointer headers)
{
- g_string_append_printf (headers, "%s: %s\r\n",
- (char *)name, (char *)value);
+ g_string_append_printf (headers, "%s: %s\r\n", name, value);
}
static void
@@ -124,14 +123,14 @@ get_response_headers (SoupMessage *msg, GString *headers,
g_string_append_printf (headers, "HTTP/1.1 %d %s\r\n",
msg->status_code, msg->reason_phrase);
- soup_message_foreach_header (msg->response_headers,
- write_header, headers);
+ soup_message_headers_foreach (msg->response_headers,
+ write_header, headers);
*encoding = soup_message_get_response_encoding (msg, NULL);
claimed_encoding = soup_server_message_get_encoding (smsg);
if (claimed_encoding == SOUP_TRANSFER_CONTENT_LENGTH &&
- !soup_message_get_header (msg->response_headers, "Content-Length")) {
+ !soup_message_headers_find (msg->response_headers, "Content-Length")) {
g_string_append_printf (headers, "Content-Length: %d\r\n",
msg->response.length);
} else if (claimed_encoding == SOUP_TRANSFER_CHUNKED)
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index 26fc9573..95559660 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -69,11 +69,8 @@ soup_message_init (SoupMessage *msg)
{
msg->status = SOUP_MESSAGE_STATUS_IDLE;
- msg->request_headers = g_hash_table_new (soup_str_case_hash,
- soup_str_case_equal);
-
- msg->response_headers = g_hash_table_new (soup_str_case_hash,
- soup_str_case_equal);
+ msg->request_headers = soup_message_headers_new ();
+ msg->response_headers = soup_message_headers_new ();
SOUP_MESSAGE_GET_PRIVATE (msg)->http_version = SOUP_HTTP_1_1;
}
@@ -100,11 +97,8 @@ finalize (GObject *object)
g_free (msg->response.body);
free_chunks (msg);
- soup_message_clear_headers (msg->request_headers);
- g_hash_table_destroy (msg->request_headers);
-
- soup_message_clear_headers (msg->response_headers);
- g_hash_table_destroy (msg->response_headers);
+ soup_message_headers_free (msg->request_headers);
+ soup_message_headers_free (msg->response_headers);
g_slist_foreach (priv->content_handlers, (GFunc) g_free, NULL);
g_slist_free (priv->content_handlers);
@@ -471,8 +465,7 @@ soup_message_set_request (SoupMessage *msg,
g_return_if_fail (content_type != NULL);
g_return_if_fail (req_body != NULL || req_length == 0);
- soup_message_add_header (msg->request_headers,
- "Content-Type", content_type);
+ soup_message_headers_append (msg->request_headers, "Content-Type", content_type);
msg->request.owner = req_owner;
msg->request.body = req_body;
msg->request.length = req_length;
@@ -499,8 +492,7 @@ soup_message_set_response (SoupMessage *msg,
g_return_if_fail (content_type != NULL);
g_return_if_fail (resp_body != NULL || resp_length == 0);
- soup_message_add_header (msg->response_headers,
- "Content-Type", content_type);
+ soup_message_headers_append (msg->response_headers, "Content-Type", content_type);
msg->response.owner = resp_owner;
msg->response.body = resp_body;
msg->response.length = resp_length;
@@ -687,168 +679,43 @@ soup_message_finished (SoupMessage *msg)
g_signal_emit (msg, signals[FINISHED], 0);
}
-static gboolean
-free_header_list (gpointer name, gpointer vals, gpointer user_data)
-{
- g_free (name);
- g_slist_foreach (vals, (GFunc) g_free, NULL);
- g_slist_free (vals);
-
- return TRUE;
-}
-
-/**
- * soup_message_clear_headers:
- * @hash: a header table (the %request_headers or %response_headers
- * field of a #SoupMessage)
- *
- * Clears @hash.
- **/
-void
-soup_message_clear_headers (GHashTable *hash)
-{
- g_return_if_fail (hash != NULL);
-
- g_hash_table_foreach_remove (hash, free_header_list, NULL);
-}
-
-/**
- * soup_message_remove_header:
- * @hash: a header table (the %request_headers or %response_headers
- * field of a #SoupMessage)
- * @name: the header name to remove
- *
- * Removes @name from @hash. If there are multiple values for @name,
- * they are all removed.
- **/
void
-soup_message_remove_header (GHashTable *hash, const char *name)
+soup_message_add_header (SoupMessageHeaders *hdrs,
+ const char *name, const char *value)
{
- gpointer old_key, old_vals;
-
- g_return_if_fail (hash != NULL);
- g_return_if_fail (name != NULL || name[0] != '\0');
-
- if (g_hash_table_lookup_extended (hash, name, &old_key, &old_vals)) {
- g_hash_table_remove (hash, name);
- free_header_list (old_key, old_vals, NULL);
- }
+ soup_message_headers_append (hdrs, name, value);
}
-/**
- * soup_message_add_header:
- * @hash: a header table (the %request_headers or %response_headers
- * field of a #SoupMessage)
- * @name: the header name to add
- * @value: the value of the new header
- *
- * Adds a header with name @name and value @value to @hash. If there
- * was already a header with name @name, this one does not replace it,
- * it is merely added to it.
- **/
-void
-soup_message_add_header (GHashTable *hash, const char *name, const char *value)
-{
- GSList *old_value;
-
- g_return_if_fail (hash != NULL);
- g_return_if_fail (name != NULL || name [0] != '\0');
- g_return_if_fail (value != NULL);
-
- old_value = g_hash_table_lookup (hash, name);
-
- if (old_value)
- old_value = g_slist_append (old_value, g_strdup (value));
- else {
- g_hash_table_insert (hash, g_strdup (name),
- g_slist_append (NULL, g_strdup (value)));
- }
-}
-
-/**
- * soup_message_get_header:
- * @hash: a header table (the %request_headers or %response_headers
- * field of a #SoupMessage)
- * @name: header name.
- *
- * Finds the first header in @hash with name @name.
- *
- * Return value: the header's value or %NULL if not found.
- **/
const char *
-soup_message_get_header (GHashTable *hash, const char *name)
+soup_message_get_header (SoupMessageHeaders *hdrs, const char *name)
{
- GSList *vals;
-
- g_return_val_if_fail (hash != NULL, NULL);
- g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
-
- vals = g_hash_table_lookup (hash, name);
- if (vals)
- return vals->data;
-
- return NULL;
+ return soup_message_headers_find (hdrs, name);
}
-/**
- * soup_message_get_header_list:
- * @hash: a header table (the %request_headers or %response_headers
- * field of a #SoupMessage)
- * @name: header name.
- *
- * Finds all headers in @hash with name @name.
- *
- * Return value: a (possibly empty) list of values of headers with
- * name @name. The caller should not modify or free this list.
- **/
const GSList *
-soup_message_get_header_list (GHashTable *hash, const char *name)
+soup_message_get_header_list (SoupMessageHeaders *hdrs, const char *name)
{
- g_return_val_if_fail (hash != NULL, NULL);
- g_return_val_if_fail (name != NULL || name [0] != '\0', NULL);
-
- return g_hash_table_lookup (hash, name);
+ /* Can't emulate this cleanly */
+ return g_hash_table_lookup ((GHashTable *)hdrs, name);
}
-typedef struct {
- GHFunc func;
- gpointer user_data;
-} SoupMessageForeachHeaderData;
-
-static void
-foreach_value_in_list (gpointer name, gpointer value, gpointer user_data)
+void
+soup_message_foreach_header (SoupMessageHeaders *hdrs,
+ GHFunc func, gpointer user_data)
{
- GSList *vals = value;
- SoupMessageForeachHeaderData *data = user_data;
-
- while (vals) {
- (*data->func) (name, vals->data, data->user_data);
- vals = vals->next;
- }
+ soup_message_headers_foreach (hdrs, (SoupMessageHeadersForeachFunc)func, user_data);
}
-/**
- * soup_message_foreach_header:
- * @hash: a header table (the %request_headers or %response_headers
- * field of a #SoupMessage)
- * @func: callback function to run for each header
- * @user_data: data to pass to @func
- *
- * Calls @func once for each header value in @hash. (If there are
- * headers will multiple values, @func will be called once on each
- * value.)
- **/
void
-soup_message_foreach_header (GHashTable *hash, GHFunc func, gpointer user_data)
+soup_message_remove_header (SoupMessageHeaders *hdrs, const char *name)
{
- SoupMessageForeachHeaderData data;
-
- g_return_if_fail (hash != NULL);
- g_return_if_fail (func != NULL);
+ soup_message_headers_remove (hdrs, name);
+}
- data.func = func;
- data.user_data = user_data;
- g_hash_table_foreach (hash, foreach_value_in_list, &data);
+void
+soup_message_clear_headers (SoupMessageHeaders *hdrs)
+{
+ soup_message_headers_clear (hdrs);
}
/**
@@ -874,7 +741,8 @@ soup_message_set_auth (SoupMessage *msg, SoupAuth *auth)
if (priv->auth) {
g_object_unref (priv->auth);
- soup_message_remove_header (msg->request_headers, "Authorization");
+ soup_message_headers_remove (msg->request_headers,
+ "Authorization");
}
priv->auth = auth;
if (!priv->auth)
@@ -882,7 +750,8 @@ soup_message_set_auth (SoupMessage *msg, SoupAuth *auth)
g_object_ref (priv->auth);
token = soup_auth_get_authorization (auth, msg);
- soup_message_add_header (msg->request_headers, "Authorization", token);
+ soup_message_headers_append (msg->request_headers,
+ "Authorization", token);
g_free (token);
}
@@ -926,8 +795,8 @@ soup_message_set_proxy_auth (SoupMessage *msg, SoupAuth *auth)
if (priv->proxy_auth) {
g_object_unref (priv->proxy_auth);
- soup_message_remove_header (msg->request_headers,
- "Proxy-Authorization");
+ soup_message_headers_remove (msg->request_headers,
+ "Proxy-Authorization");
}
priv->proxy_auth = auth;
if (!priv->proxy_auth)
@@ -935,8 +804,8 @@ soup_message_set_proxy_auth (SoupMessage *msg, SoupAuth *auth)
g_object_ref (priv->proxy_auth);
token = soup_auth_get_authorization (auth, msg);
- soup_message_add_header (msg->request_headers,
- "Proxy-Authorization", token);
+ soup_message_headers_append (msg->request_headers,
+ "Proxy-Authorization", token);
g_free (token);
}
@@ -977,7 +846,7 @@ soup_message_cleanup_response (SoupMessage *req)
free_chunks (req);
- soup_message_clear_headers (req->response_headers);
+ soup_message_headers_clear (req->response_headers);
req->status_code = SOUP_STATUS_NONE;
if (req->reason_phrase) {
@@ -1065,8 +934,8 @@ soup_message_is_keepalive (SoupMessage *msg)
{
const char *c_conn, *s_conn;
- c_conn = soup_message_get_header (msg->request_headers, "Connection");
- s_conn = soup_message_get_header (msg->response_headers, "Connection");
+ c_conn = soup_message_headers_find (msg->request_headers, "Connection");
+ s_conn = soup_message_headers_find (msg->response_headers, "Connection");
if (msg->status_code == SOUP_STATUS_OK &&
soup_method_get_id (msg->method) == SOUP_METHOD_ID_CONNECT)
@@ -1161,10 +1030,10 @@ soup_message_get_request_encoding (SoupMessage *msg, guint *content_length)
if (SOUP_IS_SERVER_MESSAGE (msg)) {
const char *enc, *len;
- enc = soup_message_get_header (msg->request_headers,
- "Transfer-Encoding");
- len = soup_message_get_header (msg->request_headers,
- "Content-Length");
+ enc = soup_message_headers_find (msg->request_headers,
+ "Transfer-Encoding");
+ len = soup_message_headers_find (msg->request_headers,
+ "Content-Length");
if (enc) {
if (g_ascii_strcasecmp (enc, "chunked") == 0)
return SOUP_TRANSFER_CHUNKED;
@@ -1234,10 +1103,10 @@ soup_message_get_response_encoding (SoupMessage *msg, guint *content_length)
} else {
const char *enc, *len;
- enc = soup_message_get_header (msg->response_headers,
- "Transfer-Encoding");
- len = soup_message_get_header (msg->response_headers,
- "Content-Length");
+ enc = soup_message_headers_find (msg->response_headers,
+ "Transfer-Encoding");
+ len = soup_message_headers_find (msg->response_headers,
+ "Content-Length");
if (enc) {
if (g_ascii_strcasecmp (enc, "chunked") == 0)
return SOUP_TRANSFER_CHUNKED;
diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h
index f0ceb4b9..56359825 100644
--- a/libsoup/soup-message.h
+++ b/libsoup/soup-message.h
@@ -7,6 +7,7 @@
#define SOUP_MESSAGE_H 1
#include <libsoup/soup-types.h>
+#include <libsoup/soup-message-headers.h>
#include <libsoup/soup-method.h>
G_BEGIN_DECLS
@@ -128,10 +129,10 @@ struct SoupMessage {
const char *reason_phrase;
SoupDataBuffer request;
- GHashTable *request_headers;
+ SoupMessageHeaders *request_headers;
SoupDataBuffer response;
- GHashTable *response_headers;
+ SoupMessageHeaders *response_headers;
SoupMessageStatus status;
};
@@ -187,24 +188,26 @@ void soup_message_set_response (SoupMessage *msg,
char *resp_body,
gulong resp_length);
-void soup_message_add_header (GHashTable *hash,
- const char *name,
- const char *value);
+#ifndef LIBSOUP_DISABLE_DEPRECATED
+void soup_message_add_header (SoupMessageHeaders *hdrs,
+ const char *name,
+ const char *value);
-const char *soup_message_get_header (GHashTable *hash,
- const char *name);
+const char *soup_message_get_header (SoupMessageHeaders *hdrs,
+ const char *name);
-const GSList *soup_message_get_header_list (GHashTable *hash,
- const char *name);
+const GSList *soup_message_get_header_list (SoupMessageHeaders *hdrs,
+ const char *name);
-void soup_message_foreach_header (GHashTable *hash,
- GHFunc func,
- gpointer user_data);
+void soup_message_foreach_header (SoupMessageHeaders *hdrs,
+ GHFunc func,
+ gpointer user_data);
-void soup_message_remove_header (GHashTable *hash,
- const char *name);
+void soup_message_remove_header (SoupMessageHeaders *hdrs,
+ const char *name);
-void soup_message_clear_headers (GHashTable *hash);
+void soup_message_clear_headers (SoupMessageHeaders *hdrs);
+#endif /* LIBSOUP_DISABLE_DEPRECATED */
/**
* SoupHttpVersion:
diff --git a/libsoup/soup-server-auth.c b/libsoup/soup-server-auth.c
index e2c5138d..47d38693 100644
--- a/libsoup/soup-server-auth.c
+++ b/libsoup/soup-server-auth.c
@@ -18,58 +18,6 @@
#include "soup-misc.h"
#include "soup-uri.h"
-typedef struct {
- const gchar *scheme;
- SoupAuthType type;
- gint strength;
-} AuthScheme;
-
-static AuthScheme known_auth_schemes [] = {
- { "Basic", SOUP_AUTH_TYPE_BASIC, 0 },
- { "Digest", SOUP_AUTH_TYPE_DIGEST, 3 },
- { NULL }
-};
-
-static SoupAuthType
-soup_auth_get_strongest_header (guint auth_types,
- const GSList *vals,
- gchar **out_hdr)
-{
- gchar *header = NULL;
- AuthScheme *scheme = NULL, *iter;
-
- g_return_val_if_fail (vals != NULL, 0);
-
- if (!auth_types)
- return 0;
-
- while (vals) {
- for (iter = known_auth_schemes; iter->scheme; iter++) {
- gchar *tryheader = vals->data;
-
- if ((iter->type & auth_types) &&
- !g_ascii_strncasecmp (tryheader,
- iter->scheme,
- strlen (iter->scheme))) {
- if (!scheme ||
- scheme->strength < iter->strength) {
- header = tryheader;
- scheme = iter;
- }
- break;
- }
- }
-
- vals = vals->next;
- }
-
- if (!scheme)
- return 0;
-
- *out_hdr = header + strlen (scheme->scheme) + 1;
- return scheme->type;
-}
-
static gboolean
check_digest_passwd (SoupServerAuthDigest *digest,
gchar *passwd)
@@ -185,7 +133,7 @@ soup_server_auth_get_user (SoupServerAuth *auth)
static gboolean
parse_digest (SoupServerAuthContext *auth_ctx,
- gchar *header,
+ const char *header,
SoupMessage *msg,
SoupServerAuth *out_auth)
{
@@ -323,26 +271,29 @@ parse_digest (SoupServerAuthContext *auth_ctx,
SoupServerAuth *
soup_server_auth_new (SoupServerAuthContext *auth_ctx,
- const GSList *auth_hdrs,
+ const char *auth_hdr,
SoupMessage *msg)
{
SoupServerAuth *ret;
SoupAuthType type;
- gchar *header = NULL;
+ const char *header = NULL;
g_return_val_if_fail (auth_ctx != NULL, NULL);
g_return_val_if_fail (msg != NULL, NULL);
- if (!auth_hdrs && auth_ctx->types) {
- soup_message_set_status (msg, SOUP_STATUS_UNAUTHORIZED);
+ if (!auth_hdr) {
+ if (auth_ctx->types)
+ soup_message_set_status (msg, SOUP_STATUS_UNAUTHORIZED);
return NULL;
}
- type = soup_auth_get_strongest_header (auth_ctx->types,
- auth_hdrs,
- &header);
-
- if (!type && auth_ctx->types) {
+ if (!g_ascii_strncasecmp (auth_hdr, "Basic ", 6)) {
+ type = SOUP_AUTH_TYPE_BASIC;
+ header = auth_hdr + 6;
+ } else if (!g_ascii_strncasecmp (auth_hdr, "Digest ", 7)) {
+ type = SOUP_AUTH_TYPE_DIGEST;
+ header = auth_hdr + 7;
+ } else if (auth_ctx->types) {
soup_message_set_status (msg, SOUP_STATUS_UNAUTHORIZED);
return NULL;
}
@@ -420,9 +371,7 @@ soup_server_auth_context_challenge (SoupServerAuthContext *auth_ctx,
hdr = g_strdup_printf ("Basic realm=\"%s\"",
auth_ctx->basic_info.realm);
- soup_message_add_header (msg->response_headers,
- header_name,
- hdr);
+ soup_message_headers_append (msg->response_headers, header_name, hdr);
g_free (hdr);
}
@@ -451,9 +400,7 @@ soup_server_auth_context_challenge (SoupServerAuthContext *auth_ctx,
else
g_string_sprintfa (str, "algorithm=\"MD5\"");
- soup_message_add_header (msg->response_headers,
- header_name,
- str->str);
+ soup_message_headers_append (msg->response_headers, header_name, str->str);
g_string_free (str, TRUE);
}
}
diff --git a/libsoup/soup-server-auth.h b/libsoup/soup-server-auth.h
index f537e378..dfb2088d 100644
--- a/libsoup/soup-server-auth.h
+++ b/libsoup/soup-server-auth.h
@@ -75,7 +75,7 @@ union SoupServerAuth {
};
SoupServerAuth *soup_server_auth_new (SoupServerAuthContext *auth_ctx,
- const GSList *auth_hdrs,
+ const char *auth_hdr,
SoupMessage *msg);
void soup_server_auth_free (SoupServerAuth *auth);
diff --git a/libsoup/soup-server.c b/libsoup/soup-server.c
index 051effe2..44f475a7 100644
--- a/libsoup/soup-server.c
+++ b/libsoup/soup-server.c
@@ -381,11 +381,11 @@ call_handler (SoupMessage *req, SoupSocket *sock)
if (hand->auth_ctx) {
SoupServerAuthContext *auth_ctx = hand->auth_ctx;
- const GSList *auth_hdrs;
+ const char *auth_hdr;
- auth_hdrs = soup_message_get_header_list (req->request_headers,
- "Authorization");
- auth = soup_server_auth_new (auth_ctx, auth_hdrs, req);
+ auth_hdr = soup_message_headers_find (req->request_headers,
+ "Authorization");
+ auth = soup_server_auth_new (auth_ctx, auth_hdr, req);
if (auth_ctx->callback) {
gboolean ret = FALSE;
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index f0fb4281..5d2f57af 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -765,13 +765,11 @@ authenticate_auth (SoupSession *session, SoupAuth *auth,
}
static gboolean
-update_auth_internal (SoupSession *session, SoupMessage *msg,
- const GSList *headers, gboolean proxy)
+update_auth_internal (SoupSession *session, SoupMessage *msg, gboolean proxy)
{
SoupSessionHost *host;
SoupAuth *new_auth, *prior_auth, *old_auth;
gpointer old_path, old_auth_info;
- const SoupUri *msg_uri;
const char *path;
char *auth_info;
GSList *pspace, *p;
@@ -787,8 +785,9 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
/* Try to construct a new auth from the headers; if we can't,
* there's no way we'll be able to authenticate.
*/
- msg_uri = soup_message_get_uri (msg);
- new_auth = soup_auth_new_from_header_list (headers);
+ new_auth = soup_auth_new_from_headers (
+ msg->response_headers,
+ proxy ? "Proxy-Authenticate" : "WWW-Authenticate");
if (!new_auth)
return FALSE;
@@ -825,7 +824,7 @@ update_auth_internal (SoupSession *session, SoupMessage *msg,
if (proxy)
pspace = g_slist_prepend (NULL, g_strdup (""));
else
- pspace = soup_auth_get_protection_space (new_auth, msg_uri);
+ pspace = soup_auth_get_protection_space (new_auth, soup_message_get_uri (msg));
for (p = pspace; p; p = p->next) {
path = p->data;
@@ -887,22 +886,10 @@ static void
authorize_handler (SoupMessage *msg, gpointer user_data)
{
SoupSession *session = user_data;
- const GSList *headers;
gboolean proxy;
- if (msg->status_code == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
- headers = soup_message_get_header_list (msg->response_headers,
- "Proxy-Authenticate");
- proxy = TRUE;
- } else {
- headers = soup_message_get_header_list (msg->response_headers,
- "WWW-Authenticate");
- proxy = FALSE;
- }
- if (!headers)
- return;
-
- if (update_auth_internal (session, msg, headers, proxy))
+ proxy = (msg->status_code == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED);
+ if (update_auth_internal (session, msg, proxy))
soup_session_requeue_message (session, msg);
}
@@ -913,7 +900,7 @@ redirect_handler (SoupMessage *msg, gpointer user_data)
const char *new_loc;
SoupUri *new_uri;
- new_loc = soup_message_get_header (msg->response_headers, "Location");
+ new_loc = soup_message_headers_find (msg->response_headers, "Location");
if (!new_loc)
return;
diff --git a/libsoup/soup.h b/libsoup/soup.h
index 17744486..d739175b 100644
--- a/libsoup/soup.h
+++ b/libsoup/soup.h
@@ -17,6 +17,7 @@ extern "C" {
#include <libsoup/soup-headers.h>
#include <libsoup/soup-message.h>
#include <libsoup/soup-message-filter.h>
+#include <libsoup/soup-message-headers.h>
#include <libsoup/soup-message-queue.h>
#include <libsoup/soup-method.h>
#include <libsoup/soup-misc.h>
diff --git a/python/libsoup.defs b/python/libsoup.defs
index 60eb5d45..33e59086 100644
--- a/python/libsoup.defs
+++ b/python/libsoup.defs
@@ -20,6 +20,10 @@
(parent "GObject")
(c-name "SoupMessage")
(gtype-id "SOUP_TYPE_MESSAGE")
+ (fields
+ '("SoupMessageHeaders*" "request_headers")
+ '("SoupMessageHeaders*" "response_headers")
+ )
)
(define-object Server
@@ -564,7 +568,7 @@
(parameters
'("const-char*" "str")
'("int" "len")
- '("GHashTable*" "dest")
+ '("SoupMessageHeaders*" "dest")
'("char**" "req_method")
'("char**" "req_path")
'("SoupHttpVersion*" "ver")
@@ -588,7 +592,7 @@
(parameters
'("const-char*" "str")
'("int" "len")
- '("GHashTable*" "dest")
+ '("SoupMessageHeaders*" "dest")
'("SoupHttpVersion*" "ver")
'("guint*" "status_code")
'("char**" "reason_phrase")
@@ -680,61 +684,6 @@
)
)
-(define-function soup_message_add_header
- (c-name "soup_message_add_header")
- (return-type "none")
- (parameters
- '("GHashTable*" "hash")
- '("const-char*" "name")
- '("const-char*" "value")
- )
-)
-
-(define-function soup_message_get_header
- (c-name "soup_message_get_header")
- (return-type "const-char*")
- (parameters
- '("GHashTable*" "hash")
- '("const-char*" "name")
- )
-)
-
-(define-function soup_message_get_header_list
- (c-name "soup_message_get_header_list")
- (return-type "const-GSList*")
- (parameters
- '("GHashTable*" "hash")
- '("const-char*" "name")
- )
-)
-
-(define-function soup_message_foreach_header
- (c-name "soup_message_foreach_header")
- (return-type "none")
- (parameters
- '("GHashTable*" "hash")
- '("GHFunc" "func")
- '("gpointer" "user_data")
- )
-)
-
-(define-function soup_message_remove_header
- (c-name "soup_message_remove_header")
- (return-type "none")
- (parameters
- '("GHashTable*" "hash")
- '("const-char*" "name")
- )
-)
-
-(define-function soup_message_clear_headers
- (c-name "soup_message_clear_headers")
- (return-type "none")
- (parameters
- '("GHashTable*" "hash")
- )
-)
-
(define-method set_http_version
(of-object "SoupMessage")
(c-name "soup_message_set_http_version")
@@ -1027,6 +976,82 @@
+;; From soup-message-headers.h
+
+(define-pointer MessageHeaders
+ (in-module "Soup")
+ (c-name "SoupMessageHeaders")
+ (gtype-id "SOUP_TYPE_MESSAGE_HEADERS")
+)
+
+(define-function soup_message_headers_new
+ (c-name "soup_message_headers_new")
+ (is-constructor-of "SoupMessageHeaders")
+ (return-type "SoupMessageHeaders*")
+)
+
+(define-method free
+ (of-object "SoupMessageHeaders")
+ (c-name "soup_message_headers_free")
+ (return-type "none")
+)
+
+(define-method append
+ (of-object "SoupMessageHeaders")
+ (c-name "soup_message_headers_append")
+ (return-type "none")
+ (parameters
+ '("const-char*" "name")
+ '("const-char*" "value")
+ )
+)
+
+(define-method replace
+ (of-object "SoupMessageHeaders")
+ (c-name "soup_message_headers_replace")
+ (return-type "none")
+ (parameters
+ '("const-char*" "name")
+ '("const-char*" "value")
+ )
+)
+
+(define-method remove
+ (of-object "SoupMessageHeaders")
+ (c-name "soup_message_headers_remove")
+ (return-type "none")
+ (parameters
+ '("const-char*" "name")
+ )
+)
+
+(define-method clear
+ (of-object "SoupMessageHeaders")
+ (c-name "soup_message_headers_clear")
+ (return-type "none")
+)
+
+(define-method find_nth
+ (of-object "SoupMessageHeaders")
+ (c-name "soup_message_headers_find_nth")
+ (return-type "const-char*")
+ (parameters
+ '("const-char*" "name")
+ '("int" "index")
+ )
+)
+
+(define-method foreach
+ (of-object "SoupMessageHeaders")
+ (c-name "soup_message_headers_foreach")
+ (return-type "none")
+ (parameters
+ '("SoupMessageHeadersForeachFunc" "func")
+ '("gpointer" "user_data")
+ )
+)
+
+
;; From soup-message-queue.h
(define-function soup_message_queue_new
@@ -2614,5 +2639,3 @@
(c-name "soup_xmlrpc_value_dump")
(return-type "none")
)
-
-
diff --git a/tests/auth-test.c b/tests/auth-test.c
index cf4473d4..61e51d60 100644
--- a/tests/auth-test.c
+++ b/tests/auth-test.c
@@ -181,8 +181,8 @@ identify_auth (SoupMessage *msg)
const char *header;
int num;
- header = soup_message_get_header (msg->request_headers,
- "Authorization");
+ header = soup_message_headers_find (msg->request_headers,
+ "Authorization");
if (!header)
return 0;
diff --git a/tests/dict.c b/tests/dict.c
index afaed0e0..f9efe736 100644
--- a/tests/dict.c
+++ b/tests/dict.c
@@ -135,8 +135,8 @@ main (int argc, char **argv)
exit (1);
}
- soup_message_add_header (SOUP_MESSAGE (msg)->request_headers,
- "SOAPAction", "http://services.aonaware.com/webservices/Define");
+ soup_message_headers_append (SOUP_MESSAGE (msg)->request_headers, "SOAPAction",
+ "http://services.aonaware.com/webservices/Define");
soup_soap_message_start_envelope (msg);
soup_soap_message_start_body (msg);
diff --git a/tests/get.c b/tests/get.c
index 4c196df2..0397b34d 100644
--- a/tests/get.c
+++ b/tests/get.c
@@ -100,9 +100,9 @@ mkdirs (const char *path)
}
static void
-print_header (gpointer name, gpointer value, gpointer data)
+print_header (const char *name, const char *value, gpointer data)
{
- printf ("%s: %s\n", (const char *)name, (const char *)value);
+ printf ("%s: %s\n", name, value);
}
static void
@@ -164,7 +164,7 @@ get_url (const char *url)
printf ("HTTP/1.%d %d %s\n",
soup_message_get_http_version (msg),
msg->status_code, msg->reason_phrase);
- soup_message_foreach_header (msg->response_headers, print_header, NULL);
+ soup_message_headers_foreach (msg->response_headers, print_header, NULL);
printf ("\n");
} else
printf ("%s: %d %s\n", name, msg->status_code, msg->reason_phrase);
@@ -176,7 +176,7 @@ get_url (const char *url)
if (SOUP_STATUS_IS_REDIRECTION (msg->status_code)) {
if (recurse)
unlink (name);
- header = soup_message_get_header (msg->response_headers, "Location");
+ header = soup_message_headers_find (msg->response_headers, "Location");
if (header) {
if (!debug)
printf (" -> %s\n", header);
@@ -197,7 +197,7 @@ get_url (const char *url)
return;
close (fd);
- header = soup_message_get_header (msg->response_headers, "Content-Type");
+ header = soup_message_headers_find (msg->response_headers, "Content-Type");
if (header && g_ascii_strncasecmp (header, "text/html", 9) != 0)
return;
diff --git a/tests/header-parsing.c b/tests/header-parsing.c
index c6b61cdc..558afa47 100644
--- a/tests/header-parsing.c
+++ b/tests/header-parsing.c
@@ -452,23 +452,26 @@ struct ResponseTest {
static const int num_resptests = G_N_ELEMENTS (resptests);
static void
-print_header (gpointer key, gpointer value, gpointer data)
+print_header (const char *name, const char *value, gpointer data)
{
- GSList *values = value;
- dprintf (" '%s': '%s'\n",
- (char *)key, (char*)values->data);
+ dprintf (" '%s': '%s'\n", name, value);
}
static void
-free_headers (gpointer value)
+count_header (const char *name, const char *value, gpointer data)
{
- GSList *headers = value;
+ int *count = data;
- /* We know that there are no duplicate headers in any of the
- * test cases, so...
- */
- g_free (headers->data);
- g_slist_free (headers);
+ *count = *count + 1;
+}
+
+static int
+count_headers (SoupMessageHeaders *hdrs)
+{
+ int count = 0;
+
+ soup_message_headers_foreach (hdrs, count_header, &count);
+ return count;
}
static int
@@ -476,9 +479,9 @@ do_request_tests (void)
{
int i, len, h, errors = 0;
char *method, *path;
- GSList *values;
+ const char *value;
SoupHttpVersion version;
- GHashTable *headers;
+ SoupMessageHeaders *headers;
dprintf ("Request tests\n");
for (i = 0; i < 1; i++) {
@@ -487,8 +490,7 @@ do_request_tests (void)
dprintf ("%2d. %s (%s): ", i + 1, reqtests[i].description,
reqtests[i].method ? "should parse" : "should NOT parse");
- headers = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, free_headers);
+ headers = soup_message_headers_new ();
method = path = NULL;
if (reqtests[i].length == -1)
@@ -506,12 +508,12 @@ do_request_tests (void)
ok = FALSE;
for (h = 0; reqtests[i].headers[h].name; h++) {
- values = g_hash_table_lookup (headers, reqtests[i].headers[h].name);
- if (!values || values->next ||
- strcmp (reqtests[i].headers[h].value, values->data) != 0)
+ value = soup_message_headers_find (headers, reqtests[i].headers[h].name);
+ if (!value || soup_message_headers_find_nth (headers, reqtests[i].headers[h].name, 1) ||
+ strcmp (reqtests[i].headers[h].value, value) != 0)
ok = FALSE;
}
- if (g_hash_table_size (headers) != h)
+ if (count_headers (headers) != h)
ok = FALSE;
} else {
if (reqtests[i].method)
@@ -537,14 +539,14 @@ do_request_tests (void)
if (method) {
dprintf (" got: '%s' '%s' 'HTTP/1.%d'\n",
method, path, version);
- g_hash_table_foreach (headers, print_header, NULL);
+ soup_message_headers_foreach (headers, print_header, NULL);
} else
dprintf (" got: parse error\n");
}
g_free (method);
g_free (path);
- g_hash_table_destroy (headers);
+ soup_message_headers_free (headers);
}
dprintf ("\n");
@@ -557,9 +559,9 @@ do_response_tests (void)
int i, len, h, errors = 0;
guint status_code;
char *reason_phrase;
- GSList *values;
+ const char *value;
SoupHttpVersion version;
- GHashTable *headers;
+ SoupMessageHeaders *headers;
dprintf ("Response tests\n");
for (i = 0; i < num_resptests; i++) {
@@ -568,8 +570,7 @@ do_response_tests (void)
dprintf ("%2d. %s (%s): ", i + 1, resptests[i].description,
resptests[i].reason_phrase ? "should parse" : "should NOT parse");
- headers = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, free_headers);
+ headers = soup_message_headers_new ();
reason_phrase = NULL;
if (resptests[i].length == -1)
@@ -587,12 +588,12 @@ do_response_tests (void)
ok = FALSE;
for (h = 0; resptests[i].headers[h].name; h++) {
- values = g_hash_table_lookup (headers, resptests[i].headers[h].name);
- if (!values || values->next ||
- strcmp (resptests[i].headers[h].value, values->data) != 0)
+ value = soup_message_headers_find (headers, resptests[i].headers[h].name);
+ if (!value || soup_message_headers_find_nth (headers, resptests[i].headers[h].name, 1) ||
+ strcmp (resptests[i].headers[h].value, value) != 0)
ok = FALSE;
}
- if (g_hash_table_size (headers) != h)
+ if (count_headers (headers) != h)
ok = FALSE;
} else {
if (resptests[i].reason_phrase)
@@ -619,13 +620,13 @@ do_response_tests (void)
if (reason_phrase) {
dprintf (" got: 'HTTP/1.%d' '%03d' '%s'\n",
version, status_code, reason_phrase);
- g_hash_table_foreach (headers, print_header, NULL);
+ soup_message_headers_foreach (headers, print_header, NULL);
} else
dprintf (" got: parse error\n");
}
g_free (reason_phrase);
- g_hash_table_destroy (headers);
+ soup_message_headers_free (headers);
}
dprintf ("\n");
diff --git a/tests/ntlm-test.c b/tests/ntlm-test.c
index 30e01dad..75429083 100644
--- a/tests/ntlm-test.c
+++ b/tests/ntlm-test.c
@@ -82,7 +82,7 @@ server_callback (SoupServerContext *context, SoupMessage *msg, gpointer data)
g_free (path);
state = GPOINTER_TO_INT (g_hash_table_lookup (connections, context->sock));
- auth = soup_message_get_header (msg->request_headers, "Authorization");
+ auth = soup_message_headers_find (msg->request_headers, "Authorization");
if (auth && !strncmp (auth, "NTLM ", 5)) {
if (!strncmp (auth + 5, NTLM_REQUEST_START,
@@ -98,8 +98,9 @@ server_callback (SoupServerContext *context, SoupMessage *msg, gpointer data)
if (state == NTLM_RECEIVED_REQUEST) {
soup_message_set_status (msg, SOUP_STATUS_UNAUTHORIZED);
- soup_message_add_header (msg->response_headers,
- "WWW-Authenticate", "NTLM " NTLM_CHALLENGE);
+ soup_message_headers_append (msg->response_headers,
+ "WWW-Authenticate",
+ "NTLM " NTLM_CHALLENGE);
state = NTLM_SENT_CHALLENGE;
} else if (!required_user || required_user == state) {
if (not_found)
@@ -112,10 +113,10 @@ server_callback (SoupServerContext *context, SoupMessage *msg, gpointer data)
}
} else {
soup_message_set_status (msg, SOUP_STATUS_UNAUTHORIZED);
- soup_message_add_header (msg->response_headers,
- "WWW-Authenticate", "NTLM");
- soup_message_add_header (msg->response_headers,
- "Connection", "close");
+ soup_message_headers_append (msg->response_headers,
+ "WWW-Authenticate", "NTLM");
+ soup_message_headers_append (msg->response_headers,
+ "Connection", "close");
}
g_hash_table_insert (connections, context->sock,
@@ -148,8 +149,8 @@ ntlm_prompt_check (SoupMessage *msg, gpointer user_data)
if (state->sent_request)
return;
- header = soup_message_get_header (msg->response_headers,
- "WWW-Authenticate");
+ header = soup_message_headers_find (msg->response_headers,
+ "WWW-Authenticate");
if (header && !strcmp (header, "NTLM"))
state->got_prompt = TRUE;
}
@@ -160,8 +161,8 @@ ntlm_challenge_check (SoupMessage *msg, gpointer user_data)
NTLMState *state = user_data;
const char *header;
- header = soup_message_get_header (msg->response_headers,
- "WWW-Authenticate");
+ header = soup_message_headers_find (msg->response_headers,
+ "WWW-Authenticate");
if (header && !strncmp (header, "NTLM ", 5))
state->got_challenge = TRUE;
}
@@ -172,8 +173,8 @@ ntlm_request_check (SoupMessage *msg, gpointer user_data)
NTLMState *state = user_data;
const char *header;
- header = soup_message_get_header (msg->request_headers,
- "Authorization");
+ header = soup_message_headers_find (msg->request_headers,
+ "Authorization");
if (header && !strncmp (header, "NTLM " NTLM_REQUEST_START,
strlen ("NTLM " NTLM_REQUEST_START)))
state->sent_request = TRUE;
@@ -185,8 +186,8 @@ ntlm_response_check (SoupMessage *msg, gpointer user_data)
NTLMState *state = user_data;
const char *header;
- header = soup_message_get_header (msg->request_headers,
- "Authorization");
+ header = soup_message_headers_find (msg->request_headers,
+ "Authorization");
if (header && !strncmp (header, "NTLM " NTLM_RESPONSE_START,
strlen ("NTLM " NTLM_RESPONSE_START)))
state->sent_response = TRUE;
diff --git a/tests/simple-httpd.c b/tests/simple-httpd.c
index ea9a54ab..0d68b6dc 100644
--- a/tests/simple-httpd.c
+++ b/tests/simple-httpd.c
@@ -20,9 +20,9 @@
#include <libsoup/soup-server-message.h>
static void
-print_header (gpointer name, gpointer value, gpointer data)
+print_header (const char *name, const char *value, gpointer data)
{
- printf ("%s: %s\n", (char *)name, (char *)value);
+ printf ("%s: %s\n", name, value);
}
static void
@@ -36,7 +36,7 @@ server_callback (SoupServerContext *context, SoupMessage *msg, gpointer data)
path = soup_uri_to_string (soup_message_get_uri (msg), TRUE);
printf ("%s %s HTTP/1.%d\n", msg->method, path,
soup_message_get_http_version (msg));
- soup_message_foreach_header (msg->request_headers, print_header, NULL);
+ soup_message_headers_foreach (msg->request_headers, print_header, NULL);
if (msg->request.length)
printf ("%.*s\n", msg->request.length, msg->request.body);
@@ -75,8 +75,8 @@ server_callback (SoupServerContext *context, SoupMessage *msg, gpointer data)
uri = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
redir_uri = g_strdup_printf ("%s/", uri);
- soup_message_add_header (msg->response_headers,
- "Location", redir_uri);
+ soup_message_headers_append (msg->response_headers,
+ "Location", redir_uri);
soup_message_set_status (msg, SOUP_STATUS_MOVED_PERMANENTLY);
g_free (redir_uri);
g_free (uri);
diff --git a/tests/simple-proxy.c b/tests/simple-proxy.c
index bcfb9efc..7a9d3eb2 100644
--- a/tests/simple-proxy.c
+++ b/tests/simple-proxy.c
@@ -27,9 +27,9 @@
SoupSession *session;
static void
-copy_header (gpointer name, gpointer value, gpointer dest_headers)
+copy_header (const char *name, const char *value, gpointer dest_headers)
{
- soup_message_add_header (dest_headers, name, value);
+ soup_message_headers_append (dest_headers, name, value);
}
static void
@@ -41,9 +41,9 @@ send_headers (SoupMessage *from, SoupMessage *to)
soup_message_set_status_full (to, from->status_code,
from->reason_phrase);
- soup_message_foreach_header (from->response_headers, copy_header,
- to->response_headers);
- soup_message_remove_header (to->response_headers, "Content-Length");
+ soup_message_headers_foreach (from->response_headers, copy_header,
+ to->response_headers);
+ soup_message_headers_remove (to->response_headers, "Content-Length");
soup_message_io_unpause (to);
}
@@ -91,10 +91,11 @@ server_callback (SoupServerContext *context, SoupMessage *msg, gpointer data)
}
msg2 = soup_message_new (msg->method, uristr);
- soup_message_foreach_header (msg->request_headers, copy_header,
- msg2->request_headers);
- soup_message_remove_header (msg2->request_headers, "Host");
- soup_message_remove_header (msg2->request_headers, "Connection");
+ msg2 = soup_message_new (msg->method, uristr);
+ soup_message_headers_foreach (msg->request_headers, copy_header,
+ msg2->request_headers);
+ soup_message_headers_remove (msg2->request_headers, "Host");
+ soup_message_headers_remove (msg2->request_headers, "Connection");
if (msg->request.length) {
msg2->request.owner = SOUP_BUFFER_USER_OWNED;