Более быстрый способ правильно извлечь имя файла из заголовка Content-Disposition в c ++ - PullRequest
0 голосов
/ 03 апреля 2020

Я хочу извлечь все возможные типы допустимых имен файлов из атрибута «имя файла» HTTP-заголовка Content-Disposition, как показано в следующем примере:

Content-Disposition: attachment; filename="filename.jpg"
Content-Disposition: attachment; filename=file-2020-April.txt.vbs"

Кроме того, иногда имя файла имеет символы не ASCII и в в таком случае правильное имя файла происходит из атрибута «filename = *», как в следующем примере: (это просто пример, а не фактические данные)

Content-Disposition: attachment; filename="??.txt"; filename*=UTF-8''日本.txt

Я использовал следующие строковые функции для извлечения только из имени файла = "

string ContentDispositionHeader;
int startPos = ContentDispositionHeader.find("\"");
startPos++;
int endPos = ContentDispositionHeader.find_last_of("\"");
int length = endPos - startPos;
string filename = ContentDispositionHeader.substr(startPos, length);

Однако мне нужно написать код для управления регистром именования файлов (обычный и UTF-8). Есть ли более быстрый способ легко извлечь имена файлов.

1 Ответ

1 голос
/ 03 апреля 2020

Я считаю, что вы не можете получить быстрее , чем O(n), где n = length of the header, если это то, что вы ищете. И это то, что вы уже пытаетесь сделать.

Ниже приведен пример, который извлекает имена файлов из заголовков аналогичным образом, учитывая, что кавычки всегда присутствуют (см. RF C 6266 (подробнее об этом); и формат UTF-8 всегда следует за форматом ASCII, если последний присутствует. Более того, при синтаксическом анализе заголовка может потребоваться больше случаев.

Вот пример ( live ):

#include <iostream>
#include <string>
#include <vector>
#include <utility>

// Filenames: <ASCII, UTF-8>
using Filenames = std::pair<std::string, std::string>;

Filenames getFilename( const std::string& header )
{
    std::string ascii;

    const std::string q1 { R"(filename=")" };
    if ( const auto pos = header.find(q1); pos != std::string::npos )
    {
        const auto len = pos + q1.size();

        const std::string q2 { R"(")" };
        if ( const auto pos = header.find(q2, len); pos != std::string::npos )
        {
            ascii = header.substr(len, pos - len);
        }
    }

    std::string utf8;

    const std::string u { R"(UTF-8'')" };
    if ( const auto pos = header.find(u); pos != std::string::npos )
    {
        utf8 = header.substr(pos + u.size());
    }

    return { ascii, utf8 };
}

int main()
{
    const std::vector<std::string> headers
    {
        R"(Content-Disposition: attachment; filename="??.txt"; filename*=UTF-8''日本.txt)",
        R"(Content-Disposition: attachment; filename*=UTF-8''日本.txt)",
        R"(Content-Disposition: attachment; filename="filename.jpg")",
        R"(Content-Disposition: attachment; filename="file-2020-April.txt.vbs")"
    };

    for ( const auto& header : headers )
    {
        const auto& [ascii, utf8] = getFilename( header );
        std::cout << header
                  << "\n\tASCII: " << ascii
                  << "\n\tUTF-8: " << utf8 << '\n';
    }

    return 0;
}

Вывод:

Content-Disposition: attachment; filename="??.txt"; filename*=UTF-8''日本.txt
    ASCII: ??.txt
    UTF-8: 日本.txt
Content-Disposition: attachment; filename*=UTF-8''日本.txt
    ASCII: 
    UTF-8: 日本.txt
Content-Disposition: attachment; filename="filename.jpg"
    ASCII: filename.jpg
    UTF-8: 
Content-Disposition: attachment; filename="file-2020-April.txt.vbs"
    ASCII: file-2020-April.txt.vbs
    UTF-8: 
...