Загрузка файла ASP.NET Core 2 с Emojis в имени файла создает искаженное имя файла - PullRequest
0 голосов
/ 10 мая 2018

Для загрузки файлов из приложения ASP.NET Core 2 я использовал PhysicalFileResult (реализация IActionResult) для возврата файлов из действия контроллера GET. Для имен файлов с «типичными» символами все работает отлично. Это включает в себя наборы символов с акцентом и кандзи, которые я тестировал до сих пор.

Однако, если имя файла содержит Emoji (что-то разрешенное файловой системой Windows), результирующее имя файла искажено или неправильно закодировано.

Например, я ожидаю, что следующий код доставит файл с именем ?.png, вместо этого он доставит файл с именем: ��.png.

public async Task<IActionResult> GetByIdAsync([FromRoute] long id)
{
    return PhysicalFile("c:\\file.png", "image/png", "?.png");
}

Есть ли особый способ, которым имена файлов, содержащие Emojis, должны быть закодированы для сохранения имени файла, или это проблема с PhysicalFileResult?

1 Ответ

0 голосов
/ 15 мая 2018

Реальность такова, что ваша проблема связана с беспорядком, который является заголовком Content-Disposition и, в более общем смысле, с кодировкой символов в заголовках HTTP. Существует очень старый вопрос переполнения стека: Как закодировать параметр имени файла заголовка Content-Disposition в HTTP , ответы которого, хотя и датированные, охватывают большую часть вашей проблемы, но давайте разберем ее.

PhysicalFileResult наследуется от FileResult и при подготовке к возврату клиенту обрабатывается FileResultExecutorBase, а интересующий вас код этого класса содержится в SetContentDispositionHeader метод:

private static void SetContentDispositionHeader(ActionContext context, FileResult result)
{
    if (!string.IsNullOrEmpty(result.FileDownloadName))
    {
        // From RFC 2183, Sec. 2.3:
        // The sender may want to suggest a filename to be used if the entity is
        // detached and stored in a separate file. If the receiving MUA writes
        // the entity to a file, the suggested filename should be used as a
        // basis for the actual filename, where possible.
        var contentDisposition = new ContentDispositionHeaderValue("attachment");
        contentDisposition.SetHttpFileName(result.FileDownloadName);
        context.HttpContext.Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();
    }
}

Что в конечном итоге приводит вас в класс ContentDispositionHeaderValue из пространства имен Microsoft.Net.Http.Headers. В этом классе в настоящее время 725 строк кода , большинство из которых существуют для того, чтобы гарантировать, что возвращаемые значения верны, учитывая сложную природу заголовков ответа HTTP.

RFC7230 указал, что в заголовках нет никакой полезной кодировки, кроме ASCII:

Исторически HTTP разрешал содержимое полей с текстом в Кодировка ISO-8859-1 [ISO-8859-1], поддерживает только другие кодировки путем использования кодировки [RFC2047]. На практике большинство полей заголовка HTTP значения используют только подмножество кодировки US-ASCII [USASCII]. вновь определенные поля заголовка ДОЛЖНЫ ограничивать значения их полей US-ASCII октет. Получатель ДОЛЖЕН обрабатывать другие октеты в содержимом поля (obs-text) как непрозрачные данные.

В конечном счете, может появиться некоторое облегчение, поскольку RFC8187 с сентября 2017 года дает разъяснения, которые должны смягчить некоторые из этих беспорядков. Выпуск 2688, поданный против абстракций HTTP покрывает необходимость включения этого RFC в ASP.Net.

В то же время вы можете попытаться вставить соответствующее имя в формате http в URI (http://example.com/filedownload/33/%F0%9F%98%80.png), вместо того чтобы полагаться на некорректный заголовок Content-Disposition для предложения имени файла. Чтобы было ясно, это неполное исправление, которое может работать не на всех клиентах.

...