Integrate most of GoogleURL in WTFURL
[WebKit-https.git] / Source / WTF / wtf / url / api / ParsedURL.cpp
1 /*
2  * Copyright (C) 2010 Google, Inc. All Rights Reserved.
3  * Copyright (C) 2012 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "ParsedURL.h"
29
30 #if USE(WTFURL)
31
32 #include <wtf/DataLog.h>
33 #include <wtf/MemoryInstrumentation.h>
34 #include <wtf/RawURLBuffer.h>
35 #include <wtf/URLComponent.h>
36 #include <wtf/URLUtil.h>
37 #include <wtf/text/CString.h>
38
39 namespace WTF {
40
41 ParsedURL::ParsedURL(const String& urlString)
42 {
43     unsigned urlStringLength = urlString.length();
44     if (!urlStringLength)
45         return; // FIXME: we should ASSERT on this, but people use KURL incorrectly with ParsedURLStringTag :(.
46
47     RawURLBuffer<char> outputBuffer;
48     String base;
49     const CString& baseStr = base.utf8();
50     bool isValid = false;
51     URLSegments baseSegments;
52
53     // FIXME: we should take shortcuts here! We do not have to resolve the relative part.
54     if (urlString.is8Bit())
55         isValid = URLUtilities::resolveRelative(baseStr.data(), baseSegments,
56                                                 reinterpret_cast<const char*>(urlString.characters8()), urlStringLength,
57                                                 /* charsetConverter */ 0,
58                                                 outputBuffer, &m_segments);
59     else
60         isValid = URLUtilities::resolveRelative(baseStr.data(), baseSegments,
61                                                 urlString.characters16(), urlStringLength,
62                                                 /* charsetConverter */ 0,
63                                                 outputBuffer, &m_segments);
64
65     // FIXME: we should ASSERT on isValid, but people use KURL incorrectly with ParsedURLStringTag :(.
66     if (isValid)
67         m_spec = URLString(String(outputBuffer.data(), outputBuffer.length()));
68 }
69
70 ParsedURL::ParsedURL(const ParsedURL& base, const String& relative)
71 {
72     if (!base.isValid())
73         return;
74
75     unsigned relativeLength = relative.length();
76     if (!relativeLength) {
77         *this = base.withoutFragment();
78         return;
79     }
80
81     RawURLBuffer<char> outputBuffer;
82     const CString& baseStr = base.m_spec.m_string.utf8();
83     bool isValid = false;
84
85     if (relative.is8Bit())
86         isValid = URLUtilities::resolveRelative(baseStr.data(), base.m_segments,
87                                                 reinterpret_cast<const char*>(relative.characters8()), relativeLength,
88                                                 /* charsetConverter */ 0,
89                                                 outputBuffer, &m_segments);
90     else
91         isValid = URLUtilities::resolveRelative(baseStr.data(), base.m_segments,
92                                                 relative.characters16(), relativeLength,
93                                                 /* charsetConverter */ 0,
94                                                 outputBuffer, &m_segments);
95
96     if (isValid)
97         m_spec = URLString(String(outputBuffer.data(), outputBuffer.length()));
98 }
99
100 ParsedURL ParsedURL::isolatedCopy() const
101 {
102     ParsedURL copy;
103     copy.m_segments = this->m_segments;
104     copy.m_spec = URLString(this->m_spec.string().isolatedCopy());
105     return copy;
106 }
107
108 String ParsedURL::scheme() const
109 {
110     return segment(m_segments.scheme);
111 }
112
113 String ParsedURL::username() const
114 {
115     return segment(m_segments.username);
116 }
117
118 String ParsedURL::password() const
119 {
120     return segment(m_segments.password);
121 }
122
123 String ParsedURL::host() const
124 {
125     return segment(m_segments.host);
126 }
127
128 String ParsedURL::port() const
129 {
130     return segment(m_segments.port);
131 }
132
133 String ParsedURL::path() const
134 {
135     return segment(m_segments.path);
136 }
137
138 String ParsedURL::query() const
139 {
140     return segment(m_segments.query);
141 }
142
143 bool ParsedURL::hasFragment() const
144 {
145     return m_segments.fragment.isValid();
146 }
147
148 String ParsedURL::fragment() const
149 {
150     return segment(m_segments.fragment);
151 }
152
153 ParsedURL ParsedURL::withoutFragment() const
154 {
155     if (!hasFragment())
156         return *this;
157
158     ParsedURL newURL;
159
160     int charactersBeforeFragemnt = m_segments.charactersBefore(URLSegments::Fragment, URLSegments::DelimiterExcluded);
161     newURL.m_spec = URLString(m_spec.string().substringSharingImpl(0, charactersBeforeFragemnt));
162
163     newURL.m_segments = m_segments;
164     newURL.m_segments.fragment = URLComponent();
165     return newURL;
166 }
167
168 String ParsedURL::baseAsString() const
169 {
170     // FIXME: Add WTFURL Implementation.
171     return String();
172 }
173
174 String ParsedURL::segment(const URLComponent& component) const
175 {
176     ASSERT(isValid());
177
178     if (!component.isValid())
179         return String();
180
181     String segment = m_spec.string().substring(component.begin(), component.length());
182
183     // FIXME: GoogleURL create empty segments. This happen for the fragment for the test fast/url/segments.html
184     // ASSERT_WITH_MESSAGE(!segment.isEmpty(), "A valid URL component should not be empty.");
185     return segment;
186 }
187
188 void ParsedURL::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
189 {
190     MemoryClassInfo info(memoryObjectInfo, this);
191     info.addMember(m_spec);
192 }
193
194 #ifndef NDEBUG
195
196 #define SHOW_COMPONENT(parsedURL, componentName) \
197     if (!parsedURL->componentName().isNull()) { \
198         dataLog("    " #componentName " = "); \
199         parsedURL->componentName().show(); \
200     }
201
202 void ParsedURL::print() const
203 {
204     if (!isValid()) {
205         dataLog("Invalid ParsedURL.\n");
206         return;
207     }
208
209     dataLog("Valid ParsedURL with:\n");
210     dataLog("    m_spec = ");
211     m_spec.print();
212
213     SHOW_COMPONENT(this, scheme);
214     SHOW_COMPONENT(this, username);
215     SHOW_COMPONENT(this, password);
216     SHOW_COMPONENT(this, host);
217     SHOW_COMPONENT(this, port);
218     SHOW_COMPONENT(this, path);
219     SHOW_COMPONENT(this, query);
220     SHOW_COMPONENT(this, fragment);
221 }
222 #endif
223
224 }
225
226 #endif // USE(WTFURL)