diff options
author | Dan Winship <danw@src.gnome.org> | 2007-11-30 02:27:10 +0000 |
---|---|---|
committer | Dan Winship <danw@src.gnome.org> | 2007-11-30 02:27:10 +0000 |
commit | a283ae769f481518a2be9da17c718b3d7a6ea24b (patch) | |
tree | ef5e20c87fddae1f2f5f6b06f719846b705bc20f | |
parent | a3b3d382c0b5ff6978b9437bd2fe607681d718ba (diff) | |
download | libsoup-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-- | ChangeLog | 14 | ||||
-rw-r--r-- | libsoup/Makefile.am | 2 | ||||
-rw-r--r-- | libsoup/soup-auth.c | 22 | ||||
-rw-r--r-- | libsoup/soup-auth.h | 4 | ||||
-rw-r--r-- | libsoup/soup-connection-ntlm.c | 26 | ||||
-rw-r--r-- | libsoup/soup-headers.c | 44 | ||||
-rw-r--r-- | libsoup/soup-headers.h | 36 | ||||
-rw-r--r-- | libsoup/soup-message-client-io.c | 21 | ||||
-rw-r--r-- | libsoup/soup-message-handlers.c | 4 | ||||
-rw-r--r-- | libsoup/soup-message-headers.c | 221 | ||||
-rw-r--r-- | libsoup/soup-message-headers.h | 44 | ||||
-rw-r--r-- | libsoup/soup-message-io.c | 4 | ||||
-rw-r--r-- | libsoup/soup-message-server-io.c | 17 | ||||
-rw-r--r-- | libsoup/soup-message.c | 219 | ||||
-rw-r--r-- | libsoup/soup-message.h | 33 | ||||
-rw-r--r-- | libsoup/soup-server-auth.c | 83 | ||||
-rw-r--r-- | libsoup/soup-server-auth.h | 2 | ||||
-rw-r--r-- | libsoup/soup-server.c | 8 | ||||
-rw-r--r-- | libsoup/soup-session.c | 29 | ||||
-rw-r--r-- | libsoup/soup.h | 1 | ||||
-rw-r--r-- | python/libsoup.defs | 141 | ||||
-rw-r--r-- | tests/auth-test.c | 4 | ||||
-rw-r--r-- | tests/dict.c | 4 | ||||
-rw-r--r-- | tests/get.c | 10 | ||||
-rw-r--r-- | tests/header-parsing.c | 63 | ||||
-rw-r--r-- | tests/ntlm-test.c | 31 | ||||
-rw-r--r-- | tests/simple-httpd.c | 10 | ||||
-rw-r--r-- | tests/simple-proxy.c | 19 |
28 files changed, 604 insertions, 512 deletions
@@ -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; |