Specifiy that this supports M47
[platform/framework/web/crosswalk-tizen.git] / common / url.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include "common/url.h"
18
19 #include <algorithm>
20 #include <stdexcept>
21
22 #include "common/logger.h"
23 #include "common/string_utils.h"
24
25 namespace common {
26
27 namespace {
28
29 const char* kSchemeTypeFile = "file";
30 const char* kSchemeTypeHttp = "http";
31 const char* kSchemeTypeHttps = "https";
32 const char* kSchemeTypeSsh = "ssh";
33 const char* kSchemeTypeFtp = "ftp";
34
35 // length of scheme identifier ://
36 const int kSchemeIdLen = 3;
37 int kPortHttp = 80;
38 int kPortHttps = 443;
39 int kPortSsh = 22;
40 int kPortFtp = 21;
41 int kPortDefault = 0;
42
43 int GetDefaultPort(const std::string& scheme) {
44   if (scheme == kSchemeTypeHttp) return kPortHttp;
45   else if (scheme == kSchemeTypeHttps) return kPortHttps;
46   else if (scheme == kSchemeTypeSsh) return kPortSsh;
47   else if (scheme == kSchemeTypeFtp) return kPortFtp;
48   else
49     return kPortDefault;
50 }
51
52 }  // namespace
53
54 class URLImpl {
55  public:
56   explicit URLImpl(const std::string& url);
57   URLImpl() {}
58
59   std::string url() const { return url_; }
60   std::string scheme() const { return scheme_; }
61   std::string domain() const { return domain_; }
62   int port() const { return port_; }
63   std::string path() const { return path_; }
64
65  private:
66   std::string url_;
67   std::string scheme_;
68   std::string domain_;
69   int port_;
70   std::string path_;
71
72   bool ExtractScheme();
73   void ExtractDomain();
74   void ExtractDomainPort();
75   void ExtractPath();
76 };
77
78 URLImpl::URLImpl(const std::string& url) : port_(0) {
79   if (url.empty())
80     return;
81
82   url_ = url;
83   if (!ExtractScheme()) {
84     ExtractDomain();
85     ExtractPath();
86     return;
87   }
88
89   if (scheme_ != kSchemeTypeFile)
90     ExtractDomainPort();
91
92   ExtractPath();
93 }
94
95 bool URLImpl::ExtractScheme() {
96   size_t end_of_scheme = 0;
97   if (url_.find("://") != std::string::npos) {
98     end_of_scheme = url_.find("://");
99     std::string scheme = url_.substr(0, end_of_scheme);
100     std::transform(scheme.begin(), scheme.end(), scheme.begin(), ::tolower);
101     scheme_ = scheme;
102     return true;
103   } else {
104     return false;
105   }
106 }
107
108 void URLImpl::ExtractDomain() {
109   size_t start_of_domain = scheme_.empty() ?
110                            0 : scheme_.length() + kSchemeIdLen;
111   size_t end_of_domain = url_.find_first_of('/', start_of_domain);
112   size_t at = url_.find_first_of('@', start_of_domain);
113   if (at < end_of_domain) {
114     start_of_domain = at + 1;
115   }
116   domain_ =
117     url_.substr(start_of_domain, end_of_domain == std::string::npos ?
118                 std::string::npos : end_of_domain - start_of_domain);
119   LOGGER(INFO) << "Extract Domain is " << domain_;
120 }
121
122 void URLImpl::ExtractDomainPort() {
123   ExtractDomain();
124   std::string domain = domain_;
125
126   // Decide start position to find port considering IPv6 case
127   size_t start_pos = domain.find('@');
128   start_pos = (start_pos != std::string::npos) ? start_pos + 1 : 0;
129   if (domain[start_pos] == '[')
130     start_pos = domain.find(']', start_pos+1);
131
132   size_t port_separator =
133     domain.find_first_of(':', start_pos != std::string::npos ? start_pos : 0);
134   if (port_separator != std::string::npos) {
135     domain_ = domain.substr(0, port_separator);
136     std::string port = domain.substr(port_separator+1);
137     if (port.empty()) {
138       port_ = GetDefaultPort(scheme_);
139     } else {
140       try {
141         port_ = std::stoi(port);
142       } catch (...) {
143         port_ = GetDefaultPort(scheme_);
144       }
145     }
146   } else {
147     domain_ = domain;
148     port_ = GetDefaultPort(scheme_);
149   }
150 }
151
152 void URLImpl::ExtractPath() {
153   std::string sub_url = url_.substr(scheme_.empty() ?
154                                     0 : scheme_.length() + kSchemeIdLen);
155   if (domain_.empty()) {
156     path_ = sub_url;
157   } else {
158     size_t start_of_path = sub_url.find_first_of('/');
159     if (start_of_path != std::string::npos)
160       path_ = sub_url.substr(start_of_path);
161   }
162 }
163
164 URL::URL(const std::string& url) {
165   impl_ = new URLImpl(url);
166 }
167
168 std::string URL::url() const { return impl_->url(); }
169 std::string URL::scheme() const { return impl_->scheme(); }
170 std::string URL::domain() const { return impl_->domain(); }
171 int URL::port() const { return impl_->port(); }
172 std::string URL::path() const { return impl_->path(); }
173
174 URL::~URL() {
175   delete impl_;
176 }
177
178 }  // namespace common