[libsoup] SoupContentDecoder: deal with broken apache Content-Encoding
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup] SoupContentDecoder: deal with broken apache Content-Encoding
- Date: Sun, 22 May 2011 14:05:31 +0000 (UTC)
commit aa8327f9f38b499006d10e3670ca1cedd43e07a8
Author: Dan Winship <danw gnome org>
Date: Sun May 22 10:01:30 2011 -0400
SoupContentDecoder: deal with broken apache Content-Encoding
When sending a .gz file, Apache will (by default) incorrectly claim
"Content-Encoding: gzip", causing us to do the wrong thing with it.
Work around this bug in the same way Firefox does.
https://bugzilla.gnome.org/show_bug.cgi?id=613361
libsoup/soup-content-decoder.c | 10 +++
tests/coding-test.c | 170 ++++++++++++++++++++++++++++++++--------
2 files changed, 148 insertions(+), 32 deletions(-)
---
diff --git a/libsoup/soup-content-decoder.c b/libsoup/soup-content-decoder.c
index d7ddd77..3ab240c 100644
--- a/libsoup/soup-content-decoder.c
+++ b/libsoup/soup-content-decoder.c
@@ -131,6 +131,16 @@ soup_content_decoder_got_headers_cb (SoupMessage *msg, SoupContentDecoder *decod
if (!header)
return;
+ /* Workaround for an apache bug (bgo 613361) */
+ if (!g_ascii_strcasecmp (header, "gzip")) {
+ const char *content_type = soup_message_headers_get_content_type (msg->response_headers, NULL);
+
+ if (content_type &&
+ (!g_ascii_strcasecmp (content_type, "application/gzip") ||
+ !g_ascii_strcasecmp (content_type, "application/x-gzip")))
+ return;
+ }
+
/* OK, really, no one is ever going to use more than one
* encoding, but we'll be robust.
*/
diff --git a/tests/coding-test.c b/tests/coding-test.c
index f3bd852..14b046b 100644
--- a/tests/coding-test.c
+++ b/tests/coding-test.c
@@ -26,14 +26,19 @@ server_callback (SoupServer *server, SoupMessage *msg,
const char *path, GHashTable *query,
SoupClientContext *context, gpointer data)
{
- const char *accept_encoding, *junk, *noencode;
+ const char *accept_encoding, *options;
GSList *codings;
char *file = NULL, *contents;
gsize length;
+ options = soup_message_headers_get_one (msg->request_headers,
+ "X-Test-Options");
+ if (!options)
+ options = "";
+
accept_encoding = soup_message_headers_get_list (msg->request_headers,
"Accept-Encoding");
- if (accept_encoding)
+ if (accept_encoding && !soup_header_contains (options, "force-encode"))
codings = soup_header_parse_quality_list (accept_encoding, NULL);
else
codings = NULL;
@@ -51,16 +56,6 @@ server_callback (SoupServer *server, SoupMessage *msg,
}
soup_header_free_list (codings);
- noencode = soup_message_headers_get_one (msg->request_headers,
- "X-No-Encode");
- if (noencode) {
- /* Force it to send the ungzipped version, even though
- * we already added "Content-Encoding: gzip"
- */
- g_free (file);
- file = NULL;
- }
-
if (!file)
file = g_strdup_printf (SRCDIR "/resources%s", path);
if (!g_file_get_contents (file, &contents, &length, NULL)) {
@@ -74,15 +69,30 @@ server_callback (SoupServer *server, SoupMessage *msg,
}
g_free (file);
+ if (soup_header_contains (options, "force-encode")) {
+ soup_message_headers_replace (msg->response_headers,
+ "Content-Encoding",
+ "gzip");
+ }
+
+ /* Content-Type matches the "real" format, not the sent format */
+ if (g_str_has_suffix (path, ".gz")) {
+ soup_message_headers_append (msg->response_headers,
+ "Content-Type",
+ "application/gzip");
+ } else {
+ soup_message_headers_append (msg->response_headers,
+ "Content-Type",
+ "text/plain");
+ }
+
soup_message_set_status (msg, SOUP_STATUS_OK);
soup_message_body_append (msg->response_body,
SOUP_MEMORY_TAKE, contents, length);
- junk = soup_message_headers_get_one (msg->request_headers,
- "X-Trailing-Junk");
- if (junk) {
+ if (soup_header_contains (options, "trailing-junk")) {
soup_message_body_append (msg->response_body, SOUP_MEMORY_COPY,
- junk, strlen (junk));
+ options, strlen (options));
}
}
@@ -90,9 +100,9 @@ static void
do_coding_test (void)
{
SoupSession *session;
- SoupMessage *msg, *msgz, *msgj, *msgn;
+ SoupMessage *msg, *msgz, *msgj, *msge;
SoupURI *uri;
- const char *coding;
+ const char *coding, *type;
session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
uri = soup_uri_new_with_base (base_uri, "/mbox");
@@ -116,7 +126,12 @@ do_coding_test (void)
debug_printf (1, " SOUP_MESSAGE_CONTENT_DECODED set!\n");
errors++;
}
-
+ type = soup_message_headers_get_one (msg->response_headers, "Content-Type");
+ if (!type || g_ascii_strcasecmp (type, "text/plain") != 0) {
+ debug_printf (1, " Unexpected Content-Type: %s\n",
+ type ? type : "(none)");
+ errors++;
+ }
debug_printf (1, "GET /mbox, Accept-Encoding: gzip\n");
soup_session_add_feature_by_type (session, SOUP_TYPE_CONTENT_DECODER);
@@ -137,6 +152,12 @@ do_coding_test (void)
debug_printf (1, " SOUP_MESSAGE_CONTENT_DECODED not set!\n");
errors++;
}
+ type = soup_message_headers_get_one (msgz->response_headers, "Content-Type");
+ if (!type || g_ascii_strcasecmp (type, "text/plain") != 0) {
+ debug_printf (1, " Unexpected Content-Type: %s\n",
+ type ? type : "(none)");
+ errors++;
+ }
if (msg->response_body->length != msgz->response_body->length) {
debug_printf (1, " Message length mismatch: %lu (plain) vs %lu (compressed)\n",
@@ -154,7 +175,7 @@ do_coding_test (void)
debug_printf (1, "GET /mbox, Accept-Encoding: gzip, plus trailing junk\n");
msgj = soup_message_new_from_uri ("GET", uri);
soup_message_headers_append (msgj->request_headers,
- "X-Trailing-Junk", "junk!");
+ "X-Test-Options", "trailing-junk");
soup_session_send_message (session, msgj);
if (!SOUP_STATUS_IS_SUCCESSFUL (msgj->status_code)) {
debug_printf (1, " Unexpected status %d %s\n",
@@ -171,6 +192,12 @@ do_coding_test (void)
debug_printf (1, " SOUP_MESSAGE_CONTENT_DECODED not set!\n");
errors++;
}
+ type = soup_message_headers_get_one (msgj->response_headers, "Content-Type");
+ if (!type || g_ascii_strcasecmp (type, "text/plain") != 0) {
+ debug_printf (1, " Unexpected Content-Type: %s\n",
+ type ? type : "(none)");
+ errors++;
+ }
if (msg->response_body->length != msgj->response_body->length) {
debug_printf (1, " Message length mismatch: %lu (plain) vs %lu (compressed w/ junk)\n",
@@ -186,16 +213,16 @@ do_coding_test (void)
debug_printf (1, "GET /mbox, Accept-Encoding: gzip, with server error\n");
- msgn = soup_message_new_from_uri ("GET", uri);
- soup_message_headers_append (msgn->request_headers,
- "X-No-Encode", "true");
- soup_session_send_message (session, msgn);
- if (!SOUP_STATUS_IS_SUCCESSFUL (msgn->status_code)) {
+ msge = soup_message_new_from_uri ("GET", uri);
+ soup_message_headers_append (msge->request_headers,
+ "X-Test-Options", "force-encode");
+ soup_session_send_message (session, msge);
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msge->status_code)) {
debug_printf (1, " Unexpected status %d %s\n",
- msgn->status_code, msgn->reason_phrase);
+ msge->status_code, msge->reason_phrase);
errors++;
}
- coding = soup_message_headers_get_one (msgn->response_headers, "Content-Encoding");
+ coding = soup_message_headers_get_one (msge->response_headers, "Content-Encoding");
if (!coding || g_ascii_strcasecmp (coding, "gzip") != 0) {
debug_printf (1, " Unexpected Content-Encoding: %s\n",
coding ? coding : "(none)");
@@ -204,21 +231,28 @@ do_coding_test (void)
/* Since the content wasn't actually gzip-encoded, decoding it
* should have failed and so the flag won't be set.
*/
- if (soup_message_get_flags (msgn) & SOUP_MESSAGE_CONTENT_DECODED) {
+ if (soup_message_get_flags (msge) & SOUP_MESSAGE_CONTENT_DECODED) {
debug_printf (1, " SOUP_MESSAGE_CONTENT_DECODED set!\n");
errors++;
}
+ type = soup_message_headers_get_one (msge->response_headers, "Content-Type");
+ if (!type || g_ascii_strcasecmp (type, "text/plain") != 0) {
+ debug_printf (1, " Unexpected Content-Type: %s\n",
+ type ? type : "(none)");
+ errors++;
+ }
+
/* Failed content-decoding should have left the body untouched
* from what the server sent... which happens to be the
* uncompressed data.
*/
- if (msg->response_body->length != msgn->response_body->length) {
+ if (msg->response_body->length != msge->response_body->length) {
debug_printf (1, " Message length mismatch: %lu (plain) vs %lu (mis-encoded)\n",
(gulong)msg->response_body->length,
- (gulong)msgn->response_body->length);
+ (gulong)msge->response_body->length);
errors++;
} else if (memcmp (msg->response_body->data,
- msgn->response_body->data,
+ msge->response_body->data,
msg->response_body->length) != 0) {
debug_printf (1, " Message data mismatch (plain/misencoded)\n");
errors++;
@@ -228,7 +262,79 @@ do_coding_test (void)
g_object_unref (msg);
g_object_unref (msgz);
g_object_unref (msgj);
- g_object_unref (msgn);
+ g_object_unref (msge);
+ soup_uri_free (uri);
+
+
+ uri = soup_uri_new_with_base (base_uri, "/mbox.gz");
+
+ debug_printf (1, "GET /mbox.gz, Accept-Encoding: gzip\n");
+ soup_session_add_feature_by_type (session, SOUP_TYPE_CONTENT_DECODER);
+ msgz = soup_message_new_from_uri ("GET", uri);
+ soup_session_send_message (session, msgz);
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msgz->status_code)) {
+ debug_printf (1, " Unexpected status %d %s\n",
+ msgz->status_code, msgz->reason_phrase);
+ errors++;
+ }
+ coding = soup_message_headers_get_one (msgz->response_headers, "Content-Encoding");
+ if (coding) {
+ debug_printf (1, " Unexpected Content-Encoding: %s\n", coding);
+ errors++;
+ }
+ type = soup_message_headers_get_one (msgz->response_headers, "Content-Type");
+ if (!type || g_ascii_strcasecmp (type, "application/gzip") != 0) {
+ debug_printf (1, " Unexpected Content-Type: %s\n",
+ type ? type : "(none)");
+ errors++;
+ }
+
+
+ debug_printf (1, "GET /mbox.gz, Accept-Encoding: gzip, with server error\n");
+ msge = soup_message_new_from_uri ("GET", uri);
+ soup_message_headers_append (msge->request_headers,
+ "X-Test-Options", "force-encode");
+ soup_session_send_message (session, msge);
+ if (!SOUP_STATUS_IS_SUCCESSFUL (msge->status_code)) {
+ debug_printf (1, " Unexpected status %d %s\n",
+ msge->status_code, msge->reason_phrase);
+ errors++;
+ }
+ coding = soup_message_headers_get_one (msge->response_headers, "Content-Encoding");
+ if (!coding || g_ascii_strcasecmp (coding, "gzip") != 0) {
+ debug_printf (1, " Unexpected Content-Encoding: %s\n",
+ coding ? coding : "(none)");
+ errors++;
+ }
+ /* SoupContentDecoder should have recognized the bug and thus
+ * not decoded it
+ */
+ if (soup_message_get_flags (msge) & SOUP_MESSAGE_CONTENT_DECODED) {
+ debug_printf (1, " SOUP_MESSAGE_CONTENT_DECODED set!\n");
+ errors++;
+ }
+ type = soup_message_headers_get_one (msge->response_headers, "Content-Type");
+ if (!type || g_ascii_strcasecmp (type, "application/gzip") != 0) {
+ debug_printf (1, " Unexpected Content-Type: %s\n",
+ type ? type : "(none)");
+ errors++;
+ }
+
+ if (msgz->response_body->length != msge->response_body->length) {
+ debug_printf (1, " Message length mismatch: %lu (.gz) vs %lu (mis-encoded)\n",
+ (gulong)msgz->response_body->length,
+ (gulong)msge->response_body->length);
+ errors++;
+ } else if (memcmp (msgz->response_body->data,
+ msge->response_body->data,
+ msgz->response_body->length) != 0) {
+ debug_printf (1, " Message data mismatch (gz/misencoded)\n");
+ errors++;
+ }
+
+
+ g_object_unref (msgz);
+ g_object_unref (msge);
soup_uri_free (uri);
soup_test_session_abort_unref (session);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]