Add an iterator type for SoupMessageHeaders.
authorDan Winship <danw@src.gnome.org>
Sat, 9 Feb 2008 00:46:12 +0000 (00:46 +0000)
committerDan Winship <danw@src.gnome.org>
Sat, 9 Feb 2008 00:46:12 +0000 (00:46 +0000)
* 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
libsoup/soup-logger.c
libsoup/soup-message-client-io.c
libsoup/soup-message-headers.c
libsoup/soup-message-headers.h
libsoup/soup-message-server-io.c
tests/get.c
tests/header-parsing.c
tests/simple-httpd.c

index 0352fa7..54610cc 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2008-02-08  Dan Winship  <danw@gnome.org>
+
+       * 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  <danw@gnome.org>
 
        * libsoup/soup-server.c (soup_server_add_auth_domain): Ref the
index aebbff5..174094f 100644 (file)
@@ -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, ' ', "");
 }
index 5d5b244..4ffbd72 100644 (file)
@@ -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");
 }
 
index 6a9eb21..dbca07c 100644 (file)
@@ -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,
index 68baf52..49f16a2 100644 (file)
@@ -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 {
index c4b85cb..3cf5870 100644 (file)
@@ -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");
 }
 
index 2c3cfba..a1b12a5 100644 (file)
@@ -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);
index bae3c97..237c4d1 100644 (file)
@@ -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) {
index cf06bee..6667251 100644 (file)
@@ -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);