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
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)
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)
guint *status_code,
char **reason_phrase)
{
+ SoupHTTPVersion version;
+
if (!str || !*str)
return FALSE;
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;
}
}
},
+ { "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 ***/
/****************************/
{ { 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);
}
},
+ { "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 ***/
/*****************************/
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