Browse Source

new option content-disposition-default-utf8

JimmyZ 8 năm trước cách đây
mục cha
commit
da730478af
11 tập tin đã thay đổi với 373 bổ sung306 xóa
  1. 3 2
      src/HttpResponse.cc
  2. 1 1
      src/HttpResponse.h
  3. 2 2
      src/HttpResponseCommand.cc
  4. 12 0
      src/OptionHandlerFactory.cc
  5. 3 0
      src/prefs.cc
  6. 2 0
      src/prefs.h
  7. 5 0
      src/usage_text.h
  8. 23 8
      src/util.cc
  9. 6 2
      src/util.h
  10. 3 3
      test/HttpResponseTest.cc
  11. 313 288
      test/UtilTest1.cc

+ 3 - 2
src/HttpResponse.cc

@@ -112,10 +112,11 @@ 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());

+ 1 - 1
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();
 

+ 2 - 2
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);
     }

+ 12 - 0
src/OptionHandlerFactory.cc

@@ -1054,6 +1054,18 @@ std::vector<OptionHandler*> OptionHandlerFactory::createOptionHandlers()
     op->addTag(TAG_HTTPS);
     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_ADVANCED);
+    op->addTag(TAG_HTTP);
+    op->setInitialOption(true);
+    op->setChangeGlobalOption(true);
+    op->setChangeOptionForReserved(true);
+    handlers.push_back(op);
+  }
   {
     OptionHandler* op(new BooleanOptionHandler(
         PREF_ENABLE_HTTP_KEEP_ALIVE, TEXT_ENABLE_HTTP_KEEP_ALIVE, A2_V_TRUE,

+ 3 - 0
src/prefs.cc

@@ -427,6 +427,9 @@ 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

+ 2 - 0
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

+ 5 - 0
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                                             \

+ 23 - 8
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,25 @@ 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 +1217,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<char, 1_k> cdval;
   size_t cdvallen = cdval.size();
@@ -1212,13 +1226,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 {

+ 6 - 2
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);
 

+ 3 - 3
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()

+ 313 - 288
test/UtilTest1.cc

@@ -3,6 +3,7 @@
 #include <cmath>
 #include <cstring>
 #include <string>
+#include <cassert>
 #include <iostream>
 
 #include <cppunit/extensions/HelperMacros.h>
@@ -751,68 +752,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()
@@ -826,140 +837,140 @@ void UtilTest1::testParseContentDisposition1()
   // test cases from http://greenbytes.de/tech/tc2231/
   // inlonly
   val = "inline";
-  CPPUNIT_ASSERT_EQUAL(
-      (ssize_t)0, util::parse_content_disposition(dest, destlen, &cs, &cslen,
-                                                  val.c_str(), val.size()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)0, util::parse_content_disposition(
+                                       dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[8]));
 
   // inlwithfnattach
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)18, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("Not an attachment!"),
                        std::string(&dest[0], &dest[18]));
 
   // inlwithasciifilenamepdf
   val = "inline; filename=\"foo.pdf\"";
-  CPPUNIT_ASSERT_EQUAL(
-      (ssize_t)7, util::parse_content_disposition(dest, destlen, &cs, &cslen,
-                                                  val.c_str(), val.size()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)7, util::parse_content_disposition(
+                                       dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)25, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("0000000000111111111122222"),
                        std::string(&dest[0], &dest[25]));
 
   // attwithasciifilename35
   val = "attachment; filename=\"00000000001111111111222222222233333\"";
-  CPPUNIT_ASSERT_EQUAL(
-      (ssize_t)35, util::parse_content_disposition(dest, destlen, &cs, &cslen,
-                                                   val.c_str(), val.size()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)35, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("00000000001111111111222222222233333"),
                        std::string(&dest[0], &dest[35]));
 
   // attwithasciifnescapedchar
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[8]));
 
   // attwithasciifnescapedquote
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)21, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("\"quoting\" tested.html"),
                        std::string(&dest[0], &dest[21]));
 
   // attwithquotedsemicolon
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)24, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("Here's a semicolon;.html"),
                        std::string(&dest[0], &dest[24]));
 
   // attwithfilenameandextparam
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[8]));
 
   // attwithfilenameandextparamescaped
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[8]));
 
   // attwithasciifilenameucase
   val = "attachment; FILENAME=\"foo.html\"";
-  CPPUNIT_ASSERT_EQUAL(
-      (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen,
-                                                  val.c_str(), val.size()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[8]));
 
   // attwithasciifilenamenq
   val = "attachment; filename=foo.html";
-  CPPUNIT_ASSERT_EQUAL(
-      (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen,
-                                                  val.c_str(), val.size()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[8]));
 
   // attwithtokfncommanq
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)9, util::parse_content_disposition(
+                                       dest, destlen, &cs, &cslen, val.c_str(),
+                                       val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("'foo.bar'"),
                        std::string(&dest[0], &dest[9]));
 
@@ -967,9 +978,9 @@ void UtilTest1::testParseContentDisposition1()
   // attachment; filename="foo-ä.html"
   val = "attachment; filename=\"foo-%E4.html\"";
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)10, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"),
                        util::iso8859p1ToUtf8(std::string(&dest[0], &dest[10])));
 
@@ -977,165 +988,165 @@ void UtilTest1::testParseContentDisposition1()
   // attachment; filename="foo-ä.html"
   val = "attachment; filename=\"foo-%C3%A4.html\"";
   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()));
+  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"),
                        util::iso8859p1ToUtf8(std::string(&dest[0], &dest[11])));
 
   // attwithfnrawpctenca
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)12, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("foo-%41.html"),
                        std::string(&dest[0], &dest[12]));
 
   // attwithfnusingpct
   val = "attachment; filename=\"50%.html\"";
-  CPPUNIT_ASSERT_EQUAL(
-      (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen,
-                                                  val.c_str(), val.size()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, util::parse_content_disposition(
+                                       dest, destlen, &cs, &cslen, val.c_str(),
+                                       val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("50%.html"),
                        std::string(&dest[0], &dest[8]));
 
   // attwithfnrawpctencaq
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)12, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("foo-%41.html"),
                        std::string(&dest[0], &dest[12]));
 
   // attwithnamepct
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)0, util::parse_content_disposition(
+                                       dest, destlen, &cs, &cslen, val.c_str(),
+                                       val.size(), false));
 
   // attwithfilenamepctandiso
   // attachment; filename="ä-%41.html"
   val = "attachment; filename=\"%E4-%2541.html\"";
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)10, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("ä-%41.html"),
                        util::iso8859p1ToUtf8(std::string(&dest[0], &dest[10])));
 
   // attwithfnrawpctenclong
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)25, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("foo-%c3%a4-%e2%82%ac.html"),
                        std::string(&dest[0], &dest[25]));
 
   // attwithasciifilenamews1
   val = "attachment; filename =\"foo.html\"";
-  CPPUNIT_ASSERT_EQUAL(
-      (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen,
-                                                  val.c_str(), val.size()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[8]));
 
   // attwith2filenames
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
 }
 
 void UtilTest1::testParseContentDisposition2()
@@ -1149,228 +1160,228 @@ void UtilTest1::testParseContentDisposition2()
   // test cases from http://greenbytes.de/tech/tc2231/
   // attmissingdelim
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)0, util::parse_content_disposition(
+                                       dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)9, 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[9]));
 
   // attabspathwin
   val = "attachment; filename=\"\\\\foo.html\"";
-  CPPUNIT_ASSERT_EQUAL(
-      (ssize_t)9, util::parse_content_disposition(dest, destlen, &cs, &cslen,
-                                                  val.c_str(), val.size()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)9, 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[9]));
 
   // attcdate
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)0, util::parse_content_disposition(
+                                       dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)0, util::parse_content_disposition(
+                                       dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)0, util::parse_content_disposition(
+                                       dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)10, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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])));
 
   // attwithfn2231utf8
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)15, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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]));
 
   // attwithfn2231noc
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)12, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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]));
 
   // attwithfn2231utf8-bad
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  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]));
 
   // attwithfn2231ws3
   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()));
+  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]));
 
   // attwithfn2231quot
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)10, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("A-%41.html"),
                        std::string(&dest[0], &dest[10]));
 
   // attwithfn2231abspathdisguised
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)9, 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[9]));
 
   // attfnboth
   val =
       "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()));
+  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]));
 
   // attfnboth2
   val =
       "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()));
+  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]));
 
   // attfnboth3
   val = "attachment; filename*0*=ISO-8859-15''euro-sign%3d%a4; "
         "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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)15, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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])));
 
   // attnewandfn
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[8]));
 
   // attrfc2047token
   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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)29, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("=?ISO-8859-1?Q?foo-=E4.html?="),
                        std::string(&dest[0], &dest[29]));
 
@@ -1378,108 +1389,122 @@ void UtilTest1::testParseContentDisposition2()
 
   // zero-length filename. token cannot be empty, so this is invalid.
   val = "attachment; filename=";
-  CPPUNIT_ASSERT_EQUAL(
-      (ssize_t)-1, util::parse_content_disposition(dest, destlen, &cs, &cslen,
-                                                   val.c_str(), val.size()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)0, util::parse_content_disposition(
+                                       dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)0, util::parse_content_disposition(
+                                       dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)0, util::parse_content_disposition(
+                                       dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)0, util::parse_content_disposition(
+                                       dest, destlen, &cs, &cslen, 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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)10, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), false));
   CPPUNIT_ASSERT_EQUAL(std::string("konnichiwa"),
                        std::string(&dest[0], &dest[10]));
 
   // lws before and after "="
   val = "attachment; filename = foo.html";
-  CPPUNIT_ASSERT_EQUAL(
-      (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen,
-                                                  val.c_str(), val.size()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[8]));
 
   // lws before and after "=" with quoted-string
   val = "attachment; filename = \"foo.html\"";
-  CPPUNIT_ASSERT_EQUAL(
-      (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen,
-                                                  val.c_str(), val.size()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[8]));
 
   // lws after parm
   val = "attachment; filename=foo.html  ";
-  CPPUNIT_ASSERT_EQUAL(
-      (ssize_t)8, util::parse_content_disposition(dest, destlen, &cs, &cslen,
-                                                  val.c_str(), val.size()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[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()));
+  CPPUNIT_ASSERT_EQUAL((ssize_t)8, 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[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(), true));
+  CPPUNIT_ASSERT_EQUAL(std::string("foo-ä.html"),
+                       std::string(&dest[0], &dest[11]));
+
+  // incomplete utf8 sequence must be rejected
+  val = "attachment; filename=\"foo-\xc3.html\"";
+  CPPUNIT_ASSERT_EQUAL((ssize_t)-1, util::parse_content_disposition(
+                                        dest, destlen, &cs, &cslen, val.c_str(),
+                                        val.size(), true));
 }
 
 } // namespace aria2