diff --git a/src/HttpResponse.cc b/src/HttpResponse.cc index f009ecae..264f9024 100644 --- a/src/HttpResponse.cc +++ b/src/HttpResponse.cc @@ -112,10 +112,12 @@ void HttpResponse::validateResponse() const error_code::HTTP_PROTOCOL_ERROR); } -std::string HttpResponse::determineFilename() const +std::string HttpResponse::determineFilename( + bool contentDispositionUTF8) const { std::string contentDisposition = util::getContentDispositionFilename( - httpHeader_->find(HttpHeader::CONTENT_DISPOSITION)); + httpHeader_->find(HttpHeader::CONTENT_DISPOSITION), + contentDispositionUTF8); if (contentDisposition.empty()) { auto file = httpRequest_->getFile(); file = util::percentDecode(file.begin(), file.end()); diff --git a/src/HttpResponse.h b/src/HttpResponse.h index 38bfa342..2caffaf1 100644 --- a/src/HttpResponse.h +++ b/src/HttpResponse.h @@ -70,7 +70,7 @@ public: * this function returns the filename from it. * If it is not there, returns the part of filename from the request URL. */ - std::string determineFilename() const; + std::string determineFilename(bool contentDispositionUTF8) const; void retrieveCookie(); diff --git a/src/HttpResponseCommand.cc b/src/HttpResponseCommand.cc index 18972575..d0e44803 100644 --- a/src/HttpResponseCommand.cc +++ b/src/HttpResponseCommand.cc @@ -261,8 +261,8 @@ bool HttpResponseCommand::executeInternal() int64_t totalLength = httpResponse->getEntityLength(); fe->setLength(totalLength); if (fe->getPath().empty()) { - auto suffixPath = util::createSafePath(httpResponse->determineFilename()); - + auto suffixPath = util::createSafePath(httpResponse->determineFilename( + getOption()->getAsBool(PREF_CONTENT_DISPOSITION_DEFAULT_UTF8))); fe->setPath(util::applyDir(getOption()->get(PREF_DIR), suffixPath)); fe->setSuffixPath(suffixPath); } diff --git a/src/OptionHandlerFactory.cc b/src/OptionHandlerFactory.cc index fd963613..73b5fa4b 100644 --- a/src/OptionHandlerFactory.cc +++ b/src/OptionHandlerFactory.cc @@ -1203,6 +1203,16 @@ std::vector OptionHandlerFactory::createOptionHandlers() op->setChangeOptionForReserved(true); handlers.push_back(op); } + { + OptionHandler* op(new BooleanOptionHandler( + PREF_CONTENT_DISPOSITION_DEFAULT_UTF8, TEXT_CONTENT_DISPOSITION_DEFAULT_UTF8, + A2_V_FALSE, OptionHandler::OPT_ARG)); + op->addTag(TAG_HTTP); + op->setInitialOption(true); + op->setChangeGlobalOption(true); + op->setChangeOptionForReserved(true); + handlers.push_back(op); + } // FTP Specific Options { OptionHandler* op( diff --git a/src/prefs.cc b/src/prefs.cc index c0e1af6d..80992a85 100644 --- a/src/prefs.cc +++ b/src/prefs.cc @@ -427,6 +427,8 @@ PrefPtr PREF_HTTP_AUTH_CHALLENGE = makePref("http-auth-challenge"); PrefPtr PREF_HTTP_NO_CACHE = makePref("http-no-cache"); // value: true | false PrefPtr PREF_HTTP_ACCEPT_GZIP = makePref("http-accept-gzip"); +// value: true | false +PrefPtr PREF_CONTENT_DISPOSITION_DEFAULT_UTF8 = makePref("content-disposition-default-utf8"); /** * Proxy related preferences diff --git a/src/prefs.h b/src/prefs.h index fb064727..91fa8769 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -380,6 +380,8 @@ extern PrefPtr PREF_HTTP_AUTH_CHALLENGE; extern PrefPtr PREF_HTTP_NO_CACHE; // value: true | false extern PrefPtr PREF_HTTP_ACCEPT_GZIP; +// value: true | false +extern PrefPtr PREF_CONTENT_DISPOSITION_DEFAULT_UTF8; /**; * Proxy related preferences diff --git a/src/usage_text.h b/src/usage_text.h index 3bd835eb..e6c18513 100644 --- a/src/usage_text.h +++ b/src/usage_text.h @@ -537,6 +537,11 @@ #define TEXT_USE_HEAD \ _(" --use-head[=true|false] Use HEAD method for the first request to the HTTP\n" \ " server.") +#define TEXT_CONTENT_DISPOSITION_DEFAULT_UTF8 \ + _(" --content-disposition-default-utf8[=true|false] Handle quoted string in\n" \ + " Content-Disposition header as UTF-8 instead of\n" \ + " ISO-8859-1, for example, the filename parameter,\n" \ + " but not the extended version filename*") #define TEXT_EVENT_POLL \ _(" --event-poll=POLL Specify the method for polling events.") #define TEXT_BT_EXTERNAL_IP \ diff --git a/src/util.cc b/src/util.cc index 8229f98b..bbf6977a 100644 --- a/src/util.cc +++ b/src/util.cc @@ -879,7 +879,7 @@ typedef enum { ssize_t parse_content_disposition(char* dest, size_t destlen, const char** charsetp, size_t* charsetlenp, - const char* in, size_t len) + const char* in, size_t len, bool defaultUTF8) { const char *p = in, *eop = in + len, *mark_first = nullptr, *mark_last = nullptr; @@ -891,7 +891,7 @@ ssize_t parse_content_disposition(char* dest, size_t destlen, /* To suppress warnings */ char* dp = dest; size_t dlen = destlen; - uint32_t dfa_state = 0; + uint32_t dfa_state = UTF8_ACCEPT; uint32_t dfa_code = 0; uint8_t pctval = 0; @@ -981,6 +981,10 @@ ssize_t parse_content_disposition(char* dest, size_t destlen, if (*p == '"') { quoted_seen = 0; state = CD_QUOTED_STRING; + if(defaultUTF8){ + dfa_state = UTF8_ACCEPT; + dfa_code = 0; + } } else if (inRFC2616HttpToken(*p)) { if (in_file_parm) { @@ -1011,16 +1015,24 @@ ssize_t parse_content_disposition(char* dest, size_t destlen, quoted_seen = 1; } else if (*p == '"' && quoted_seen == 0) { + if(defaultUTF8 && dfa_state != UTF8_ACCEPT){ + return -1; + } if (in_file_parm) { flags |= CD_FILENAME_FOUND; } state = CD_AFTER_VALUE; } else { - /* TEXT which is OCTET except CTLs, but including LWS. We only - accept ISO-8859-1 chars. */ + /* TEXT which is OCTET except CTLs, but including LWS. Accept + ISO-8859-1 chars, or UTF-8 if defaultUTF8 is set */ quoted_seen = 0; - if (!isIso8859p1(*p)) { + if (defaultUTF8){ + if (utf8dfa(&dfa_state, &dfa_code, (unsigned char)*p) == UTF8_REJECT) { + return -1; + } + } + else if (!isIso8859p1(*p)) { return -1; } if (in_file_parm) { @@ -1204,7 +1216,8 @@ ssize_t parse_content_disposition(char* dest, size_t destlen, } } -std::string getContentDispositionFilename(const std::string& header) +std::string getContentDispositionFilename(const std::string& header, + bool defaultUTF8) { std::array cdval; size_t cdvallen = cdval.size(); @@ -1212,13 +1225,14 @@ std::string getContentDispositionFilename(const std::string& header) size_t charsetlen; ssize_t rv = parse_content_disposition(cdval.data(), cdvallen, &charset, &charsetlen, - header.c_str(), header.size()); + header.c_str(), header.size(), defaultUTF8); if (rv == -1) { return ""; } std::string res; - if (!charset || strieq(charset, charset + charsetlen, "iso-8859-1")) { + if ((charset && strieq(charset, charset + charsetlen, "iso-8859-1")) + || (!charset && !defaultUTF8)){ res = iso8859p1ToUtf8(cdval.data(), rv); } else { diff --git a/src/util.h b/src/util.h index 76ecb549..2fc8ca40 100644 --- a/src/util.h +++ b/src/util.h @@ -322,11 +322,15 @@ std::string iso8859p1ToUtf8(const std::string& src); // succeeds, or -1. If there is enough room to store filename in // |dest|, this function returns -1. If this function returns -1, the // |dest|, |*charsetp| and |*charsetlenp| are undefined. +// +// It will handle quoted string(as in RFC 7230 section 3.2.6) as +// ISO-8859-1 by default, or UTF-8 if defaultUTF8 == true. ssize_t parse_content_disposition(char* dest, size_t destlen, const char** charsetp, size_t* charsetlenp, - const char* in, size_t len); + const char* in, size_t len, bool defaultUTF8); -std::string getContentDispositionFilename(const std::string& header); +std::string getContentDispositionFilename(const std::string& header, + bool defaultUTF8); std::string toUpper(std::string src); diff --git a/test/HttpResponseTest.cc b/test/HttpResponseTest.cc index f34e1219..ab1e5a8f 100644 --- a/test/HttpResponseTest.cc +++ b/test/HttpResponseTest.cc @@ -148,7 +148,7 @@ void HttpResponseTest::testDetermineFilename_without_ContentDisposition() httpResponse.setHttpRequest(std::move(httpRequest)); CPPUNIT_ASSERT_EQUAL(std::string("aria2-1.0.0.tar.bz2"), - httpResponse.determineFilename()); + httpResponse.determineFilename(false)); } void HttpResponseTest:: @@ -166,7 +166,7 @@ void HttpResponseTest:: httpResponse.setHttpRequest(std::move(httpRequest)); CPPUNIT_ASSERT_EQUAL(std::string("aria2-1.0.0.tar.bz2"), - httpResponse.determineFilename()); + httpResponse.determineFilename(false)); } void HttpResponseTest::testDetermineFilename_with_ContentDisposition() @@ -184,7 +184,7 @@ void HttpResponseTest::testDetermineFilename_with_ContentDisposition() httpResponse.setHttpRequest(std::move(httpRequest)); CPPUNIT_ASSERT_EQUAL(std::string("aria2-current.tar.bz2"), - httpResponse.determineFilename()); + httpResponse.determineFilename(false)); } void HttpResponseTest::testGetRedirectURI_without_Location() diff --git a/test/UtilTest1.cc b/test/UtilTest1.cc index 08ac13d4..ad8eddb2 100644 --- a/test/UtilTest1.cc +++ b/test/UtilTest1.cc @@ -751,68 +751,78 @@ void UtilTest1::testGetContentDispositionFilename() val = "attachment; filename=\"aria2.tar.bz2\""; CPPUNIT_ASSERT_EQUAL(std::string("aria2.tar.bz2"), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); val = "attachment; filename=\"\""; CPPUNIT_ASSERT_EQUAL(std::string(""), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); val = "attachment; filename=\""; CPPUNIT_ASSERT_EQUAL(std::string(""), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); val = "attachment; filename= \" aria2.tar.bz2 \""; CPPUNIT_ASSERT_EQUAL(std::string(" aria2.tar.bz2 "), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); val = "attachment; filename=dir/file"; CPPUNIT_ASSERT_EQUAL(std::string(""), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); val = "attachment; filename=dir\\file"; CPPUNIT_ASSERT_EQUAL(std::string(""), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); val = "attachment; filename=\"dir/file\""; CPPUNIT_ASSERT_EQUAL(std::string(""), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); val = "attachment; filename=\"dir\\\\file\""; CPPUNIT_ASSERT_EQUAL(std::string(""), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); val = "attachment; filename=\"/etc/passwd\""; CPPUNIT_ASSERT_EQUAL(std::string(""), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); val = "attachment; filename=\"..\""; CPPUNIT_ASSERT_EQUAL(std::string(""), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); val = "attachment; filename=.."; CPPUNIT_ASSERT_EQUAL(std::string(""), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); // Unescaping %2E%2E%2F produces "../". But since we won't unescape, // we just accept it as is. val = "attachment; filename=\"%2E%2E%2Ffoo.html\""; CPPUNIT_ASSERT_EQUAL(std::string("%2E%2E%2Ffoo.html"), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); // iso-8859-1 string will be converted to utf-8. val = "attachment; filename*=iso-8859-1''foo-%E4.html"; CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); val = "attachment; filename*= UTF-8''foo-%c3%a4.html"; CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); // iso-8859-1 string will be converted to utf-8. val = "attachment; filename=\"foo-%E4.html\""; val = util::percentDecode(val.begin(), val.end()); CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"), - util::getContentDispositionFilename(val)); + util::getContentDispositionFilename(val, false)); + + // allow utf-8 in filename if default_utf8 is set. + val = "attachment; filename=\"foo-ä.html\""; + CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"), + util::getContentDispositionFilename(val, true)); + + // return empty if default_utf8 is set but invalid utf8. + val = "attachment; filename=\"foo-\xc2\x02.html\""; + CPPUNIT_ASSERT_EQUAL(std::string(""), + util::getContentDispositionFilename(val, true)); } void UtilTest1::testParseContentDisposition1() @@ -828,19 +838,19 @@ void UtilTest1::testParseContentDisposition1() val = "inline"; CPPUNIT_ASSERT_EQUAL( (ssize_t)0, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // inlonlyquoted val = "\"inline\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // inlwithasciifilename val = "inline; filename=\"foo.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); @@ -848,7 +858,7 @@ void UtilTest1::testParseContentDisposition1() val = "inline; filename=\"Not an attachment!\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)18, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("Not an attachment!"), std::string(&dest[0], &dest[18])); @@ -856,14 +866,14 @@ void UtilTest1::testParseContentDisposition1() val = "inline; filename=\"foo.pdf\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)7, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.pdf"), std::string(&dest[0], &dest[7])); // attwithasciifilename25 val = "attachment; filename=\"0000000000111111111122222\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)25, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("0000000000111111111122222"), std::string(&dest[0], &dest[25])); @@ -871,7 +881,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; filename=\"00000000001111111111222222222233333\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)35, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("00000000001111111111222222222233333"), std::string(&dest[0], &dest[35])); @@ -879,7 +889,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; filename=\"f\\oo.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); @@ -887,7 +897,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; filename=\"\\\"quoting\\\" tested.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)21, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("\"quoting\" tested.html"), std::string(&dest[0], &dest[21])); @@ -895,7 +905,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; filename=\"Here's a semicolon;.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)24, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("Here's a semicolon;.html"), std::string(&dest[0], &dest[24])); @@ -903,7 +913,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; foo=\"bar\"; filename=\"foo.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); @@ -911,7 +921,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; foo=\"\\\"\\\\\";filename=\"foo.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); @@ -919,7 +929,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; FILENAME=\"foo.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); @@ -927,7 +937,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; filename=foo.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); @@ -935,31 +945,31 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; filename=foo,bar.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithasciifilenamenqs val = "attachment; filename=foo.html ;"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attemptyparam val = "attachment; ;filename=foo"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithasciifilenamenqws val = "attachment; filename=foo bar.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithfntokensq val = "attachment; filename='foo.bar'"; CPPUNIT_ASSERT_EQUAL( (ssize_t)9, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("'foo.bar'"), std::string(&dest[0], &dest[9])); @@ -969,7 +979,7 @@ void UtilTest1::testParseContentDisposition1() val = util::percentDecode(val.begin(), val.end()); CPPUNIT_ASSERT_EQUAL( (ssize_t)10, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"), util::iso8859p1ToUtf8(std::string(&dest[0], &dest[10]))); @@ -979,7 +989,7 @@ void UtilTest1::testParseContentDisposition1() val = util::percentDecode(val.begin(), val.end()); CPPUNIT_ASSERT_EQUAL( (ssize_t)11, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"), util::iso8859p1ToUtf8(std::string(&dest[0], &dest[11]))); @@ -987,7 +997,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; filename=\"foo-%41.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)12, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo-%41.html"), std::string(&dest[0], &dest[12])); @@ -995,7 +1005,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; filename=\"50%.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("50%.html"), std::string(&dest[0], &dest[8])); @@ -1003,7 +1013,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; filename=\"foo-%\\41.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)12, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo-%41.html"), std::string(&dest[0], &dest[12])); @@ -1011,7 +1021,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; name=\"foo-%41.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)0, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithfilenamepctandiso // attachment; filename="ä-%41.html" @@ -1019,7 +1029,7 @@ void UtilTest1::testParseContentDisposition1() val = util::percentDecode(val.begin(), val.end()); CPPUNIT_ASSERT_EQUAL( (ssize_t)10, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("ä-%41.html"), util::iso8859p1ToUtf8(std::string(&dest[0], &dest[10]))); @@ -1027,7 +1037,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; filename=\"foo-%c3%a4-%e2%82%ac.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)25, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo-%c3%a4-%e2%82%ac.html"), std::string(&dest[0], &dest[25])); @@ -1035,7 +1045,7 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; filename =\"foo.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); @@ -1043,99 +1053,99 @@ void UtilTest1::testParseContentDisposition1() val = "attachment; filename=\"foo.html\"; filename=\"bar.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attfnbrokentoken val = "attachment; filename=foo[1](2).html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attfnbrokentokeniso val = "attachment; filename=foo-%E4.html"; val = util::percentDecode(val.begin(), val.end()); CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attfnbrokentokenutf // attachment; filename=foo-ä.html val = "attachment; filename=foo-ä.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attmissingdisposition val = "filename=foo.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attmissingdisposition2 val = "x=y; filename=foo.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attmissingdisposition3 val = "\"foo; filename=bar;baz\"; filename=qux"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attmissingdisposition4 val = "filename=foo.html, filename=bar.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // emptydisposition val = "; filename=foo.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // doublecolon val = ": inline; attachment; filename=foo.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attandinline val = "inline; attachment; filename=foo.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attandinline2 val = "attachment; inline; filename=foo.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attbrokenquotedfn val = "attachment; filename=\"foo.html\".txt"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attbrokenquotedfn2 val = "attachment; filename=\"bar"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attbrokenquotedfn3 val = "attachment; filename=foo\"bar;baz\"qux"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attmultinstances val = "attachment; filename=foo.html, attachment; filename=bar.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); } void UtilTest1::testParseContentDisposition2() @@ -1151,37 +1161,37 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; foo=foo filename=bar"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attmissingdelim2 val = "attachment; filename=bar foo=foo "; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attmissingdelim3 val = "attachment filename=bar"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attreversed val = "filename=foo.html; attachment"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attconfusedparam val = "attachment; xfilename=foo.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)0, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attabspath val = "attachment; filename=\"/foo.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)9, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("/foo.html"), std::string(&dest[0], &dest[9])); @@ -1189,7 +1199,7 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; filename=\"\\\\foo.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)9, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("\\foo.html"), std::string(&dest[0], &dest[9])); @@ -1197,25 +1207,25 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; creation-date=\"Wed, 12 Feb 1997 16:29:51 -0500\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)0, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // dispext val = "foobar"; CPPUNIT_ASSERT_EQUAL( (ssize_t)0, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // dispextbadfn val = "attachment; example=\"filename=example.txt\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)0, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithisofn2231iso val = "attachment; filename*=iso-8859-1''foo-%E4.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)10, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("iso-8859-1"), std::string(cs, cslen)); CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"), util::iso8859p1ToUtf8(std::string(&dest[0], &dest[10]))); @@ -1224,7 +1234,7 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; filename*=UTF-8''foo-%c3%a4-%e2%82%ac.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)15, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("UTF-8"), std::string(cs, cslen)); CPPUNIT_ASSERT_EQUAL(std::string("foo-ä-€.html"), std::string(&dest[0], &dest[15])); @@ -1233,13 +1243,13 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; filename*=''foo-%c3%a4-%e2%82%ac.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithfn2231utf8comp val = "attachment; filename*=UTF-8''foo-a%cc%88.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)12, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); val = "foo-a%cc%88.html"; CPPUNIT_ASSERT_EQUAL(std::string(util::percentDecode(val.begin(), val.end())), std::string(&dest[0], &dest[12])); @@ -1248,25 +1258,25 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; filename*=iso-8859-1''foo-%c3%a4-%e2%82%ac.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithfn2231iso-bad val = "attachment; filename*=utf-8''foo-%E4.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithfn2231ws1 val = "attachment; filename *=UTF-8''foo-%c3%a4.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithfn2231ws2 val = "attachment; filename*= UTF-8''foo-%c3%a4.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)11, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"), std::string(&dest[0], &dest[11])); @@ -1274,7 +1284,7 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; filename* =UTF-8''foo-%c3%a4.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)11, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"), std::string(&dest[0], &dest[11])); @@ -1282,37 +1292,37 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; filename*=\"UTF-8''foo-%c3%a4.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithfn2231quot2 val = "attachment; filename*=\"foo%20bar.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithfn2231singleqmissing val = "attachment; filename*=UTF-8'foo-%c3%a4.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithfn2231nbadpct1 val = "attachment; filename*=UTF-8''foo%"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithfn2231nbadpct2 val = "attachment; filename*=UTF-8''f%oo.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attwithfn2231dpct val = "attachment; filename*=UTF-8''A-%2541.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)10, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("A-%41.html"), std::string(&dest[0], &dest[10])); @@ -1320,7 +1330,7 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; filename*=UTF-8''%5cfoo.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)9, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("\\foo.html"), std::string(&dest[0], &dest[9])); @@ -1329,7 +1339,7 @@ void UtilTest1::testParseContentDisposition2() "attachment; filename=\"foo-ae.html\"; filename*=UTF-8''foo-%c3%a4.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)11, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"), std::string(&dest[0], &dest[11])); @@ -1338,7 +1348,7 @@ void UtilTest1::testParseContentDisposition2() "attachment; filename*=UTF-8''foo-%c3%a4.html; filename=\"foo-ae.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)11, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"), std::string(&dest[0], &dest[11])); @@ -1347,7 +1357,7 @@ void UtilTest1::testParseContentDisposition2() "filename*=ISO-8859-1''currency-sign%3d%a4"; CPPUNIT_ASSERT_EQUAL( (ssize_t)15, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("ISO-8859-1"), std::string(cs, cslen)); CPPUNIT_ASSERT_EQUAL(std::string("currency-sign=¤"), util::iso8859p1ToUtf8(std::string(&dest[0], &dest[15]))); @@ -1356,7 +1366,7 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; foobar=x; filename=\"foo.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); @@ -1364,13 +1374,13 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; filename==?ISO-8859-1?Q?foo-=E4.html?="; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // attrfc2047quoted val = "attachment; filename=\"=?ISO-8859-1?Q?foo-=E4.html?=\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)29, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("=?ISO-8859-1?Q?foo-=E4.html?="), std::string(&dest[0], &dest[29])); @@ -1380,52 +1390,52 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; filename="; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // zero-length filename. quoted-string can be empty string, so this // is ok. val = "attachment; filename=\"\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)0, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // empty value is not allowed val = "attachment; filename=;"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // / is not valid char in token. val = "attachment; filename=dir/file"; CPPUNIT_ASSERT_EQUAL( (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); // value-chars is *(pct-encoded / attr-char), so empty string is // allowed. val = "attachment; filename*=UTF-8''"; CPPUNIT_ASSERT_EQUAL( (ssize_t)0, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("UTF-8"), std::string(cs, cslen)); val = "attachment; filename*=UTF-8''; filename=foo"; CPPUNIT_ASSERT_EQUAL( (ssize_t)0, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("UTF-8"), std::string(cs, cslen)); val = "attachment; filename*=UTF-8'' ; filename=foo"; CPPUNIT_ASSERT_EQUAL( (ssize_t)0, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("UTF-8"), std::string(cs, cslen)); // with language val = "attachment; filename*=UTF-8'japanese'konnichiwa"; CPPUNIT_ASSERT_EQUAL( (ssize_t)10, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("konnichiwa"), std::string(&dest[0], &dest[10])); @@ -1433,7 +1443,7 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; filename = foo.html"; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); @@ -1441,7 +1451,7 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; filename = \"foo.html\""; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); @@ -1449,37 +1459,45 @@ void UtilTest1::testParseContentDisposition2() val = "attachment; filename=foo.html "; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); val = "attachment; filename=foo.html ; hello=world"; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); val = "attachment; filename=\"foo.html\" "; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); val = "attachment; filename=\"foo.html\" ; hello=world"; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); val = "attachment; filename*=UTF-8''foo.html ; hello=world"; CPPUNIT_ASSERT_EQUAL( (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen, - val.c_str(), val.size())); + val.c_str(), val.size(), false)); CPPUNIT_ASSERT_EQUAL(std::string("foo.html"), std::string(&dest[0], &dest[8])); + + // allow utf8 if content-disposition-default-utf8 is set + val = "attachment; filename=\"foo-ä.html\""; + CPPUNIT_ASSERT_EQUAL( + (ssize_t)11, util::parse_content_disposition(dest, destlen, &cs, &cslen, + val.c_str(), val.size(), false)); + CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"), + std::string(&dest[0], &dest[11])); } } // namespace aria2