Move URL from WebCore to WTF
[WebKit-https.git] / Source / WebCore / html / URLSearchParams.cpp
1 /*
2  * Copyright (C) 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
20  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26 #include "URLSearchParams.h"
27
28 #include "DOMURL.h"
29 #include <wtf/URLParser.h>
30
31 namespace WebCore {
32
33 URLSearchParams::URLSearchParams(const String& init, DOMURL* associatedURL)
34     : m_associatedURL(associatedURL)
35     , m_pairs(init.startsWith('?') ? WTF::URLParser::parseURLEncodedForm(StringView(init).substring(1)) : WTF::URLParser::parseURLEncodedForm(init))
36 {
37 }
38
39 URLSearchParams::URLSearchParams(const Vector<WTF::KeyValuePair<String, String>>& pairs)
40     : m_pairs(pairs)
41 {
42 }
43
44 ExceptionOr<Ref<URLSearchParams>> URLSearchParams::create(Variant<Vector<Vector<String>>, Vector<WTF::KeyValuePair<String, String>>, String>&& variant)
45 {
46     auto visitor = WTF::makeVisitor([&](const Vector<Vector<String>>& vector) -> ExceptionOr<Ref<URLSearchParams>> {
47         Vector<WTF::KeyValuePair<String, String>> pairs;
48         for (const auto& pair : vector) {
49             if (pair.size() != 2)
50                 return Exception { TypeError };
51             pairs.append({pair[0], pair[1]});
52         }
53         return adoptRef(*new URLSearchParams(WTFMove(pairs)));
54     }, [&](const Vector<WTF::KeyValuePair<String, String>>& pairs) {
55         return adoptRef(*new URLSearchParams(pairs));
56     }, [&](const String& string) {
57         return adoptRef(*new URLSearchParams(string, nullptr));
58     });
59     return WTF::visit(visitor, variant);
60 }
61
62 String URLSearchParams::get(const String& name) const
63 {
64     for (const auto& pair : m_pairs) {
65         if (pair.key == name)
66             return pair.value;
67     }
68     return String();
69 }
70
71 bool URLSearchParams::has(const String& name) const
72 {
73     for (const auto& pair : m_pairs) {
74         if (pair.key == name)
75             return true;
76     }
77     return false;
78 }
79
80 void URLSearchParams::sort()
81 {
82     std::stable_sort(m_pairs.begin(), m_pairs.end(), [] (const auto& a, const auto& b) {
83         return WTF::codePointCompareLessThan(a.key, b.key);
84     });
85     updateURL();
86 }
87
88 void URLSearchParams::set(const String& name, const String& value)
89 {
90     for (auto& pair : m_pairs) {
91         if (pair.key != name)
92             continue;
93         if (pair.value != value)
94             pair.value = value;
95         bool skippedFirstMatch = false;
96         m_pairs.removeAllMatching([&] (const auto& pair) {
97             if (pair.key == name) {
98                 if (skippedFirstMatch)
99                     return true;
100                 skippedFirstMatch = true;
101             }
102             return false;
103         });
104         updateURL();
105         return;
106     }
107     m_pairs.append({name, value});
108     updateURL();
109 }
110
111 void URLSearchParams::append(const String& name, const String& value)
112 {
113     m_pairs.append({name, value});
114     updateURL();
115 }
116
117 Vector<String> URLSearchParams::getAll(const String& name) const
118 {
119     Vector<String> values;
120     values.reserveInitialCapacity(m_pairs.size());
121     for (const auto& pair : m_pairs) {
122         if (pair.key == name)
123             values.uncheckedAppend(pair.value);
124     }
125     return values;
126 }
127
128 void URLSearchParams::remove(const String& name)
129 {
130     if (m_pairs.removeAllMatching([&] (const auto& pair) { return pair.key == name; }))
131         updateURL();
132 }
133
134 String URLSearchParams::toString() const
135 {
136     return WTF::URLParser::serialize(m_pairs);
137 }
138
139 void URLSearchParams::updateURL()
140 {
141     if (m_associatedURL)
142         m_associatedURL->setQuery(WTF::URLParser::serialize(m_pairs));
143 }
144
145 void URLSearchParams::updateFromAssociatedURL()
146 {
147     ASSERT(m_associatedURL);
148     String search = m_associatedURL->search();
149     m_pairs = search.startsWith('?') ? WTF::URLParser::parseURLEncodedForm(StringView(search).substring(1)) : WTF::URLParser::parseURLEncodedForm(search);
150 }
151
152 std::optional<WTF::KeyValuePair<String, String>> URLSearchParams::Iterator::next()
153 {
154     auto& pairs = m_target->pairs();
155     if (m_index >= pairs.size())
156         return std::nullopt;
157
158     auto& pair = pairs[m_index++];
159     return WTF::KeyValuePair<String, String> { pair.key, pair.value };
160 }
161
162 URLSearchParams::Iterator::Iterator(URLSearchParams& params)
163     : m_target(params)
164 {
165 }
166     
167 }