soup-multipart: Fix generation of Content-Disposition for broken servers
authorDan Winship <danw@gnome.org>
Mon, 4 Apr 2011 17:21:16 +0000 (13:21 -0400)
committerDan Winship <danw@gnome.org>
Thu, 7 Apr 2011 12:36:07 +0000 (08:36 -0400)
Some servers require that Content-Disposition headers use
quoted-string values, even if the provided filename can be represented
as a token. So use soup_header_g_string_append_param_quoted(), but also
change that to fall back to using RFC 5987 encoding if necessary, so
that we can still specify UTF-8-encoded filenames.

libsoup/soup-headers.c
libsoup/soup-multipart.c

index 33f6f6f..2b9c29d 100644 (file)
@@ -844,6 +844,57 @@ append_param_rfc5987 (GString    *string,
        g_free (encoded);
 }
 
+static void
+append_param_quoted (GString    *string,
+                    const char *name,
+                    const char *value)
+{
+       int len;
+
+       g_string_append (string, name);
+       g_string_append (string, "=\"");
+       while (*value) {
+               while (*value == '\\' || *value == '"') {
+                       g_string_append_c (string, '\\');
+                       g_string_append_c (string, *value++);
+               }
+               len = strcspn (value, "\\\"");
+               g_string_append_len (string, value, len);
+               value += len;
+       }
+       g_string_append_c (string, '"');
+}
+
+static void
+append_param_internal (GString    *string,
+                      const char *name,
+                      const char *value,
+                      gboolean    allow_token)
+{
+       const char *v;
+       gboolean use_token = allow_token;
+
+       for (v = value; *v; v++) {
+               if (*v & 0x80) {
+                       if (g_utf8_validate (value, -1, NULL)) {
+                               append_param_rfc5987 (string, name, value);
+                               return;
+                       } else {
+                               use_token = FALSE;
+                               break;
+                       }
+               } else if (!soup_char_is_token (*v))
+                       use_token = FALSE;
+       }
+
+       if (use_token) {
+               g_string_append (string, name);
+               g_string_append_c (string, '=');
+               g_string_append (string, value);
+       } else
+               append_param_quoted (string, name, value);
+}
+
 /**
  * soup_header_g_string_append_param_quoted:
  * @string: a #GString being used to construct an HTTP header value
@@ -853,6 +904,9 @@ append_param_rfc5987 (GString    *string,
  * Appends something like <literal>@name="@value"</literal> to
  * @string, taking care to escape any quotes or backslashes in @value.
  *
+ * If @value is (non-ASCII) UTF-8, this will instead use RFC 5987
+ * encoding, just like soup_header_g_string_append_param().
+ *
  * Since: 2.32
  **/
 void
@@ -860,24 +914,11 @@ soup_header_g_string_append_param_quoted (GString    *string,
                                          const char *name,
                                          const char *value)
 {
-       int len;
-
        g_return_if_fail (string != NULL);
        g_return_if_fail (name != NULL);
        g_return_if_fail (value != NULL);
 
-       g_string_append (string, name);
-       g_string_append (string, "=\"");
-       while (*value) {
-               while (*value == '\\' || *value == '"') {
-                       g_string_append_c (string, '\\');
-                       g_string_append_c (string, *value++);
-               }
-               len = strcspn (value, "\\\"");
-               g_string_append_len (string, value, len);
-               value += len;
-       }
-       g_string_append_c (string, '"');
+       append_param_internal (string, name, value, FALSE);
 }
 
 /**
@@ -905,9 +946,6 @@ soup_header_g_string_append_param (GString    *string,
                                   const char *name,
                                   const char *value)
 {
-       const char *v;
-       gboolean token = TRUE;
-
        g_return_if_fail (string != NULL);
        g_return_if_fail (name != NULL);
 
@@ -916,23 +954,5 @@ soup_header_g_string_append_param (GString    *string,
                return;
        }
 
-       for (v = value; *v; v++) {
-               if (*v & 0x80) {
-                       if (g_utf8_validate (value, -1, NULL)) {
-                               append_param_rfc2231 (string, name, value);
-                               return;
-                       } else {
-                               token = FALSE;
-                               break;
-                       }
-               } else if (!soup_char_is_token (*v))
-                       token = FALSE;
-       }
-
-       if (token) {
-               g_string_append (string, name);
-               g_string_append_c (string, '=');
-               g_string_append (string, value);
-       } else
-               soup_header_g_string_append_param_quoted (string, name, value);
+       append_param_internal (string, name, value, TRUE);
 }
index 45deed6..31d4aba 100644 (file)
@@ -371,10 +371,10 @@ soup_multipart_append_form_file (SoupMultipart *multipart,
 
        headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART);
        disposition = g_string_new ("form-data; ");
-       soup_header_g_string_append_param (disposition, "name", control_name);
+       soup_header_g_string_append_param_quoted (disposition, "name", control_name);
        if (filename) {
                g_string_append (disposition, "; ");
-               soup_header_g_string_append_param (disposition, "filename", filename);
+               soup_header_g_string_append_param_quoted (disposition, "filename", filename);
        }
        soup_message_headers_append (headers, "Content-Disposition",
                                     disposition->str);