From 429ae942574c9f62938ad77eebe70aed0500b665 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Mon, 4 Apr 2011 13:21:16 -0400 Subject: [PATCH] soup-multipart: Fix generation of Content-Disposition for broken servers 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 | 92 +++++++++++++++++++++++++++++------------------- libsoup/soup-multipart.c | 4 +-- 2 files changed, 58 insertions(+), 38 deletions(-) diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c index 33f6f6f..2b9c29d 100644 --- a/libsoup/soup-headers.c +++ b/libsoup/soup-headers.c @@ -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 @name="@value" 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); } diff --git a/libsoup/soup-multipart.c b/libsoup/soup-multipart.c index 45deed6..31d4aba 100644 --- a/libsoup/soup-multipart.c +++ b/libsoup/soup-multipart.c @@ -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); -- 2.7.4