[libsoup/gnome-3-38] headers: Support invalid content-disposition without disposition-type



commit 1d37844399452f66938183db40f1caca5e8c3911
Author: Patrick Griffis <pgriffis igalia com>
Date:   Thu Jul 15 12:00:01 2021 -0500

    headers: Support invalid content-disposition without disposition-type

 libsoup/soup-message-headers.c | 40 +++++++++++++++++++++++++---------------
 tests/header-parsing-test.c    | 36 +++++++++++++++++++++++++++++++++++-
 2 files changed, 60 insertions(+), 16 deletions(-)
---
diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
index 5c8c7cb9..aaf496e7 100644
--- a/libsoup/soup-message-headers.c
+++ b/libsoup/soup-message-headers.c
@@ -1272,26 +1272,36 @@ parse_content_foo (SoupMessageHeaders *hdrs, const char *header_name,
 {
        const char *header;
        char *semi;
+        char *equal;
 
        header = soup_message_headers_get_one (hdrs, header_name);
        if (!header)
                return FALSE;
 
-       if (foo) {
-               *foo = g_strdup (header);
-               semi = strchr (*foo, ';');
-               if (semi) {
-                       char *p = semi;
-
-                       *semi++ = '\0';
-                       while (p - 1 > *foo && g_ascii_isspace(p[-1]))
-                               *(--p) = '\0';
-               }
-       } else {
-               semi = strchr (header, ';');
-               if (semi)
-                       semi++;
-       }
+        /* Some websites send an invalid disposition that only contains parameters;
+         * We can be flexible about handling these by detecting if the first word
+         * is a parameter (foo=bar). */
+        equal = strchr (header, '=');
+        semi = strchr (header, ';');
+        if (equal && (!semi || (equal < semi))) {
+                semi = (char *)header;
+                if (foo)
+                        *foo = NULL;
+        } else if (foo) {
+                *foo = g_strdup (header);
+                semi = strchr (*foo, ';');
+                if (semi) {
+                        char *p = semi;
+
+                        *semi++ = '\0';
+                        while (p - 1 > *foo && g_ascii_isspace(p[-1]))
+                                *(--p) = '\0';
+                }
+        } else {
+                /* Skip type, we don't store it */
+                if (semi)
+                        semi++;
+        }
 
        if (!params)
                return TRUE;
diff --git a/tests/header-parsing-test.c b/tests/header-parsing-test.c
index 31edfd02..946f1188 100644
--- a/tests/header-parsing-test.c
+++ b/tests/header-parsing-test.c
@@ -1032,13 +1032,15 @@ do_param_list_tests (void)
 #define RFC5987_TEST_HEADER_UTF8     "attachment; filename*=UTF-8''t%C3%A9st.txt; filename=\"test.txt\""
 #define RFC5987_TEST_HEADER_ISO      "attachment; filename=\"test.txt\"; filename*=iso-8859-1''t%E9st.txt"
 #define RFC5987_TEST_HEADER_FALLBACK "attachment; filename*=Unknown''t%FF%FF%FFst.txt; filename=\"test.txt\""
+#define RFC5987_TEST_HEADER_NO_TYPE  "filename=\"test.txt\""
+#define RFC5987_TEST_HEADER_NO_TYPE_2  "filename=\"test.txt\"; foo=bar"
 
 static void
 do_content_disposition_tests (void)
 {
        SoupMessageHeaders *hdrs;
        GHashTable *params;
-       const char *header, *filename;
+       const char *header, *filename, *parameter2;
        char *disposition;
        SoupBuffer *buffer;
        SoupMultipart *multipart;
@@ -1101,6 +1103,38 @@ do_content_disposition_tests (void)
        g_assert_cmpstr (filename, ==, RFC5987_TEST_FALLBACK_FILENAME);
        g_hash_table_destroy (params);
 
+        /* Invalid disposition with only a filename still works */
+        soup_message_headers_clear (hdrs);
+        soup_message_headers_append (hdrs, "Content-Disposition",
+                                    RFC5987_TEST_HEADER_NO_TYPE);
+       if (!soup_message_headers_get_content_disposition (hdrs,
+                                                          &disposition,
+                                                          &params)) {
+               soup_test_assert (FALSE, "filename-only decoding FAILED");
+               return;
+       }
+        g_assert_null (disposition);
+        filename = g_hash_table_lookup (params, "filename");
+       g_assert_cmpstr (filename, ==, RFC5987_TEST_FALLBACK_FILENAME);
+       g_hash_table_destroy (params);
+
+        /* Invalid disposition with only two parameters still works */
+        soup_message_headers_clear (hdrs);
+        soup_message_headers_append (hdrs, "Content-Disposition",
+                                    RFC5987_TEST_HEADER_NO_TYPE_2);
+       if (!soup_message_headers_get_content_disposition (hdrs,
+                                                          &disposition,
+                                                          &params)) {
+               soup_test_assert (FALSE, "only two parameters decoding FAILED");
+               return;
+       }
+        g_assert_null (disposition);
+        filename = g_hash_table_lookup (params, "filename");
+       g_assert_cmpstr (filename, ==, RFC5987_TEST_FALLBACK_FILENAME);
+        parameter2 = g_hash_table_lookup (params, "foo");
+        g_assert_cmpstr (parameter2, ==, "bar");
+       g_hash_table_destroy (params);
+
        soup_message_headers_free (hdrs);
 
        /* Ensure that soup-multipart always quotes filename */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]