1/*
2 * Copyright (C) 2009 Google 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 are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "HTTPHeaderMap.h"
33
34#include <utility>
35#include <wtf/CrossThreadCopier.h>
36#include <wtf/text/StringView.h>
37
38namespace WebCore {
39
40HTTPHeaderMap::HTTPHeaderMap()
41{
42}
43
44HTTPHeaderMap HTTPHeaderMap::isolatedCopy() const
45{
46 HTTPHeaderMap map;
47 map.m_commonHeaders = crossThreadCopy(m_commonHeaders);
48 map.m_uncommonHeaders = crossThreadCopy(m_uncommonHeaders);
49 return map;
50}
51
52String HTTPHeaderMap::get(const String& name) const
53{
54 HTTPHeaderName headerName;
55 if (findHTTPHeaderName(name, headerName))
56 return get(headerName);
57
58 auto index = m_uncommonHeaders.findMatching([&](auto& header) {
59 return equalIgnoringASCIICase(header.key, name);
60 });
61 return index != notFound ? m_uncommonHeaders[index].value : String();
62}
63
64#if USE(CF)
65
66void HTTPHeaderMap::set(CFStringRef name, const String& value)
67{
68 // Fast path: avoid constructing a temporary String in the common header case.
69 if (auto* nameCharacters = CFStringGetCStringPtr(name, kCFStringEncodingASCII)) {
70 unsigned length = CFStringGetLength(name);
71 HTTPHeaderName headerName;
72 if (findHTTPHeaderName(StringView(reinterpret_cast<const LChar*>(nameCharacters), length), headerName)) {
73 auto index = m_commonHeaders.findMatching([&](auto& header) {
74 return header.key == headerName;
75 });
76 if (index == notFound)
77 m_commonHeaders.append(CommonHeader { headerName, value });
78 else
79 m_commonHeaders[index].value = value;
80 } else
81 set(String(nameCharacters, length), value);
82 return;
83 }
84
85 set(String(name), value);
86}
87
88#endif // USE(CF)
89
90void HTTPHeaderMap::set(const String& name, const String& value)
91{
92 HTTPHeaderName headerName;
93 if (findHTTPHeaderName(name, headerName)) {
94 set(headerName, value);
95 return;
96 }
97
98 auto index = m_uncommonHeaders.findMatching([&](auto& header) {
99 return equalIgnoringASCIICase(header.key, name);
100 });
101 if (index == notFound)
102 m_uncommonHeaders.append(UncommonHeader { name, value });
103 else
104 m_uncommonHeaders[index].value = value;
105}
106
107void HTTPHeaderMap::add(const String& name, const String& value)
108{
109 HTTPHeaderName headerName;
110 if (findHTTPHeaderName(name, headerName)) {
111 add(headerName, value);
112 return;
113 }
114 auto index = m_uncommonHeaders.findMatching([&](auto& header) {
115 return equalIgnoringASCIICase(header.key, name);
116 });
117 if (index == notFound)
118 m_uncommonHeaders.append(UncommonHeader { name, value });
119 else
120 m_uncommonHeaders[index].value = makeString(m_uncommonHeaders[index].value, ", ", value);
121}
122
123void HTTPHeaderMap::append(const String& name, const String& value)
124{
125 ASSERT(!contains(name));
126
127 HTTPHeaderName headerName;
128 if (findHTTPHeaderName(name, headerName))
129 m_commonHeaders.append(CommonHeader { headerName, value });
130 else
131 m_uncommonHeaders.append(UncommonHeader { name, value });
132}
133
134bool HTTPHeaderMap::addIfNotPresent(HTTPHeaderName headerName, const String& value)
135{
136 if (contains(headerName))
137 return false;
138
139 m_commonHeaders.append(CommonHeader { headerName, value });
140 return true;
141}
142
143bool HTTPHeaderMap::contains(const String& name) const
144{
145 HTTPHeaderName headerName;
146 if (findHTTPHeaderName(name, headerName))
147 return contains(headerName);
148
149 return m_uncommonHeaders.findMatching([&](auto& header) {
150 return equalIgnoringASCIICase(header.key, name);
151 }) != notFound;
152}
153
154bool HTTPHeaderMap::remove(const String& name)
155{
156 HTTPHeaderName headerName;
157 if (findHTTPHeaderName(name, headerName))
158 return remove(headerName);
159
160 return m_uncommonHeaders.removeFirstMatching([&](auto& header) {
161 return equalIgnoringASCIICase(header.key, name);
162 });
163}
164
165String HTTPHeaderMap::get(HTTPHeaderName name) const
166{
167 auto index = m_commonHeaders.findMatching([&](auto& header) {
168 return header.key == name;
169 });
170 return index != notFound ? m_commonHeaders[index].value : String();
171}
172
173void HTTPHeaderMap::set(HTTPHeaderName name, const String& value)
174{
175 auto index = m_commonHeaders.findMatching([&](auto& header) {
176 return header.key == name;
177 });
178 if (index == notFound)
179 m_commonHeaders.append(CommonHeader { name, value });
180 else
181 m_commonHeaders[index].value = value;
182}
183
184bool HTTPHeaderMap::contains(HTTPHeaderName name) const
185{
186 return m_commonHeaders.findMatching([&](auto& header) {
187 return header.key == name;
188 }) != notFound;
189}
190
191bool HTTPHeaderMap::remove(HTTPHeaderName name)
192{
193 return m_commonHeaders.removeFirstMatching([&](auto& header) {
194 return header.key == name;
195 });
196}
197
198void HTTPHeaderMap::add(HTTPHeaderName name, const String& value)
199{
200 auto index = m_commonHeaders.findMatching([&](auto& header) {
201 return header.key == name;
202 });
203 if (index != notFound)
204 m_commonHeaders[index].value = makeString(m_commonHeaders[index].value, ", ", value);
205 else
206 m_commonHeaders.append(CommonHeader { name, value });
207}
208
209} // namespace WebCore
210