From 801cefbcf058518a60360e1297c63b482e267655 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 9 Feb 2008 00:46:12 +0000 Subject: [PATCH] Add an iterator type for SoupMessageHeaders. * libsoup/soup-message-headers.c (SoupMessageHeadersIter) (soup_message_headers_iter_init, soup_message_headers_iter_next): Add an iterator type for SoupMessageHeaders. * libsoup/soup-message-client-io.c (get_request_headers): * libsoup/soup-message-server-io.c (get_response_headers): Use SoupMessageHeadersIter. * libsoup/soup-logger.c (print_request, print_response): Use SoupMessageHeadersIter. And take advantage of the simplification to fix the kludge where 'direction' was stored as a field in SoupLoggerPrivate rather than being an argument to soup_logger_print. * tests/get.c (get_url): * tests/header-parsing.c (check_headers): * tests/simple-httpd.c (server_callback): Use SoupMessageHeadersIter svn path=/trunk/; revision=1079 --- ChangeLog | 21 ++++++++ libsoup/soup-logger.c | 107 +++++++++++++++++++-------------------- libsoup/soup-message-client-io.c | 13 ++--- libsoup/soup-message-headers.c | 67 ++++++++++++++++++++++++ libsoup/soup-message-headers.h | 10 ++++ libsoup/soup-message-server-io.c | 13 ++--- tests/get.c | 14 ++--- tests/header-parsing.c | 19 +++---- tests/simple-httpd.c | 12 ++--- 9 files changed, 181 insertions(+), 95 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0352fa7..54610cc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2008-02-08 Dan Winship + + * libsoup/soup-message-headers.c (SoupMessageHeadersIter) + (soup_message_headers_iter_init, soup_message_headers_iter_next): + Add an iterator type for SoupMessageHeaders. + + * libsoup/soup-message-client-io.c (get_request_headers): + * libsoup/soup-message-server-io.c (get_response_headers): Use + SoupMessageHeadersIter. + + * libsoup/soup-logger.c (print_request, print_response): Use + SoupMessageHeadersIter. And take advantage of the simplification + to fix the kludge where 'direction' was stored as a field in + SoupLoggerPrivate rather than being an argument to + soup_logger_print. + + * tests/get.c (get_url): + * tests/header-parsing.c (check_headers): + * tests/simple-httpd.c (server_callback): Use + SoupMessageHeadersIter + 2008-02-06 Dan Winship * libsoup/soup-server.c (soup_server_add_auth_domain): Ref the diff --git a/libsoup/soup-logger.c b/libsoup/soup-logger.c index aebbff5..174094f 100644 --- a/libsoup/soup-logger.c +++ b/libsoup/soup-logger.c @@ -91,7 +91,6 @@ typedef struct { SoupLoggerPrinter printer; gpointer printer_data; GDestroyNotify printer_dnotify; - char direction; } SoupLoggerPrivate; #define SOUP_LOGGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_LOGGER, SoupLoggerPrivate)) @@ -373,7 +372,7 @@ soup_logger_detach (SoupLogger *logger, static void soup_logger_print (SoupLogger *logger, SoupLoggerLogLevel level, - const char *format, ...) + char direction, const char *format, ...) { SoupLoggerPrivate *priv = SOUP_LOGGER_GET_PRIVATE (logger); va_list args; @@ -394,10 +393,10 @@ soup_logger_print (SoupLogger *logger, SoupLoggerLogLevel level, if (end) *end = '\0'; if (priv->printer) { - priv->printer (logger, level, priv->direction, + priv->printer (logger, level, direction, line, priv->printer_data); } else - printf ("%c %s\n", priv->direction, line); + printf ("%c %s\n", direction, line); line = end + 1; } while (end && *line); @@ -406,28 +405,22 @@ soup_logger_print (SoupLogger *logger, SoupLoggerLogLevel level, } static void -print_header (const char *name, const char *value, gpointer logger) +soup_logger_print_basic_auth (SoupLogger *logger, const char *value) { - if (!g_ascii_strcasecmp (name, "Authorization") && - !g_ascii_strncasecmp (value, "Basic ", 6)) { - char *decoded, *p; - gsize len; - - decoded = (char *)g_base64_decode (value + 6, &len); - if (!decoded) - decoded = g_strdup (value); - p = strchr (decoded, ':'); - if (p) { - while (++p < decoded + len) - *p = '*'; - } - soup_logger_print (logger, SOUP_LOGGER_LOG_HEADERS, - "%s: Basic [%.*s]", name, len, decoded); - g_free (decoded); - } else { - soup_logger_print (logger, SOUP_LOGGER_LOG_HEADERS, - "%s: %s", name, value); + char *decoded, *p; + gsize len; + + decoded = (char *)g_base64_decode (value + 6, &len); + if (!decoded) + decoded = g_strdup (value); + p = strchr (decoded, ':'); + if (p) { + while (++p < decoded + len) + *p = '*'; } + soup_logger_print (logger, SOUP_LOGGER_LOG_HEADERS, '>', + "Authorization: Basic [%.*s]", len, decoded); + g_free (decoded); } static void @@ -437,6 +430,8 @@ print_request (SoupLogger *logger, SoupMessage *msg, { SoupLoggerPrivate *priv = SOUP_LOGGER_GET_PRIVATE (logger); SoupLoggerLogLevel log_level; + SoupMessageHeadersIter iter; + const char *name, *value; SoupURI *uri; if (priv->request_filter) { @@ -448,16 +443,14 @@ print_request (SoupLogger *logger, SoupMessage *msg, if (log_level == SOUP_LOGGER_LOG_NONE) return; - priv->direction = '>'; - uri = soup_message_get_uri (msg); if (msg->method == SOUP_METHOD_CONNECT) { - soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, + soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, '>', "CONNECT %s:%u HTTP/1.%d", uri->host, uri->port, soup_message_get_http_version (msg)); } else { - soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, + soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, '>', "%s %s%s%s HTTP/1.%d", msg->method, uri->path, uri->query ? "?" : "", @@ -465,10 +458,10 @@ print_request (SoupLogger *logger, SoupMessage *msg, soup_message_get_http_version (msg)); } - soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, + soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, '>', "Soup-Debug-Timestamp: %lu", (unsigned long)time (0)); - soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, + soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, '>', "Soup-Debug: %s %u (%p), %s %u (%p), %s %u (%p)%s", g_type_name_from_instance ((GTypeInstance *)session), soup_logger_get_id (logger, session), session, @@ -481,9 +474,18 @@ print_request (SoupLogger *logger, SoupMessage *msg, if (log_level == SOUP_LOGGER_LOG_MINIMAL) return; - print_header ("Host", uri->host, logger); - soup_message_headers_foreach (msg->request_headers, - print_header, logger); + soup_logger_print (logger, SOUP_LOGGER_LOG_HEADERS, '>', + "Host: %s", uri->host); + soup_message_headers_iter_init (&iter, msg->request_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) { + if (!g_ascii_strcasecmp (name, "Authorization") && + !g_ascii_strncasecmp (value, "Basic ", 6)) + soup_logger_print_basic_auth (logger, value); + else { + soup_logger_print (logger, SOUP_LOGGER_LOG_HEADERS, '>', + "%s: %s", name, value); + } + } if (log_level == SOUP_LOGGER_LOG_HEADERS) return; @@ -494,7 +496,7 @@ print_request (SoupLogger *logger, SoupMessage *msg, soup_buffer_free (request); if (soup_message_headers_get_expectations (msg->request_headers) != SOUP_EXPECTATION_CONTINUE) { - soup_logger_print (logger, SOUP_LOGGER_LOG_BODY, + soup_logger_print (logger, SOUP_LOGGER_LOG_BODY, '>', "\n%s", msg->request_body->data); } } @@ -505,6 +507,8 @@ print_response (SoupLogger *logger, SoupMessage *msg) { SoupLoggerPrivate *priv = SOUP_LOGGER_GET_PRIVATE (logger); SoupLoggerLogLevel log_level; + SoupMessageHeadersIter iter; + const char *name, *value; if (priv->response_filter) { log_level = priv->response_filter (logger, msg, @@ -515,17 +519,15 @@ print_response (SoupLogger *logger, SoupMessage *msg) if (log_level == SOUP_LOGGER_LOG_NONE) return; - priv->direction = '<'; - - soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, + soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, '<', "HTTP/1.%d %u %s\n", soup_message_get_http_version (msg), msg->status_code, msg->reason_phrase); - soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, + soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, '<', "Soup-Debug-Timestamp: %lu", (unsigned long)time (0)); - soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, + soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, '<', "Soup-Debug: %s %u (%p)", g_type_name_from_instance ((GTypeInstance *)msg), soup_logger_get_id (logger, msg), msg); @@ -533,13 +535,16 @@ print_response (SoupLogger *logger, SoupMessage *msg) if (log_level == SOUP_LOGGER_LOG_MINIMAL) return; - soup_message_headers_foreach (msg->response_headers, - print_header, logger); + soup_message_headers_iter_init (&iter, msg->response_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) { + soup_logger_print (logger, SOUP_LOGGER_LOG_HEADERS, '<', + "%s: %s", name, value); + } if (log_level == SOUP_LOGGER_LOG_HEADERS) return; if (msg->response_body->length) { - soup_logger_print (logger, SOUP_LOGGER_LOG_BODY, + soup_logger_print (logger, SOUP_LOGGER_LOG_BODY, '<', "\n%s", msg->response_body->data); } } @@ -553,14 +558,12 @@ got_informational (SoupMessage *msg, gpointer user_data) g_mutex_lock (priv->lock); print_response (logger, msg); - priv->direction = ' '; - soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, ""); + soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, ' ', ""); if (msg->status_code == SOUP_STATUS_CONTINUE && msg->request_body->data) { SoupLoggerLogLevel log_level; - priv->direction = '>'; - soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, + soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, '>', "[Now sending request body...]"); if (priv->request_filter) { @@ -570,12 +573,11 @@ got_informational (SoupMessage *msg, gpointer user_data) log_level = priv->level; if (log_level == SOUP_LOGGER_LOG_BODY) { - soup_logger_print (logger, SOUP_LOGGER_LOG_BODY, + soup_logger_print (logger, SOUP_LOGGER_LOG_BODY, '>', "%s", msg->request_body->data); } - priv->direction = ' '; - soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, ""); + soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, ' ', ""); } g_mutex_unlock (priv->lock); @@ -590,8 +592,7 @@ got_body (SoupMessage *msg, gpointer user_data) g_mutex_lock (priv->lock); print_response (logger, msg); - priv->direction = ' '; - soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, ""); + soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, ' ', ""); g_mutex_unlock (priv->lock); } @@ -613,7 +614,6 @@ request_started (SoupSession *session, SoupMessage *msg, SoupSocket *socket, gpointer user_data) { SoupLogger *logger = user_data; - SoupLoggerPrivate *priv = SOUP_LOGGER_GET_PRIVATE (logger); gboolean restarted; guint msg_id; @@ -639,6 +639,5 @@ request_started (SoupSession *session, SoupMessage *msg, soup_logger_set_id (logger, socket); print_request (logger, msg, session, socket, restarted); - priv->direction = ' '; - soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, ""); + soup_logger_print (logger, SOUP_LOGGER_LOG_MINIMAL, ' ', ""); } diff --git a/libsoup/soup-message-client-io.c b/libsoup/soup-message-client-io.c index 5d5b244..4ffbd72 100644 --- a/libsoup/soup-message-client-io.c +++ b/libsoup/soup-message-client-io.c @@ -59,13 +59,6 @@ parse_response_headers (SoupMessage *req, return SOUP_STATUS_OK; } -static void -add_header (const char *name, const char *value, gpointer data) -{ - GString *headers = data; - g_string_append_printf (headers, "%s: %s\r\n", name, value); -} - static void get_request_headers (SoupMessage *req, GString *header, SoupEncoding *encoding, gpointer user_data) @@ -74,6 +67,8 @@ get_request_headers (SoupMessage *req, GString *header, gboolean proxy = GPOINTER_TO_UINT (user_data); SoupURI *uri = soup_message_get_uri (req); char *uri_string; + SoupMessageHeadersIter iter; + const char *name, *value; if (req->method == SOUP_METHOD_CONNECT) { /* CONNECT URI is hostname:port for tunnel destination */ @@ -108,7 +103,9 @@ get_request_headers (SoupMessage *req, GString *header, req->request_body->length); } - soup_message_headers_foreach (req->request_headers, add_header, header); + soup_message_headers_iter_init (&iter, req->request_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + g_string_append_printf (header, "%s: %s\r\n", name, value); g_string_append (header, "\r\n"); } diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c index 6a9eb21..dbca07c 100644 --- a/libsoup/soup-message-headers.c +++ b/libsoup/soup-message-headers.c @@ -257,6 +257,71 @@ soup_message_headers_get (SoupMessageHeaders *hdrs, const char *name) } /** + * SoupMessageHeadersIter: + * + * An opaque type used to iterate over a %SoupMessageHeaders + * structure. + * + * After intializing the iterator with + * soup_message_headers_iter_init(), call + * soup_message_headers_iter_next() to fetch data from it. + * + * You may not modify the headers while iterating over them. + **/ + +typedef struct { + SoupMessageHeaders *hdrs; + int index; +} SoupMessageHeadersIterReal; + +/** + * soup_message_headers_iter_init: + * @iter: a pointer to a %SoupMessageHeadersIter structure + * @hdrs: a %SoupMessageHeaders + * + * Initializes @iter for iterating @hdrs. + **/ +void +soup_message_headers_iter_init (SoupMessageHeadersIter *iter, + SoupMessageHeaders *hdrs) +{ + SoupMessageHeadersIterReal *real = (SoupMessageHeadersIterReal *)iter; + + real->hdrs = hdrs; + real->index = 0; +} + +/** + * soup_message_headers_iter_next: + * @iter: a %SoupMessageHeadersIter + * @name: pointer to a variable to return the header name in + * @value: pointer to a variable to return the header value in + * + * Yields the next name/value pair in the %SoupMessageHeaders being + * iterated by @iter. If @iter has already yielded the last header, + * then soup_message_headers_iter_next() will return %FALSE and @name + * and @value will be unchanged. + * + * Return value: %TRUE if another name and value were returned, %FALSE + * if the end of the headers has been reached. + **/ +gboolean +soup_message_headers_iter_next (SoupMessageHeadersIter *iter, + const char **name, const char **value) +{ + SoupMessageHeadersIterReal *real = (SoupMessageHeadersIterReal *)iter; + SoupHeader *hdr_array = (SoupHeader *)real->hdrs->array->data; + + if (real->index >= real->hdrs->array->len) + return FALSE; + + *name = hdr_array[real->index].name; + *value = hdr_array[real->index].value; + real->index++; + return TRUE; +} + +/** * SoupMessageHeadersForeachFunc: * @name: the header name * @value: the header value @@ -281,6 +346,8 @@ soup_message_headers_get (SoupMessageHeaders *hdrs, const char *name) * then the I/O code will output multiple copies of the header when * sending the message to the remote implementation, which may be * required for interoperability in some cases.) + * + * You may not modify the headers from @func. **/ void soup_message_headers_foreach (SoupMessageHeaders *hdrs, diff --git a/libsoup/soup-message-headers.h b/libsoup/soup-message-headers.h index 68baf52..49f16a2 100644 --- a/libsoup/soup-message-headers.h +++ b/libsoup/soup-message-headers.h @@ -43,6 +43,16 @@ void soup_message_headers_foreach (SoupMessageHeaders *hdrs, SoupMessageHeadersForeachFunc func, gpointer user_data); +typedef struct { + gpointer dummy[3]; +} SoupMessageHeadersIter; + +void soup_message_headers_iter_init (SoupMessageHeadersIter *iter, + SoupMessageHeaders *hdrs); +gboolean soup_message_headers_iter_next (SoupMessageHeadersIter *iter, + const char **name, + const char **value); + /* Specific headers */ typedef enum { diff --git a/libsoup/soup-message-server-io.c b/libsoup/soup-message-server-io.c index c4b85cb..3cf5870 100644 --- a/libsoup/soup-message-server-io.c +++ b/libsoup/soup-message-server-io.c @@ -93,16 +93,12 @@ parse_request_headers (SoupMessage *msg, char *headers, guint headers_len, } static void -write_header (const char *name, const char *value, gpointer headers) -{ - g_string_append_printf (headers, "%s: %s\r\n", name, value); -} - -static void get_response_headers (SoupMessage *msg, GString *headers, SoupEncoding *encoding, gpointer user_data) { SoupEncoding claimed_encoding; + SoupMessageHeadersIter iter; + const char *name, *value; g_string_append_printf (headers, "HTTP/1.1 %d %s\r\n", msg->status_code, msg->reason_phrase); @@ -124,8 +120,9 @@ get_response_headers (SoupMessage *msg, GString *headers, msg->response_body->length); } - soup_message_headers_foreach (msg->response_headers, - write_header, headers); + soup_message_headers_iter_init (&iter, msg->response_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + g_string_append_printf (headers, "%s: %s\r\n", name, value); g_string_append (headers, "\r\n"); } diff --git a/tests/get.c b/tests/get.c index 2c3cfba..a1b12a5 100644 --- a/tests/get.c +++ b/tests/get.c @@ -100,12 +100,6 @@ mkdirs (const char *path) } static void -print_header (const char *name, const char *value, gpointer data) -{ - printf ("%s: %s\n", name, value); -} - -static void get_url (const char *url) { char *url_to_get, *slash, *name; @@ -158,13 +152,19 @@ get_url (const char *url) } if (debug) { + SoupMessageHeadersIter iter; + const char *name, *value; char *path = soup_uri_to_string (soup_message_get_uri (msg), TRUE); + printf ("%s %s HTTP/1.%d\n\n", method, path, soup_message_get_http_version (msg)); printf ("HTTP/1.%d %d %s\n", soup_message_get_http_version (msg), msg->status_code, msg->reason_phrase); - soup_message_headers_foreach (msg->response_headers, print_header, NULL); + + soup_message_headers_iter_init (&iter, msg->response_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + printf ("%s: %s\r\n", name, value); printf ("\n"); } else printf ("%s: %d %s\n", name, msg->status_code, msg->reason_phrase); diff --git a/tests/header-parsing.c b/tests/header-parsing.c index bae3c97..237c4d1 100644 --- a/tests/header-parsing.c +++ b/tests/header-parsing.c @@ -577,25 +577,22 @@ print_header (const char *name, const char *value, gpointer data) debug_printf (1, " '%s': '%s'\n", name, value); } -static void -add_header_name (const char *name, const char *value, gpointer data) -{ - GSList **names = data; - - if (!g_slist_find_custom (*names, name, (GCompareFunc)strcmp)) - *names = g_slist_append (*names, (char *)name); -} - static gboolean check_headers (Header *headers, SoupMessageHeaders *hdrs) { GSList *header_names, *h; - const char *value; + SoupMessageHeadersIter iter; + const char *name, *value; gboolean ok = TRUE; int i; header_names = NULL; - soup_message_headers_foreach (hdrs, add_header_name, &header_names); + soup_message_headers_iter_init (&iter, hdrs); + while (soup_message_headers_iter_next (&iter, &name, &value)) { + if (!g_slist_find_custom (header_names, name, + (GCompareFunc)strcmp)) + header_names = g_slist_append (header_names, (char *)name); + } for (i = 0, h = header_names; headers[i].name && h; i++, h = h->next) { if (strcmp (h->data, headers[i].name) != 0) { diff --git a/tests/simple-httpd.c b/tests/simple-httpd.c index cf06bee..6667251 100644 --- a/tests/simple-httpd.c +++ b/tests/simple-httpd.c @@ -155,21 +155,19 @@ do_put (SoupServer *server, SoupMessage *msg, const char *path) } static void -print_header (const char *name, const char *value, gpointer data) -{ - printf ("%s: %s\n", name, value); -} - -static void server_callback (SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *context, gpointer data) { char *file_path; + SoupMessageHeadersIter iter; + const char *name, *value; printf ("%s %s HTTP/1.%d\n", msg->method, path, soup_message_get_http_version (msg)); - soup_message_headers_foreach (msg->request_headers, print_header, NULL); + soup_message_headers_iter_init (&iter, msg->request_headers); + while (soup_message_headers_iter_next (&iter, &name, &value)) + printf ("%s: %s\n", name, value); if (msg->request_body->length) printf ("%s\n", msg->request_body->data); -- 2.7.4