File indexing completed on 2024-04-28 15:25:52

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2010, 2011 Rolf Eike Beer <kde@opensource.sf-tec.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "httpheaderdispositiontest.h"
0009 
0010 #include <QTest>
0011 
0012 #include <QByteArray>
0013 
0014 #include <parsinghelpers.h>
0015 
0016 #include <parsinghelpers.cpp>
0017 
0018 // QT5 TODO QTEST_GUILESS_MAIN(HeaderDispositionTest)
0019 QTEST_MAIN(HeaderDispositionTest)
0020 
0021 static void runTest(const QString &header, const QByteArray &result)
0022 {
0023     QMap<QString, QString> parameters = contentDispositionParser(header);
0024 
0025     QList<QByteArray> results = result.split('\n');
0026     if (result.isEmpty()) {
0027         results.clear();
0028     }
0029 
0030     for (const QByteArray &ba : std::as_const(results)) {
0031         QList<QByteArray> values = ba.split('\t');
0032         const QString key(QString::fromLatin1(values.takeFirst()));
0033 
0034         QVERIFY(parameters.contains(key));
0035 
0036         const QByteArray val = values.takeFirst();
0037         QVERIFY(values.isEmpty());
0038 
0039         QCOMPARE(parameters[key], QString::fromUtf8(val.constData(), val.length()));
0040     }
0041 
0042     QCOMPARE(parameters.count(), results.count());
0043 }
0044 
0045 void HeaderDispositionTest::runAllTests_data()
0046 {
0047     QTest::addColumn<QString>("header");
0048     QTest::addColumn<QByteArray>("result");
0049 
0050     // http://greenbytes.de/tech/tc2231/
0051     QTest::newRow("greenbytes-inlonly") << "inline" << QByteArray("type\tinline");
0052     QTest::newRow("greenbytes-inlonlyquoted") << "\"inline\"" << QByteArray();
0053     QTest::newRow("greenbytes-inlwithasciifilename") << "inline; filename=\"foo.html\""
0054                                                      << QByteArray(
0055                                                             "type\tinline\n"
0056                                                             "filename\tfoo.html");
0057     QTest::newRow("greenbytes-inlwithfnattach") << "inline; filename=\"Not an attachment!\""
0058                                                 << QByteArray(
0059                                                        "type\tinline\n"
0060                                                        "filename\tNot an attachment!");
0061     QTest::newRow("greenbytes-inlwithasciifilenamepdf") << "inline; filename=\"foo.pdf\""
0062                                                         << QByteArray(
0063                                                                "type\tinline\n"
0064                                                                "filename\tfoo.pdf");
0065     QTest::newRow("greenbytes-attonly") << "attachment" << QByteArray("type\tattachment");
0066     QTest::newRow("greenbytes-attonlyquoted") << "\"attachment\"" << QByteArray();
0067     QTest::newRow("greenbytes-attonlyucase") << "ATTACHMENT" << QByteArray("type\tattachment");
0068     QTest::newRow("greenbytes-attwithasciifilename") << "attachment; filename=\"foo.html\""
0069                                                      << QByteArray(
0070                                                             "type\tattachment\n"
0071                                                             "filename\tfoo.html");
0072     QTest::newRow("greenbytes-attwithasciifnescapedchar") << "attachment; filename=\"f\\oo.html\""
0073                                                           << QByteArray(
0074                                                                  "type\tattachment\n"
0075                                                                  "filename\tfoo.html");
0076     QTest::newRow("greenbytes-attwithasciifnescapedquote") << "attachment; filename=\"\\\"quoting\\\" tested.html\""
0077                                                            << QByteArray(
0078                                                                   "type\tattachment\n"
0079                                                                   "filename\t\"quoting\" tested.html");
0080     QTest::newRow("greenbytes-attwithquotedsemicolon") << "attachment; filename=\"Here's a semicolon;.html\""
0081                                                        << QByteArray(
0082                                                               "type\tattachment\n"
0083                                                               "filename\tHere's a semicolon;.html");
0084     QTest::newRow("greenbytes-attwithfilenameandextparam") << "attachment; foo=\"bar\"; filename=\"foo.html\""
0085                                                            << QByteArray(
0086                                                                   "type\tattachment\n"
0087                                                                   "foo\tbar\n"
0088                                                                   "filename\tfoo.html");
0089     QTest::newRow("greenbytes-attwithfilenameandextparamescaped") << "attachment; foo=\"\\\"\\\\\";filename=\"foo.html\""
0090                                                                   << QByteArray(
0091                                                                          "type\tattachment\n"
0092                                                                          "foo\t\"\\\n"
0093                                                                          "filename\tfoo.html");
0094     QTest::newRow("greenbytes-attwithasciifilenameucase") << "attachment; FILENAME=\"foo.html\""
0095                                                           << QByteArray(
0096                                                                  "type\tattachment\n"
0097                                                                  "filename\tfoo.html");
0098     // specification bug in RfC 2616, legal through RfC 2183 and 6266
0099     QTest::newRow("greenbytes-attwithasciifilenamenq") << "attachment; filename=foo.html"
0100                                                        << QByteArray(
0101                                                               "type\tattachment\n"
0102                                                               "filename\tfoo.html");
0103     QTest::newRow("greenbytes-attwithasciifilenamenqws") << "attachment; filename=foo bar.html" << QByteArray("type\tattachment");
0104     QTest::newRow("greenbytes-attwithfntokensq") << "attachment; filename='foo.bar'"
0105                                                  << QByteArray(
0106                                                         "type\tattachment\n"
0107                                                         "filename\t'foo.bar'");
0108     QTest::newRow("greenbytes-attwithisofnplain-x") << QStringLiteral("attachment; filename=\"foo-\xe4.html\"")
0109                                                     << QByteArray(
0110                                                            "type\tattachment\n"
0111                                                            "filename\tfoo-ä.html");
0112     QTest::newRow("greenbytes-attwithisofnplain") << QString::fromLatin1("attachment; filename=\"foo-ä.html\"")
0113                                                   << QByteArray(
0114                                                          "type\tattachment\n"
0115                                                          "filename\tfoo-ä.html");
0116     QTest::newRow("greenbytes-attwithfnrawpctenca") << "attachment; filename=\"foo-%41.html\""
0117                                                     << QByteArray(
0118                                                            "type\tattachment\n"
0119                                                            "filename\tfoo-%41.html");
0120     QTest::newRow("greenbytes-attwithfnusingpct") << "attachment; filename=\"50%.html\""
0121                                                   << QByteArray(
0122                                                          "type\tattachment\n"
0123                                                          "filename\t50%.html");
0124     QTest::newRow("greenbytes-attwithfnrawpctencaq") << "attachment; filename=\"foo-%\\41.html\""
0125                                                      << QByteArray(
0126                                                             "type\tattachment\n"
0127                                                             "filename\tfoo-%41.html");
0128     QTest::newRow("greenbytes-attwithnamepct") << "attachment; name=\"foo-%41.html\""
0129                                                << QByteArray(
0130                                                       "type\tattachment\n"
0131                                                       "name\tfoo-%41.html");
0132     QTest::newRow("greenbytes-attwithfilenamepctandiso") << QStringLiteral("attachment; filename=\"\xe4-%41.html\"")
0133                                                          << QByteArray(
0134                                                                 "type\tattachment\n"
0135                                                                 "filename\tä-%41.html");
0136     QTest::newRow("greenbytes-attwithfnrawpctenclong") << "attachment; filename=\"foo-%c3%a4-%e2%82%ac.html\""
0137                                                        << QByteArray(
0138                                                               "type\tattachment\n"
0139                                                               "filename\tfoo-%c3%a4-%e2%82%ac.html");
0140     QTest::newRow("greenbytes-attwithasciifilenamews1") << "attachment; filename =\"foo.html\""
0141                                                         << QByteArray(
0142                                                                "type\tattachment\n"
0143                                                                "filename\tfoo.html");
0144     QTest::newRow("greenbytes-attwith2filenames") << "attachment; filename=\"foo.html\"; filename=\"bar.html\"" << QByteArray("type\tattachment");
0145     QTest::newRow("greenbytes-attfnbrokentoken") << "attachment; filename=foo[1](2).html" << QByteArray("type\tattachment");
0146     QTest::newRow("greenbytes-attmissingdisposition") << "filename=foo.html" << QByteArray();
0147     QTest::newRow("greenbytes-attmissingdisposition2") << "x=y; filename=foo.html" << QByteArray();
0148     QTest::newRow("greenbytes-attmissingdisposition3") << "\"foo; filename=bar;baz\"; filename=qux" << QByteArray();
0149     QTest::newRow("greenbytes-attmissingdisposition4") << "filename=foo.html, filename=bar.html" << QByteArray();
0150     QTest::newRow("greenbytes-emptydisposition") << "; filename=foo.html" << QByteArray();
0151     QTest::newRow("greenbytes-attbrokenquotedfn") << "attachment; filename=\"foo.html\".txt" << QByteArray("type\tattachment");
0152     QTest::newRow("greenbytes-attbrokenquotedfn2") << "attachment; filename=\"bar" << QByteArray("type\tattachment");
0153     QTest::newRow("greenbytes-attbrokenquotedfn3") << "attachment; filename=foo\"bar;baz\"qux" << QByteArray("type\tattachment");
0154     QTest::newRow("greenbytes-attreversed") << "filename=foo.html; attachment" << QByteArray();
0155     QTest::newRow("greenbytes-attconfusedparam") << "attachment; xfilename=foo.html"
0156                                                  << QByteArray(
0157                                                         "type\tattachment\n"
0158                                                         "xfilename\tfoo.html");
0159     QTest::newRow("greenbytes-attabspath") << "attachment; filename=\"/foo.html\""
0160                                            << QByteArray(
0161                                                   "type\tattachment\n"
0162                                                   "filename\tfoo.html");
0163 #ifdef Q_OS_WIN
0164     QTest::newRow("greenbytes-attabspath") << "attachment; filename=\"\\\\foo.html\""
0165                                            << QByteArray(
0166                                                   "type\tattachment\n"
0167                                                   "filename\tfoo.html");
0168 #else // Q_OS_WIN
0169     QTest::newRow("greenbytes-attabspath") << "attachment; filename=\"\\\\foo.html\""
0170                                            << QByteArray(
0171                                                   "type\tattachment\n"
0172                                                   "filename\t\\foo.html");
0173 #endif // Q_OS_WIN
0174     QTest::newRow("greenbytes-") << "attachment; creation-date=\"Wed, 12 Feb 1997 16:29:51 -0500\""
0175                                  << QByteArray(
0176                                         "type\tattachment\n"
0177                                         "creation-date\tWed, 12 Feb 1997 16:29:51 -0500");
0178     QTest::newRow("greenbytes-") << "attachment; modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\""
0179                                  << QByteArray(
0180                                         "type\tattachment\n"
0181                                         "modification-date\tWed, 12 Feb 1997 16:29:51 -0500");
0182     QTest::newRow("greenbytes-dispext") << "foobar" << QByteArray("type\tfoobar");
0183     QTest::newRow("greenbytes-dispextbadfn") << "attachment; example=\"filename=example.txt\""
0184                                              << QByteArray(
0185                                                     "type\tattachment\n"
0186                                                     "example\tfilename=example.txt");
0187     QTest::newRow("greenbytes-attwithisofn2231iso") << "attachment; filename*=iso-8859-1''foo-%E4.html"
0188                                                     << QByteArray(
0189                                                            "type\tattachment\n"
0190                                                            "filename\tfoo-ä.html");
0191     QTest::newRow("greenbytes-attwithfn2231utf8") << "attachment; filename*=UTF-8''foo-%c3%a4-%e2%82%ac.html"
0192                                                   << QByteArray(
0193                                                          "type\tattachment\n"
0194                                                          "filename\tfoo-ä-€.html");
0195     QTest::newRow("greenbytes-attwithfn2231noc") << "attachment; filename*=''foo-%c3%a4-%e2%82%ac.html" << QByteArray("type\tattachment");
0196     // it's not filename, but "filename "
0197     QTest::newRow("greenbytes-attwithfn2231ws1") << "attachment; filename *=UTF-8''foo-%c3%a4.html" << QByteArray("type\tattachment");
0198     QTest::newRow("greenbytes-attwithfn2231ws2") << "attachment; filename*= UTF-8''foo-%c3%a4.html"
0199                                                  << QByteArray(
0200                                                         "type\tattachment\n"
0201                                                         "filename\tfoo-ä.html");
0202     QTest::newRow("greenbytes-attwithfn2231ws3") << "attachment; filename* =UTF-8''foo-%c3%a4.html"
0203                                                  << QByteArray(
0204                                                         "type\tattachment\n"
0205                                                         "filename\tfoo-ä.html");
0206     // argument must not be enclosed in double quotes
0207     QTest::newRow("greenbytes-attwithfn2231quot") << "attachment; filename*=\"UTF-8''foo-%c3%a4.html\"" << QByteArray("type\tattachment");
0208     QTest::newRow("greenbytes-attwithfn2231dpct") << "attachment; filename*=UTF-8''A-%2541.html"
0209                                                   << QByteArray(
0210                                                          "type\tattachment\n"
0211                                                          "filename\tA-%41.html");
0212 #ifdef Q_OS_WIN
0213     QTest::newRow("greenbytes-attwithfn2231abspathdisguised") << "attachment; filename*=UTF-8''%5cfoo.html"
0214                                                               << QByteArray(
0215                                                                      "type\tattachment\n"
0216                                                                      "filename\tfoo.html");
0217 #else // Q_OS_WIN
0218     QTest::newRow("greenbytes-attwithfn2231abspathdisguised") << "attachment; filename*=UTF-8''%5cfoo.html"
0219                                                               << QByteArray(
0220                                                                      "type\tattachment\n"
0221                                                                      "filename\t\\foo.html");
0222 #endif // Q_OS_WIN
0223     QTest::newRow("greenbytes-attfncont") << "attachment; filename*0=\"foo.\"; filename*1=\"html\""
0224                                           << QByteArray(
0225                                                  "type\tattachment\n"
0226                                                  "filename\tfoo.html");
0227     QTest::newRow("greenbytes-attfncontenc") << "attachment; filename*0*=UTF-8''foo-%c3%a4; filename*1=\".html\""
0228                                              << QByteArray(
0229                                                     "type\tattachment\n"
0230                                                     "filename\tfoo-ä.html");
0231     // no leading zeros
0232     QTest::newRow("greenbytes-attfncontlz") << "attachment; filename*0=\"foo\"; filename*01=\"bar\""
0233                                             << QByteArray(
0234                                                    "type\tattachment\n"
0235                                                    "filename\tfoo");
0236     QTest::newRow("greenbytes-attfncontnc") << "attachment; filename*0=\"foo\"; filename*2=\"bar\""
0237                                             << QByteArray(
0238                                                    "type\tattachment\n"
0239                                                    "filename\tfoo");
0240     // first element must have number 0
0241     QTest::newRow("greenbytes-attfnconts1") << "attachment; filename*1=\"foo.\"; filename*2=\"html\"" << QByteArray("type\tattachment");
0242     // we must not rely on element ordering
0243     QTest::newRow("greenbytes-attfncontord") << "attachment; filename*1=\"bar\"; filename*0=\"foo\""
0244                                              << QByteArray(
0245                                                     "type\tattachment\n"
0246                                                     "filename\tfoobar");
0247     // specifying both param and param* is allowed, param* should be taken
0248     QTest::newRow("greenbytes-attfnboth") << "attachment; filename=\"foo-ae.html\"; filename*=UTF-8''foo-%c3%a4.html"
0249                                           << QByteArray(
0250                                                  "type\tattachment\n"
0251                                                  "filename\tfoo-ä.html");
0252     // specifying both param and param* is allowed, param* should be taken
0253     QTest::newRow("greenbytes-attfnboth2") << "attachment; filename*=UTF-8''foo-%c3%a4.html; filename=\"foo-ae.html\""
0254                                            << QByteArray(
0255                                                   "type\tattachment\n"
0256                                                   "filename\tfoo-ä.html");
0257     QTest::newRow("greenbytes-attnewandfn") << "attachment; foobar=x; filename=\"foo.html\""
0258                                             << QByteArray(
0259                                                    "type\tattachment\n"
0260                                                    "filename\tfoo.html\n"
0261                                                    "foobar\tx");
0262     // invalid argument, should be ignored
0263     QTest::newRow("greenbytes-attrfc2047token") << "attachment; filename==?ISO-8859-1?Q?foo-=E4.html?=" << QByteArray("type\tattachment");
0264     QTest::newRow("space_before_value") << "attachment; filename= \"foo.html\""
0265                                         << QByteArray(
0266                                                "type\tattachment\n"
0267                                                "filename\tfoo.html");
0268     // no character set given but 8 bit characters
0269     QTest::newRow("8bit_in_ascii") << "attachment; filename*=''foo-%c3%a4.html" << QByteArray("type\tattachment");
0270     // there may not be gaps in numbering
0271     QTest::newRow("continuation013") << "attachment; filename*0=\"foo.\"; filename*1=\"html\"; filename*3=\"bar\""
0272                                      << QByteArray(
0273                                             "type\tattachment\n"
0274                                             "filename\tfoo.html");
0275     // "wrong" element ordering and encoding
0276     QTest::newRow("reversed_continuation+encoding") << "attachment; filename*1=\"html\"; filename*0*=us-ascii''foo."
0277                                                     << QByteArray(
0278                                                            "type\tattachment\n"
0279                                                            "filename\tfoo.html");
0280     // unknown charset
0281     QTest::newRow("unknown_charset") << "attachment; filename*=unknown''foo" << QByteArray("type\tattachment");
0282     // no apostrophs
0283     QTest::newRow("encoding-no-apostrophs") << "attachment; filename*=foo" << QByteArray("type\tattachment");
0284     // only one apostroph
0285     QTest::newRow("encoding-one-apostroph") << "attachment; filename*=us-ascii'foo" << QByteArray("type\tattachment");
0286     // duplicate filename, both should be ignored and parsing should stop
0287     QTest::newRow("duplicate-filename") << "attachment; filename=foo; filename=bar; foo=bar" << QByteArray("type\tattachment");
0288     // garbage after closing quote, parsing should stop there
0289     QTest::newRow("garbage_after_closing_quote") << "attachment; filename*=''foo; bar=\"f\"oo; baz=foo"
0290                                                  << QByteArray(
0291                                                         "type\tattachment\n"
0292                                                         "filename\tfoo");
0293     // trailing whitespace should be ignored
0294     QTest::newRow("whitespace_after_value") << "attachment; filename=\"foo\" ; bar=baz"
0295                                             << QByteArray(
0296                                                    "type\tattachment\n"
0297                                                    "filename\tfoo\n"
0298                                                    "bar\tbaz");
0299     // invalid syntax for type
0300     QTest::newRow("invalid_type1") << "filename=foo.html" << QByteArray();
0301     // invalid syntax for type
0302     QTest::newRow("invalid_type2") << "inline{; filename=\"foo\"" << QByteArray();
0303     QTest::newRow("invalid_type3") << "foo bar; filename=\"foo\"" << QByteArray();
0304     QTest::newRow("invalid_type4") << "foo\tbar; filename=\"foo\"" << QByteArray();
0305     // missing closing quote, so parameter is broken
0306     QTest::newRow("no_closing_quote") << "attachment; filename=\"bar" << QByteArray("type\tattachment");
0307     // we ignore any path given in the header and use only the filename
0308     QTest::newRow("full_path_given") << "attachment; filename=\"/etc/shadow\""
0309                                      << QByteArray(
0310                                             "type\tattachment\n"
0311                                             "filename\tshadow");
0312     // we ignore any path given in the header and use only the filename even if there is an error later
0313     QTest::newRow("full_path_and_parse_error") << "attachment; filename=\"/etc/shadow\"; foo=\"baz\"; foo=\"bar\""
0314                                                << QByteArray(
0315                                                       "type\tattachment\n"
0316                                                       "filename\tshadow");
0317     // control characters are forbidden in the quoted string
0318     QTest::newRow("control_character_in_value") << "attachment; filename=\"foo\003\"" << QByteArray("type\tattachment");
0319     // duplicate keys must be ignored
0320     QTest::newRow("duplicate_with_continuation") << "attachment; filename=\"bar\"; filename*0=\"foo.\"; filename*1=\"html\"" << QByteArray("type\tattachment");
0321 
0322     // percent encoding, invalid first character
0323     QTest::newRow("percent-first-char-invalid") << "attachment; filename*=UTF-8''foo-%o5.html" << QByteArray("type\tattachment");
0324     // percent encoding, invalid second character
0325     QTest::newRow("percent-second-char-invalid") << "attachment; filename*=UTF-8''foo-%5o.html" << QByteArray("type\tattachment");
0326     // percent encoding, both characters invalid
0327     QTest::newRow("greenbytes-attwithfn2231nbadpct2") << "attachment; filename*=UTF-8''foo-%oo.html" << QByteArray("type\tattachment");
0328     // percent encoding, invalid second character
0329     QTest::newRow("percent-second-char-missing") << "attachment; filename*=UTF-8''foo-%f.html" << QByteArray("type\tattachment");
0330     // percent encoding, too short value
0331     QTest::newRow("percent-short-encoding-at-end") << "attachment; filename*=UTF-8''foo-%f" << QByteArray("type\tattachment");
0332 }
0333 
0334 #if 0
0335 // currently unclear if our behaviour is only accidentally correct
0336 // invalid syntax
0337 {  "inline; attachment; filename=foo.html",
0338     "type\tinline"
0339 },
0340 // invalid syntax
0341 {
0342     "attachment; inline; filename=foo.html",
0343     "type\tattachment"
0344 },
0345 
0346 // deactivated for now: failing due to missing implementation
0347 {
0348     "attachment; filename=\"foo-&#xc3;&#xa4;.html\"",
0349     "type\tattachment\n"
0350     "filename\tfoo-ä.html"
0351 },
0352 // deactivated for now: not the same utf, no idea if the expected value is actually correct
0353 {
0354     "attachment; filename*=UTF-8''foo-a%cc%88.html",
0355     "type\tattachment\n"
0356     "filename\tfoo-ä.html"
0357 }
0358 
0359 // deactivated for now: only working to missing implementation
0360 // string is not valid iso-8859-1 so filename should be ignored
0361 //"attachment; filename*=iso-8859-1''foo-%c3%a4-%e2%82%ac.html",
0362 //"type\tattachment",
0363 
0364 // deactivated for now: only working to missing implementation
0365 // should not be decoded
0366 //"attachment; filename=\"=?ISO-8859-1?Q?foo-=E4.html?=\"",
0367 //"type\tattachment\n"
0368 //"filename\t=?ISO-8859-1?Q?foo-=E4.html?=",
0369 
0370 };
0371 #endif
0372 
0373 void HeaderDispositionTest::runAllTests()
0374 {
0375     QFETCH(QString, header);
0376     QFETCH(QByteArray, result);
0377 
0378     runTest(header, result);
0379 }
0380 
0381 #include "moc_httpheaderdispositiontest.cpp"