Przeglądaj źródła

Support PREF_DIR change for Metalink files

Reworked previous commit adeead6f0396e2f8551d1182972e277728fd6c8b, and
now support changing PREF_DIR for Metalink downloads.
Tatsuhiro Tsujikawa 11 lat temu
rodzic
commit
4f3c526dcd

+ 5 - 0
src/FileEntry.cc

@@ -572,6 +572,11 @@ void FileEntry::setOriginalName(std::string originalName)
   originalName_ = std::move(originalName);
 }
 
+void FileEntry::setSuffixPath(std::string suffixPath)
+{
+  suffixPath_ = std::move(suffixPath);
+}
+
 bool FileEntry::emptyRequestUri() const
 {
   return uris_.empty() && inFlightRequests_.empty() && requestPool_.empty();

+ 10 - 0
src/FileEntry.h

@@ -85,6 +85,9 @@ private:
   std::string path_;
   std::string contentType_;
   std::string originalName_;
+  // path_ without parent directory component.  This is primarily used
+  // to change directory (PREF_DIR option).
+  std::string suffixPath_;
 
   Timer lastFasterReplace_;
   int maxConnectionPerServer_;
@@ -264,6 +267,13 @@ public:
     return originalName_;
   }
 
+  void setSuffixPath(std::string suffixPath);
+
+  const std::string& getSuffixPath() const
+  {
+    return suffixPath_;
+  }
+
   bool removeUri(const std::string& uri);
 
   bool emptyRequestUri() const;

+ 6 - 4
src/FtpNegotiationCommand.cc

@@ -361,11 +361,13 @@ bool FtpNegotiationCommand::onFileSizeDetermined(int64_t totalLength)
 {
   getFileEntry()->setLength(totalLength);
   if(getFileEntry()->getPath().empty()) {
+    auto suffixPath = util::createSafePath
+      (util::percentDecode(std::begin(getRequest()->getFile()),
+                           std::end(getRequest()->getFile())));
+
     getFileEntry()->setPath
-      (util::createSafePath
-       (getOption()->get(PREF_DIR),
-        util::percentDecode(getRequest()->getFile().begin(),
-                            getRequest()->getFile().end())));
+      (util::applyDir(getOption()->get(PREF_DIR), suffixPath));
+    getFileEntry()->setSuffixPath(suffixPath);
   }
   getRequestGroup()->preDownloadProcessing();
   if(totalLength == 0) {

+ 5 - 2
src/HttpResponseCommand.cc

@@ -249,8 +249,11 @@ bool HttpResponseCommand::executeInternal()
     int64_t totalLength = httpResponse->getEntityLength();
     fe->setLength(totalLength);
     if (fe->getPath().empty()) {
-      fe->setPath(util::createSafePath(getOption()->get(PREF_DIR),
-                                       httpResponse->determineFilename()));
+      auto suffixPath =
+        util::createSafePath(httpResponse->determineFilename());
+
+      fe->setPath(util::applyDir(getOption()->get(PREF_DIR), suffixPath));
+      fe->setSuffixPath(suffixPath);
     }
     fe->setContentType(httpResponse->getContentType());
     grp->preDownloadProcessing();

+ 3 - 0
src/Metalink2RequestGroup.cc

@@ -265,6 +265,8 @@ Metalink2RequestGroup::createRequestGroup
                         entry->file->getPath()));
       dctx->getFirstFileEntry()->setUris(uris);
       dctx->getFirstFileEntry()->setMaxConnectionPerServer(maxConn);
+      dctx->getFirstFileEntry()->setSuffixPath(entry->file->getPath());
+
       if(option->getAsBool(PREF_METALINK_ENABLE_UNIQUE_PROTOCOL)) {
         dctx->getFirstFileEntry()->setUniqueProtocol(true);
       }
@@ -307,6 +309,7 @@ Metalink2RequestGroup::createRequestGroup
           fe->setUniqueProtocol(true);
         }
         fe->setOriginalName(entry->metaurls[0]->name);
+        fe->setSuffixPath(entry->file->getPath());
         fileEntries.push_back(fe);
         if(offset >
            std::numeric_limits<int64_t>::max() - entry->file->getLength()) {

+ 23 - 10
src/RpcMethodImpl.cc

@@ -1473,22 +1473,35 @@ void changeOption
     }
   }
   if(option.defined(PREF_DIR) || option.defined(PREF_OUT)) {
-    if(dctx->getFileEntries().size() == 1
-#ifdef ENABLE_BITTORRENT
-       && !dctx->hasAttribute(CTX_ATTR_BT)
-#endif // ENABLE_BITTORRENT
-       ) {
+    if(!group->getMetadataInfo()) {
+
+      assert(dctx->getFileEntries().size() == 1);
 
       auto& fileEntry = dctx->getFirstFileEntry();
 
-      if(grOption->blank(PREF_OUT)) {
-        // We need to reset length to 0, so that we pretend that file
-        // name is unknown and it should be determined at next run.
-        fileEntry->setLength(0);
+      if(!grOption->blank(PREF_OUT)) {
+        fileEntry->setPath
+          (util::applyDir(grOption->get(PREF_DIR), grOption->get(PREF_OUT)));
+        fileEntry->setSuffixPath(A2STR::NIL);
+      } else if(fileEntry->getSuffixPath().empty()) {
         fileEntry->setPath(A2STR::NIL);
       } else {
         fileEntry->setPath
-          (util::applyDir(grOption->get(PREF_DIR), grOption->get(PREF_OUT)));
+          (util::applyDir(grOption->get(PREF_DIR),
+                          fileEntry->getSuffixPath()));
+      }
+    } else if(group->getMetadataInfo()
+#ifdef ENABLE_BITTORRENT
+              && !dctx->hasAttribute(CTX_ATTR_BT)
+#endif // ENABLE_BITTORRENT
+              ) {
+      // In case of Metalink
+      for(auto& fileEntry : dctx->getFileEntries()) {
+        // PREF_OUT is not applicable to Metalink.  We have always
+        // suffixPath set.
+        fileEntry->setPath
+          (util::applyDir(grOption->get(PREF_DIR),
+                          fileEntry->getSuffixPath()));
       }
     }
   }

+ 16 - 8
src/bittorrent_helper.cc

@@ -278,11 +278,15 @@ void extractFileEntries
                              (util::percentEncode)));
       std::vector<std::string> uris;
       createUri(urlList.begin(), urlList.end(),std::back_inserter(uris),pePath);
-      std::shared_ptr<FileEntry> fileEntry
-        (new FileEntry(util::applyDir(option->get(PREF_DIR),
-                                      util::escapePath(utf8Path)),
-                       fileLengthData->i(), offset, uris));
+
+      auto suffixPath = util::escapePath(utf8Path);
+
+      auto fileEntry =
+        std::make_shared<FileEntry>(util::applyDir(option->get(PREF_DIR),
+                                                   suffixPath),
+                                    fileLengthData->i(), offset, uris);
       fileEntry->setOriginalName(utf8Path);
+      fileEntry->setSuffixPath(suffixPath);
       fileEntry->setMaxConnectionPerServer(maxConn);
       fileEntries.push_back(fileEntry);
       offset += fileEntry->getLength();
@@ -316,11 +320,15 @@ void extractFileEntries
         uris.push_back(elem);
       }
     }
-    std::shared_ptr<FileEntry> fileEntry
-      (new FileEntry(util::applyDir(option->get(PREF_DIR),
-                                    util::escapePath(utf8Name)),
-                     totalLength, 0, uris));
+
+    auto suffixPath = util::escapePath(utf8Name);
+
+    auto fileEntry =
+      std::make_shared<FileEntry>(util::applyDir(option->get(PREF_DIR),
+                                                 suffixPath),
+                                  totalLength, 0, uris);
     fileEntry->setOriginalName(utf8Name);
+    fileEntry->setSuffixPath(suffixPath);
     fileEntry->setMaxConnectionPerServer(maxConn);
     fileEntries.push_back(fileEntry);
   }

+ 7 - 0
src/util.cc

@@ -1878,6 +1878,13 @@ std::string createSafePath
                         );
 }
 
+std::string createSafePath(const std::string& filename)
+{
+  return util::isUtf8(filename) ?
+    util::fixTaintedBasename(filename) :
+    util::escapePath(util::percentEncode(filename));
+}
+
 std::string encodeNonUtf8(const std::string& s)
 {
   return util::isUtf8(s)?s:util::percentEncode(s);

+ 2 - 0
src/util.h

@@ -791,6 +791,8 @@ void executeHookByOptName
 
 std::string createSafePath(const std::string& dir, const std::string& filename);
 
+std::string createSafePath(const std::string& filename);
+
 std::string encodeNonUtf8(const std::string& s);
 
 // Create string safely. If str is NULL, returns empty string.

+ 8 - 0
test/BittorrentHelperTest.cc

@@ -198,6 +198,8 @@ void BittorrentHelperTest::testGetFileEntriesSingle() {
                        fileEntry1->getPath());
   CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.8.2.tar.bz2"),
                        fileEntry1->getOriginalName());
+  CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.8.2.tar.bz2"),
+                       fileEntry1->getSuffixPath());
   CPPUNIT_ASSERT_EQUAL(10, fileEntry1->getMaxConnectionPerServer());
 }
 
@@ -355,6 +357,8 @@ void BittorrentHelperTest::testGetFileEntries_multiFileUrlList() {
   const std::shared_ptr<FileEntry>& fileEntry1 = *itr;
   CPPUNIT_ASSERT_EQUAL(std::string("./aria2-test@/aria2@/src@/aria2c@"),
                        fileEntry1->getPath());
+  CPPUNIT_ASSERT_EQUAL(std::string("aria2-test@/aria2@/src@/aria2c@"),
+                       fileEntry1->getSuffixPath());
   const std::deque<std::string>& uris1 = fileEntry1->getRemainingUris();
   CPPUNIT_ASSERT_EQUAL((size_t)2, uris1.size());
   CPPUNIT_ASSERT_EQUAL(std::string("http://localhost/dist/aria2-test%40/aria2%40/src%40/aria2c%40"),
@@ -434,6 +438,9 @@ void BittorrentHelperTest::testLoadFromMemory_multiFileNonUtf8Path()
   CPPUNIT_ASSERT_EQUAL
     (std::string("./%1B%24B%25O%25m%21%3C%1B%28B/path/%90%A2%8AE"),
      fe->getPath());
+  CPPUNIT_ASSERT_EQUAL
+    (std::string("%1B%24B%25O%25m%21%3C%1B%28B/path/%90%A2%8AE"),
+     fe->getSuffixPath());
   CPPUNIT_ASSERT_EQUAL
     (std::string("./%1B%24B%25O%25m%21%3C%1B%28B"), dctx->getBasePath());
 }
@@ -452,6 +459,7 @@ void BittorrentHelperTest::testLoadFromMemory_singleFileNonUtf8Path()
 
   const std::shared_ptr<FileEntry>& fe = dctx->getFirstFileEntry();
   CPPUNIT_ASSERT_EQUAL(std::string("./%90%A2%8AE"), fe->getPath());
+  CPPUNIT_ASSERT_EQUAL(std::string("%90%A2%8AE"), fe->getSuffixPath());
 }
 
 void BittorrentHelperTest::testLoadFromMemory()

+ 2 - 0
test/Metalink2RequestGroupTest.cc

@@ -163,6 +163,8 @@ void Metalink2RequestGroupTest::testGenerate_groupByMetaurl()
     CPPUNIT_ASSERT_EQUAL((size_t)2, fileEntries.size());
     CPPUNIT_ASSERT_EQUAL(std::string("./file1"), fileEntries[0]->getPath());
     CPPUNIT_ASSERT_EQUAL(std::string("file1"), fileEntries[0]->getOriginalName());
+    CPPUNIT_ASSERT_EQUAL(std::string("file1"),
+                         fileEntries[0]->getSuffixPath());
     CPPUNIT_ASSERT_EQUAL((size_t)1, fileEntries[0]->getRemainingUris().size());
     CPPUNIT_ASSERT_EQUAL(std::string("http://file1p1"),
                          fileEntries[0]->getRemainingUris()[0]);