Implement new Url class 99/41899/15
authorJoonghyun Cho <jh5.cho@samsung.com>
Fri, 19 Jun 2015 02:36:07 +0000 (11:36 +0900)
committerJoonghyun Cho <jh5.cho@samsung.com>
Mon, 6 Jul 2015 08:05:40 +0000 (17:05 +0900)
Change-Id: I6e2ffeb4d28074a930caba3910ad47b0f7974d16

src/common/CMakeLists.txt
src/common/resource_manager.cc
src/common/url.cc [new file with mode: 0755]
src/common/url.h [new file with mode: 0755]
tests/utc/common/CMakeLists.txt
tests/utc/common/utc_common_url.cc [new file with mode: 0755]
tests/utc/common/utc_common_xxx.cc [deleted file]

index f107499..e7dbeef 100755 (executable)
@@ -46,6 +46,7 @@ SET(TARGET_COMMON_STATIC_SRCS
   ${BASE_SRCDIR}/common/app_control.cc
   ${BASE_SRCDIR}/common/locale_manager.cc
   ${BASE_SRCDIR}/common/app_db.cc
+  ${BASE_SRCDIR}/common/url.cc
 )
 
 INCLUDE_DIRECTORIES(${TARGET_COMMON_STATIC_INCS})
index 935e873..244c884 100755 (executable)
@@ -31,6 +31,7 @@
 #include "common/app_control.h"
 #include "common/application_data.h"
 #include "common/locale_manager.h"
+#include "common/url.h"
 
 using wgt::parse::AppControlInfo;
 
@@ -125,37 +126,6 @@ static std::string InsertPrefixPath(const std::string& start_uri) {
     return std::string(kSchemeTypeFile) + "/" + start_uri;
 }
 
-static void GetURLInfo(const std::string& url,
-                       std::string* scheme,
-                       std::string* domain,
-                       std::string* port) {
-  if (url.empty())
-    return;
-
-  size_t end_of_scheme = url.find_first_of(':');
-  if (end_of_scheme == std::string::npos) {
-    end_of_scheme = -1;
-  } else {
-    *scheme = url.substr(0, end_of_scheme);
-  }
-
-  if (end_of_scheme+1 == url.length())
-    return;
-
-  size_t start_of_domain = url.find_first_not_of('/', end_of_scheme+1);
-  size_t end_of_domain = url.find_first_of('/', start_of_domain);
-  *domain = url.substr(start_of_domain,
-      end_of_domain == std::string::npos ?
-          std::string::npos : end_of_domain - start_of_domain);
-  size_t port_separator = (*domain).find_first_of(':');
-  if (port_separator != std::string::npos) {
-    *port = (*domain).substr(port_separator+1);
-    *domain = (*domain).substr(0, port_separator);
-  } else {
-    *port = "80";
-  }
-}
-
 }  // namespace
 
 ResourceManager::Resource::Resource(const std::string& uri)
@@ -413,33 +383,30 @@ bool ResourceManager::CheckWARP(const std::string& url) {
   bool& result = warp_cache_[url];
   result = true;
 
+  URL url_info(url);
+
   // if didn't have a scheme, it means local resource
-  size_t end_of_scheme = url.find_first_of(':');
-  if (end_of_scheme == std::string::npos) {
+  if (url_info.scheme().empty()) {
     return true;
   }
 
-  std::string scheme;
-  std::string domain;
-  std::string port;
-  GetURLInfo(url, &scheme, &domain, &port);
-
   for (auto& allow : warp->access_map()) {
     if (allow.first == "*") {
       return true;
     } else if (allow.first.empty()) {
       continue;
     }
-    std::string a_scheme, a_domain, a_port;
-    GetURLInfo(allow.first, &a_scheme, &a_domain, &a_port);
+
+    URL allow_url(allow.first);
 
     // should be match the scheme and port
-    if (a_scheme != scheme || a_port != port) {
+    if (allow_url.scheme() != url_info.scheme() ||
+        allow_url.port() != url_info.port()) {
       continue;
     }
 
     // if domain alos was matched, allow resource
-    if (a_domain == domain) {
+    if (allow_url.domain() == url_info.domain()) {
       return true;
     } else if (allow.second) {
       // if does not match domain, should be check sub domain
@@ -447,8 +414,7 @@ bool ResourceManager::CheckWARP(const std::string& url) {
       // filter : test.com , subdomain=true
       // url : aaa.test.com
       // check url was ends with ".test.com"
-      a_domain = "." + a_domain;
-      if (utils::EndsWith(domain, a_domain)) {
+      if (utils::EndsWith(url_info.domain(), "." + allow_url.domain())) {
         return true;
       }
     }
@@ -476,30 +442,24 @@ bool ResourceManager::CheckAllowNavigation(const std::string& url) {
   bool& result = warp_cache_[url];
   result = true;
 
+  URL url_info(url);
+
   // if didn't have a scheme, it means local resource
-  size_t end_of_scheme = url.find_first_of(':');
-  if (end_of_scheme == std::string::npos) {
+  if (url_info.scheme().empty()) {
     return true;
   }
 
-  std::string scheme;
-  std::string domain;
-  std::string port;
-  GetURLInfo(url, &scheme, &domain, &port);
-
   for (auto& allow_domain : allow->GetAllowedDomains()) {
-    std::string a_scheme;
-    std::string a_domain;
-    std::string a_port;
-    GetURLInfo(allow_domain, &a_scheme, &a_domain, &a_port);
+    URL a_domain_info(allow_domain);
 
     // check wildcard *
-    if (a_domain == "*") {
+    if (a_domain_info.domain() == "*") {
       return true;
     }
 
     bool prefix_wild = false;
     bool suffix_wild = false;
+    std::string a_domain = a_domain_info.domain();
     if (utils::StartsWith(a_domain, "*.")) {
       prefix_wild = true;
       // *.domain.com -> .domain.com
@@ -513,25 +473,25 @@ bool ResourceManager::CheckAllowNavigation(const std::string& url) {
 
     if (!prefix_wild && !suffix_wild) {
       // if no wildcard, should be exactly matched
-      if (domain == a_domain) {
+      if (url_info.domain() == a_domain) {
         return true;
       }
     } else if (prefix_wild && !suffix_wild) {
       // *.domain.com : it shoud be "domain.com" or end with ".domain.com"
-      if (domain == a_domain.substr(1) ||
-          utils::EndsWith(domain, a_domain)) {
+      if (url_info.domain() == a_domain.substr(1) ||
+          utils::EndsWith(url_info.domain(), a_domain)) {
         return true;
       }
     } else if (!prefix_wild && suffix_wild) {
       // www.sample.* : it should be starts with "www.sample."
-      if (utils::StartsWith(domain, a_domain)) {
+      if (utils::StartsWith(url_info.domain(), a_domain)) {
         return true;
       }
     } else if (prefix_wild && suffix_wild) {
       // *.sample.* : it should be starts with sample. or can find ".sample."
       // in url
-      if (utils::StartsWith(domain, a_domain.substr(1)) ||
-          std::string::npos != domain.find(a_domain)) {
+      if (utils::StartsWith(url_info.domain(), a_domain.substr(1)) ||
+          std::string::npos != url_info.domain().find(a_domain)) {
         return true;
       }
     }
diff --git a/src/common/url.cc b/src/common/url.cc
new file mode 100755 (executable)
index 0000000..8618987
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include <algorithm>
+#include <stdexcept>
+
+#include "common/url.h"
+
+#include "common/logger.h"
+#include "common/string_utils.h"
+
+namespace wrt {
+
+namespace {
+
+const char* kSchemeTypeApp = "app";
+const char* kSchemeTypeFile = "file";
+const char* kSchemeTypeHttp = "http";
+const char* kSchemeTypeHttps = "https";
+const char* kSchemeTypeSsh = "ssh";
+const char* kSchemeTypeFtp = "ftp";
+// lendth of scheme identifier ://
+const int kSchemeIdLen = 3;
+int kPortHttp = 80;
+int kPortHttps = 443;
+int kPortSsh = 22;
+int kPortFtp = 21;
+int kPortDefault = 0;
+
+int GetDefaultPort(const std::string& scheme) {
+  if (scheme == kSchemeTypeHttp) return kPortHttp;
+  else if (scheme == kSchemeTypeHttps) return kPortHttps;
+  else if (scheme == kSchemeTypeSsh) return kPortSsh;
+  else if (scheme == kSchemeTypeFtp) return kPortFtp;
+  else
+    return kPortDefault;
+}
+
+}  // namespace
+
+class URLImpl {
+ public:
+  explicit URLImpl(const std::string& url);
+  URLImpl() {}
+
+  std::string url() const { return url_; }
+  std::string scheme() const { return scheme_; }
+  std::string domain() const { return domain_; }
+  int port() const { return port_; }
+  std::string path() const { return path_; }
+
+ private:
+  std::string url_;
+  std::string scheme_;
+  std::string domain_;
+  int port_;
+  std::string path_;
+
+  bool ExtractScheme();
+  void ExtractDomain();
+  void ExtractDomainPort();
+  void ExtractPath();
+};
+
+URLImpl::URLImpl(const std::string& url) : port_(0) {
+  if (url.empty())
+    return;
+
+  url_ = url;
+  if (!ExtractScheme()) {
+    ExtractDomain();
+    ExtractPath();
+    return;
+  }
+
+  if (scheme_ != kSchemeTypeFile)
+    ExtractDomainPort();
+
+  ExtractPath();
+}
+
+bool URLImpl::ExtractScheme() {
+  size_t end_of_scheme = 0;
+  if (url_.find("://") != std::string::npos) {
+    end_of_scheme = url_.find("://");
+    std::string scheme = url_.substr(0, end_of_scheme);
+    std::transform(scheme.begin(), scheme.end(), scheme.begin(), ::tolower);
+    scheme_ = scheme;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void URLImpl::ExtractDomain() {
+  size_t start_of_domain = scheme_.empty() ?
+                           0 : scheme_.length() + kSchemeIdLen;
+  size_t end_of_domain = url_.find_first_of('/', start_of_domain);
+  domain_ =
+    url_.substr(start_of_domain, end_of_domain == std::string::npos ?
+                std::string::npos : end_of_domain - start_of_domain);
+}
+
+void URLImpl::ExtractDomainPort() {
+  ExtractDomain();
+  std::string domain = domain_;
+
+  // Decide start position to find port considering IPv6 case
+  size_t start_pos = domain.find('@');
+  start_pos = (start_pos != std::string::npos) ? start_pos + 1 : 0;
+  if (domain[start_pos] == '[')
+    start_pos = domain.find(']', start_pos+1);
+
+  size_t port_separator =
+    domain.find_first_of(':', start_pos != std::string::npos ? start_pos : 0);
+  if (port_separator != std::string::npos) {
+    domain_ = domain.substr(0, port_separator);
+    std::string port = domain.substr(port_separator+1);
+    if (port.empty())
+      port_ = GetDefaultPort(scheme_);
+    else {
+      try {
+        port_ = std::stoi(port);
+      } catch (...) {
+        port_ = GetDefaultPort(scheme_);
+      }
+    }
+  } else {
+    domain_ = domain;
+    port_ = GetDefaultPort(scheme_);
+  }
+}
+
+void URLImpl::ExtractPath() {
+  std::string sub_url = url_.substr(scheme_.empty() ?
+                                    0 : scheme_.length() + kSchemeIdLen);
+  if (domain_.empty()) {
+    path_ = sub_url;
+  } else {
+    size_t start_of_path = sub_url.find_first_of('/');
+    if (start_of_path != std::string::npos)
+      path_ = sub_url.substr(start_of_path);
+  }
+}
+
+URL::URL(const std::string& url) {
+  impl_ = new URLImpl(url);
+}
+
+std::string URL::url() const { return impl_->url(); }
+std::string URL::scheme() const { return impl_->scheme(); }
+std::string URL::domain() const { return impl_->domain(); }
+int URL::port() const { return impl_->port(); }
+std::string URL::path() const { return impl_->path(); }
+
+URL::~URL() {
+  delete impl_;
+}
+
+}  // namespace wrt
diff --git a/src/common/url.h b/src/common/url.h
new file mode 100755 (executable)
index 0000000..ab9b845
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#ifndef WRT_COMMON_URL_H_
+#define WRT_COMMON_URL_H_
+
+#include <string>
+
+namespace wrt {
+
+class URLImpl;
+
+/*
+ * This class parses a given url based on its scheme type.
+ * The parsed data is stored in different variables depending on the scheme
+ * type.
+ * The following shows the variables which are used for each scheme type:
+ * http:// https:// ssh:// ftp://
+ *   => url_, scheme_, domain_, port_, path_
+ * app://
+ *   => url_, scheme_, domain_, path_
+ * file://
+ *   => url_, scheme_, path_
+ * No Scheme Type
+ *   => domain_, path_
+ *
+ * If the url does not have specific data, an empty string will be stored
+ * in the corresponding variables.
+ *
+ * ex) http://user:password@www.google.co.kr:8080/market/Item?12345
+ * url_ = http://user:password@www.google.co.kr:8080/market/Item?12345
+ * scheme_ = http
+ * domain_ = user:password@www.google.co.kr
+ * port_ = 8080
+ * path_ = /market/Item?12345
+*/
+class URL {
+ public:
+  explicit URL(const std::string& url);
+  ~URL();
+
+  std::string url() const;
+  std::string scheme() const;
+  std::string domain() const;
+  int port() const;
+  std::string path() const;
+
+ private:
+  URLImpl* impl_;
+};
+
+}  // namespace wrt
+
+#endif  // WRT_COMMON_URL_H_
index 83e751c..d4ad980 100755 (executable)
@@ -32,7 +32,7 @@ SET(UTC_COMMON_LIBS
 
 # Source Files
 SET(UTC_COMMON_SRCS
-  ${UTC_SRCDIR}/common/utc_common_xxx.cc
+  ${UTC_SRCDIR}/common/utc_common_url.cc
 )
 
 # Compiler Flags
diff --git a/tests/utc/common/utc_common_url.cc b/tests/utc/common/utc_common_url.cc
new file mode 100755 (executable)
index 0000000..3967f2c
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include <limits.h>
+#include "common/url.h"
+#include "gtest/gtest.h"
+#include <string>
+#include <iostream>
+
+namespace wrt {
+
+int GetDefaultPort(const std::string& scheme) {
+ if (scheme == "http")
+   return 80;
+ else if (scheme == "https")
+   return 443;
+ else if (scheme == "ssh")
+   return 22;
+ else if (scheme == "ftp")
+   return 21;
+ else
+   return 0;
+}
+
+void TestExpectEq(const std::string& test_url, const std::string& scheme,
+                 const std::string& domain, int port, const std::string path) {
+  URL url(test_url);
+  EXPECT_EQ(scheme, url.scheme());
+  EXPECT_EQ(port, url.port());
+  EXPECT_EQ(domain, url.domain());
+  EXPECT_EQ(path, url.path());
+}
+
+// Tests URL Class
+
+TEST(SchemeHttpTest, Positive) {
+  // "scheme://domain:port/path"
+  std::string scheme;
+  std::string domain;
+  int port;
+  std::string path;
+  std::string url;
+
+  // normal
+  url = "https://username:password@samsung.com:443/dir1/abc.jpg";
+  scheme = "https";
+  domain = "username:password@samsung.com";
+  port = 443;
+  path = "/dir1/abc.jpg";
+  TestExpectEq(url, scheme, domain, port, path);
+
+  // no port
+  url = "https://username:password@samsung.com/dir1/abc.jpg";
+  scheme = "https";
+  domain = "username:password@samsung.com";
+  port = GetDefaultPort("https");
+  path = "/dir1/abc.jpg";
+  TestExpectEq(url, scheme, domain, port, path);
+
+  // no path
+  url = "https://username:password@samsung.com:443";
+  scheme = "https";
+  domain = "username:password@samsung.com";
+  port = 443;
+  path = "";
+  TestExpectEq(url, scheme, domain, port, path);
+
+  // no path,port
+  url = "https://username:password@samsung.com";
+  scheme = "https";
+  domain = "username:password@samsung.com";
+  port = GetDefaultPort("https");
+  path = "";
+  TestExpectEq(url, scheme, domain, port, path);
+
+  // ugly scheme
+  url = "HtTp://username:password@samsung.com/path";
+  scheme = "http";
+  domain = "username:password@samsung.com";
+  port = GetDefaultPort("http");
+  path = "/path";
+  TestExpectEq(url, scheme, domain, port, path);
+
+  // ugly scheme with no userinfo
+  url = "HtTp://www.samsung.com/path";
+  scheme = "http";
+  domain = "www.samsung.com";
+  port = GetDefaultPort("http");
+  path = "/path";
+  TestExpectEq(url, scheme, domain, port, path);
+
+  // normal with port 8080
+  url = "http://www.naver.com:8080/";
+  scheme = "http";
+  domain = "www.naver.com";
+  port = 8080;
+  path = "/";
+  TestExpectEq(url, scheme, domain, port, path);
+
+  // normal with port 80
+  url = "http://www.naver.com:80/";
+  scheme = "http";
+  domain = "www.naver.com";
+  port = 80;
+  path = "/";
+  TestExpectEq(url, scheme, domain, port, path);
+}
+
+TEST(SchemeHttpTest, Negative) {
+  // "scheme://domain:port/path"
+  std::string scheme;
+  std::string domain;
+  int port = 0;
+  std::string path;
+  std::string url;
+
+  // no url
+  url = "";
+  scheme = "";
+  domain = "";
+  port = 0;
+  path = "";
+  TestExpectEq(url, scheme, domain, port, path);
+
+  // no scheme
+  url = "username:password@samsung.com:80/dir1/path";
+  scheme = "";
+  domain = "username:password@samsung.com:80";
+  port = 0;
+  path = "/dir1/path";
+  TestExpectEq(url, scheme, domain, port, path);
+
+  // no domain
+  url = "https://";
+  scheme = "https";
+  domain = "";
+  port = GetDefaultPort("https");;
+  path = "";
+  TestExpectEq(url, scheme, domain, port, path);
+
+  // invalid port
+  url = "ftp://ftp.wordpress.com:invalid/path";
+  scheme = "ftp";
+  domain = "ftp.wordpress.com";
+  port = GetDefaultPort("ftp");;
+  path = "/path";
+  TestExpectEq(url, scheme, domain, port, path);
+}
+
+TEST(SchemeAppTest, Positive) {
+  std::string scheme;
+  std::string domain;
+  int port = 0;
+  std::string path;
+  std::string url;
+
+  //app://appid
+  url = "app://appid";
+  scheme = "app";
+  domain = "appid";
+  path = "";
+  TestExpectEq(url, scheme, domain, port, path);
+
+  //app://appid/path
+  url = "app://appid/path/path2";
+  scheme = "app";
+  domain = "appid";
+  path = "/path/path2";
+  TestExpectEq(url, scheme, domain, port, path);
+}
+
+TEST(SchemeFileTest, Positive) {
+  std::string url;
+  std::string scheme;
+  std::string domain;
+  int port = 0;
+  std::string path;
+
+  // normal file scheme
+  url = "file://file/scheme/path";
+  scheme = "file";
+  path = "file/scheme/path";
+  TestExpectEq(url, scheme, domain, port, path);
+
+  // ugly file scheme
+  url = "fiLE://///path/";
+  scheme = "file";
+  path = "///path/";
+  TestExpectEq(url, scheme, domain, port, path);
+}
+
+}  // namespace wrt
diff --git a/tests/utc/common/utc_common_xxx.cc b/tests/utc/common/utc_common_xxx.cc
deleted file mode 100755 (executable)
index 0d8454b..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-#include <limits.h>
-#include "gtest/gtest.h"
-
-namespace wrt {
-
-TEST(Test1, Positive) {
-}
-
-TEST(Test1, Negative) {
-}
-
-}  // namespace wrt