merge with master
[platform/framework/web/wrt-commons.git] / modules / utils / src / warp_iri.cpp
1 /*
2  * Copyright (c) 2011 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  * This file  have been implemented in compliance with  W3C WARP SPEC.
18  * but there are some patent issue between  W3C WARP SPEC and APPLE.
19  * so if you want to use this file, refer to the README file in root directory
20  */
21 #include <stddef.h>
22 #include <list>
23 #include <set>
24 #include <string>
25 #include <dpl/utils/warp_iri.h>
26 #include <dpl/string.h>
27 #include <dpl/auto_ptr.h>
28 #include <dpl/foreach.h>
29 #include <idna.h>
30 #include <istream>
31 #include <iri.h>
32 //#include <ValidatorCommon.h>
33
34 namespace {
35 // All schemes which are supported by external application should be ignored
36 // by WARP engine.
37 //
38 // Warp specification require from iri to have host element. File protocol
39 // does not contain host element so it's always denied by warp.
40 // Unfortunatly all widgets are using file protocol to load its data from
41 // hard drive. What's why we cannot check any iri with file schema.
42
43 const char *IRI_IGNORED_SCHEME[] = { "file://", "widget://", "app://", "tel:",
44                                      "sms:", "mmsto:", "mailto:", "data:", "blob:",
45                                      0 };
46
47 const DPL::String SCHEMA_HTTP = DPL::FromUTF8String("http");
48 const DPL::String SCHEMA_HTTPS = DPL::FromUTF8String("https");
49 const DPL::String SCHEMA_FTP = DPL::FromUTF8String("ftp");
50 } // namespace anonymous
51
52 // This will create AutoPtr deleter for iri_struct.
53 // Deleter must be in the same namespace as definition of AutoPtr.
54
55 namespace DPL {
56 DECLARE_DELETER(iri_struct, iri_destroy)
57 } // namespace DPL
58
59 WarpIRI::WarpIRI() :
60     m_domain(false),
61     m_port(UNKNOWN_PORT),
62     m_isAccessDefinition(false),
63     m_isIRIValid(false)
64 {}
65
66 void WarpIRI::set(const char *p_iri,
67                   bool domain)
68 {
69     if (!p_iri) {
70         m_isAccessDefinition = m_isIRIValid = false;
71         return;
72     }
73
74     m_domain = domain;
75     m_isAccessDefinition = true;
76     m_isIRIValid = true;
77     m_host.clear();
78
79     if (strcmp(p_iri, "*") == 0) {
80         return;
81     }
82
83     DPL::AutoPtr<iri_struct> iri(iri_parse(p_iri));
84
85     if (!iri.get()) {
86         LogError("Error in iri_parse!");
87         m_isIRIValid = false;
88         m_isAccessDefinition = false;
89         return;
90     }
91
92     if (iri->scheme == NULL || iri->host == NULL) {
93         m_isIRIValid = false;
94         m_isAccessDefinition = false;
95         return;
96     }
97
98     // all of this must be NULL in WARP definition
99     if (iri->user || iri->path || iri->query || iri->anchor) {
100         m_isAccessDefinition = false;
101     }
102
103     m_schema = DPL::FromASCIIString(std::string(iri->scheme));
104     m_port = static_cast<unsigned int>(iri->port);
105
106     if (m_port == 0) {
107         m_port = getPort(m_schema);
108         if (m_port == UNKNOWN_PORT) {
109             m_isAccessDefinition = false;
110             return;
111         }
112     }
113
114     DPL::String str = DPL::FromASCIIString(std::string(iri->host));
115
116     std::string utf8host = iri->host;
117     std::list<std::string> hostTokenList;
118     DPL::Tokenize(utf8host, ".", std::front_inserter(hostTokenList));
119
120     if (SCHEMA_HTTP == m_schema || SCHEMA_HTTPS == m_schema) {
121         FOREACH(i, hostTokenList) {
122             char *output = NULL;
123             int rc = idna_to_ascii_8z(i->c_str(),
124                                       &output,
125                                       IDNA_USE_STD3_ASCII_RULES);
126
127             if (IDNA_SUCCESS != rc) {
128                 LogWarning("libidn error: " << rc << " " <<
129                            idna_strerror((Idna_rc)rc));
130                 m_isIRIValid = false;
131                 m_isAccessDefinition = false;
132             } else {
133                 std::string token(output);
134                 std::transform(token.begin(),
135                                token.end(),
136                                token.begin(),
137                                    ::tolower);
138                 m_host.push_back(DPL::FromUTF8String(token));
139             }
140             free(output);
141         }
142     } else {
143         FOREACH(i, hostTokenList){
144             m_host.push_back(DPL::FromUTF8String(*i));
145         }
146     }
147 }
148
149 void WarpIRI::set(const DPL::String &iristring,
150                   bool domain)
151 {
152     set(DPL::ToUTF8String(iristring).c_str(), domain);
153 }
154
155 unsigned int WarpIRI::getPort(const DPL::String &schema) const
156 {
157     unsigned int port = UNKNOWN_PORT;
158     if (schema == SCHEMA_HTTP) {
159         port = 80;
160     } else if (schema == SCHEMA_HTTPS) {
161         port = 443;
162     } else if (schema == SCHEMA_FTP) {
163         port = 21;
164     }
165     return port;
166 }
167
168 bool WarpIRI::isSubDomain(const WarpIRI &second) const
169 {
170     if (!m_isAccessDefinition || !second.m_isIRIValid) {
171         return false;
172     }
173     if (m_schema != second.m_schema) {
174         return false;
175     }
176     if (m_port != second.m_port) {
177         return false;
178     }
179
180     size_t size = m_host.size() < second.m_host.size() ?
181         m_host.size() : second.m_host.size();
182
183     if (m_host.size() > second.m_host.size()) {
184         return false;
185     }
186
187     if (!m_domain && (m_host.size() != second.m_host.size())) {
188         return false;
189     }
190
191     for (size_t i = 0; i < size; ++i) {
192         if (DPL::StringCompare(m_host[i], second.m_host[i])) {
193             return false;
194         }
195     }
196     return true;
197 }
198
199 bool WarpIRI::isAccessDefinition() const
200 {
201     return m_isAccessDefinition;
202 }
203
204 bool WarpIRI::getSubDomain() const
205 {
206     return m_domain;
207 }
208
209 bool WarpIRI::isIRISchemaIgnored(const char *iri)
210 {
211     for (int i = 0; IRI_IGNORED_SCHEME[i]; ++i) {
212         if (0 ==
213             strncmp(iri, IRI_IGNORED_SCHEME[i],
214                     strlen(IRI_IGNORED_SCHEME[i])))
215         {
216             return true;
217         }
218     }
219     return false;
220 }