Procházet zdrojové kódy

Handle "..", "." in util::joinUri()

Tatsuhiro Tsujikawa před 14 roky
rodič
revize
1122e55a35
2 změnil soubory, kde provedl 52 přidání a 8 odebrání
  1. 25 8
      src/util.cc
  2. 27 0
      test/UtilTest.cc

+ 25 - 8
src/util.cc

@@ -1594,18 +1594,35 @@ std::string joinUri(const std::string& baseUri, const std::string& uri)
     if(!uri::parse(bus, baseUri)) {
       return uri;
     }
-    if(util::startsWith(uri, "/")) {
-      bus.dir.clear();
+    std::vector<std::string> parts;
+    if(!util::startsWith(uri, "/")) {
+      util::split(bus.dir, std::back_inserter(parts), "/");
     }
+    std::string::const_iterator qend;
+    for(qend = uri.begin(); qend != uri.end(); ++qend) {
+      if(*qend == '#') {
+        break;
+      }
+    }
+    std::string::const_iterator end;
+    for(end = uri.begin(); end != qend; ++end) {
+      if(*end == '?') {
+        break;
+      }
+    }
+    std::string path(uri.begin(), end);
+    util::split(path, std::back_inserter(parts), "/");
+    bus.dir.clear();
     bus.file.clear();
     bus.query.clear();
-    std::string newUri = construct(bus);
-    if(util::startsWith(uri, "/")) {
-      newUri += uri.substr(1);
-    } else {
-      newUri += uri;
+    std::string res = uri::construct(bus);
+    res += util::joinPath(parts.begin(), parts.end());
+    if((path.empty() || util::endsWith(path, "/")) &&
+       !util::endsWith(res, "/")) {
+      res += "/";
     }
-    return newUri;
+    res += std::string(end, qend);
+    return res;
   }
 }
 

+ 27 - 0
test/UtilTest.cc

@@ -1268,6 +1268,33 @@ void UtilTest::testJoinUri()
                                      "dir/file?q=k"));
   CPPUNIT_ASSERT_EQUAL(std::string("dir/file"),
                        util::joinUri("baduri", "dir/file"));
+  CPPUNIT_ASSERT_EQUAL(std::string("http://base/a/b/d/file"),
+                       util::joinUri("http://base/a/b/c/x",
+                                     "../d/file"));
+  CPPUNIT_ASSERT_EQUAL(std::string("http://base/a/b/file"),
+                       util::joinUri("http://base/c/x",
+                                     "../../a/b/file"));
+  CPPUNIT_ASSERT_EQUAL(std::string("http://base/"),
+                       util::joinUri("http://base/c/x",
+                                     "../.."));
+  CPPUNIT_ASSERT_EQUAL(std::string("http://base/"),
+                       util::joinUri("http://base/c/x",
+                                     ".."));
+  CPPUNIT_ASSERT_EQUAL(std::string("http://base/a/file"),
+                       util::joinUri("http://base/b/c/x",
+                                     "/a/x/../file"));
+  CPPUNIT_ASSERT_EQUAL(std::string("http://base/file"),
+                       util::joinUri("http://base/f/?q=k",
+                                     "/file"));
+  CPPUNIT_ASSERT_EQUAL(std::string("http://base/file?q=/"),
+                       util::joinUri("http://base/",
+                                     "/file?q=/"));
+  CPPUNIT_ASSERT_EQUAL(std::string("http://base/file?q=v"),
+                       util::joinUri("http://base/",
+                                     "/file?q=v#a?q=x"));
+  CPPUNIT_ASSERT_EQUAL(std::string("http://base/file"),
+                       util::joinUri("http://base/",
+                                     "/file#a?q=x"));
 }
 
 } // namespace aria2