if the request headers contain an unrecognized Expect: header, return
authorDan Winship <danw@src.gnome.org>
Sun, 3 Feb 2008 02:17:54 +0000 (02:17 +0000)
committerDan Winship <danw@src.gnome.org>
Sun, 3 Feb 2008 02:17:54 +0000 (02:17 +0000)
* libsoup/soup-headers.c (soup_headers_parse_request): if the
request headers contain an unrecognized Expect: header, return
SOUP_STATUS_EXPECTATION_FAILED. Also, process Connection headers
in HTTP/1.0 messages as required by 2616 14.10.
(soup_headers_parse_response): Likewise handle Connection headers
in HTTP/1.0 messages

* tests/header-parsing.c: test those things

svn path=/trunk/; revision=1070

ChangeLog
libsoup/soup-headers.c
tests/header-parsing.c

index b78cdc0..fbda55a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2008-02-02  Dan Winship  <danw@gnome.org>
 
+       * libsoup/soup-headers.c (soup_headers_parse_request): if the
+       request headers contain an unrecognized Expect: header, return
+       SOUP_STATUS_EXPECTATION_FAILED. Also, process Connection headers
+       in HTTP/1.0 messages as required by 2616 14.10.
+       (soup_headers_parse_response): Likewise handle Connection headers
+       in HTTP/1.0 messages
+
+       * tests/header-parsing.c: test those things
+
+2008-02-02  Dan Winship  <danw@gnome.org>
+
        * libsoup/soup-session.c (redirect_handler): Misc fixes: don't
        redirect on "300 Multiple Choices", "304 Not Modified", "305 Use
        Proxy", or any unrecognized status code. Don't redirect unsafe
index 79e512f..b132003 100644 (file)
@@ -105,6 +105,23 @@ done:
        return success;
 }
 
+/* RFC 2616 14.10 */
+static void
+soup_headers_clean_for_10 (SoupMessageHeaders *hdrs)
+{
+       const char *connection;
+       GSList *tokens, *t;
+
+       connection = soup_message_headers_get (hdrs, "Connection");
+       if (!connection)
+               return;
+
+       tokens = soup_header_parse_list (connection);
+       for (t = tokens; t; t = t->next)
+               soup_message_headers_remove (hdrs, t->data);
+       soup_header_free_list (tokens);
+}
+
 /**
  * soup_headers_parse_request:
  * @str: the header string (including the trailing blank line)
@@ -195,6 +212,12 @@ soup_headers_parse_request (const char          *str,
        if (!soup_headers_parse (str, len, req_headers)) 
                return SOUP_STATUS_BAD_REQUEST;
 
+       if (soup_message_headers_get_expectations (req_headers) &
+           SOUP_EXPECTATION_UNRECOGNIZED)
+               return SOUP_STATUS_EXPECTATION_FAILED;
+       if (minor_version == 0)
+               soup_headers_clean_for_10 (req_headers);
+
        if (req_method)
                *req_method = g_strndup (method, method_end - method);
        if (req_path)
@@ -300,6 +323,8 @@ soup_headers_parse_response (const char          *str,
                             guint               *status_code,
                             char               **reason_phrase)
 {
+       SoupHTTPVersion version;
+
        if (!str || !*str)
                return FALSE;
 
@@ -307,10 +332,15 @@ soup_headers_parse_response (const char          *str,
                return FALSE;
 
        if (!soup_headers_parse_status_line (str, 
-                                            ver
+                                            &version
                                             status_code, 
                                             reason_phrase))
                return FALSE;
+       if (ver)
+               *ver = version;
+
+       if (version == SOUP_HTTP_1_0)
+               soup_headers_clean_for_10 (headers);
 
        return TRUE;
 }
index 854efef..bae3c97 100644 (file)
@@ -168,6 +168,16 @@ struct RequestTest {
          }
        },
 
+       { "Connection header on HTTP/1.0 message",
+         "GET / HTTP/1.0\r\nFoo: bar\r\nConnection: Bar, Quux\r\nBar: baz\r\nQuux: foo\r\n", -1,
+         SOUP_STATUS_OK,
+         "GET", "/", SOUP_HTTP_1_0,
+         { { "Foo", "bar" },
+           { "Connection", "Bar, Quux" },
+           { NULL }
+         }
+       },
+
        /****************************/
        /*** RECOVERABLE REQUESTS ***/
        /****************************/
@@ -328,6 +338,12 @@ struct RequestTest {
          { { NULL } }
        },
 
+       { "Unrecognized expectation",
+         "GET / HTTP/1.1\r\nHost: example.com\r\nExpect: the-impossible\r\n", -1,
+         SOUP_STATUS_EXPECTATION_FAILED,
+         NULL, NULL, -1,
+         { { NULL } }
+       }
 };
 static const int num_reqtests = G_N_ELEMENTS (reqtests);
 
@@ -395,6 +411,15 @@ struct ResponseTest {
          }
        },
 
+       { "Connection header on HTTP/1.0 message",
+         "HTTP/1.0 200 ok\r\nFoo: bar\r\nConnection: Bar\r\nBar: quux\r\n", -1,
+         SOUP_HTTP_1_0, SOUP_STATUS_OK, "ok",
+         { { "Foo", "bar" },
+           { "Connection", "Bar" },
+           { NULL }
+         }
+       },
+
        /*****************************/
        /*** RECOVERABLE RESPONSES ***/
        /*****************************/
@@ -552,24 +577,41 @@ print_header (const char *name, const char *value, gpointer data)
        debug_printf (1, "              '%s': '%s'\n", name, value);
 }
 
-typedef struct {
-       Header *headers;
-       int i;
-       gboolean ok;
-} HeaderForeachData;
+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)
 {
-       int i;
+       GSList *header_names, *h;
        const char *value;
+       gboolean ok = TRUE;
+       int i;
 
-       for (i = 0; headers[i].name; i++) {
+       header_names = NULL;
+       soup_message_headers_foreach (hdrs, add_header_name, &header_names);
+
+       for (i = 0, h = header_names; headers[i].name && h; i++, h = h->next) {
+               if (strcmp (h->data, headers[i].name) != 0) {
+                       ok = FALSE;
+                       break;
+               }
                value = soup_message_headers_get (hdrs, headers[i].name);
-               if (strcmp (value, headers[i].value) != 0)
-                       return FALSE;
+               if (strcmp (value, headers[i].value) != 0) {
+                       ok = FALSE;
+                       break;
+               }
        }
-       return TRUE;
+       if (headers[i].name || h)
+               ok = FALSE;
+       g_slist_free (header_names);
+       return ok;
 }
 
 static void