Skip to content

Support filename header with UTF-8 encoded special characters #2276

Open
@FerdinandStapenhorst

Description

@FerdinandStapenhorst

The current function GetMultipartFileHeader only works for file names with ASCII characters.

private static string GetMultipartFileHeader(HttpFile file)
{
    return string.Format(
        "--{0}{4}Content-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"{4}Content-Type: {3}{4}{4}",
        FORM_BOUNDARY, file.Name, file.FileName, file.ContentType ?? "application/octet-stream", LINE_BREAK);
}

Here an example version also supporting other encoded file names by using the filename* header format defined in RFC 5987 "Character Set and Language Encoding for HTTP Header Field Parameters."

private static string GetMultipartFileHeader(HttpFile file, Encoding encoding = null)
{
    // Default to UTF-8 encoding if none is specified
    encoding ??= Encoding.UTF8;

    // Encode the file name using the specified encoding
    string encodedFileName = EncodeFileName(file.FileName, encoding);

    // Generate an ASCII fallback for older servers
    string asciiFileName = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes(file.FileName))
                             .Replace("?", ""); // Replace unrepresentable characters

    return string.Format(
        "--{0}{5}Content-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"; filename*={3}''{4}{5}Content-Type: {6}{5}{5}",
        FORM_BOUNDARY,                         // Boundary for the multipart form-data
        file.Name,                             // Form parameter name
        asciiFileName,                         // ASCII fallback file name
        encoding.WebName,                      // Character set for filename*
        encodedFileName,                       // Percent-encoded file name
        LINE_BREAK,                            // Line break (e.g., "\r\n")
        file.ContentType ?? "application/octet-stream" // Default Content-Type
    );
}


// Helper function to encode the file name for the specified encoding
private static string EncodeFileName(string fileName, Encoding encoding)
{
    byte[] encodedBytes = encoding.GetBytes(fileName);
    return string.Join("", encodedBytes.Select(b => $"%{b:X2}"));
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions