Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Side by Side Diff: Source/modules/serviceworkers/Headers.cpp

Issue 358573002: [ServiceWorker] Implement Headers class. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "modules/serviceworkers/Headers.h"
7
8 #include "bindings/v8/Dictionary.h"
9 #include "bindings/v8/ExceptionState.h"
10 #include "core/fetch/CrossOriginAccessControl.h"
11 #include "core/xml/XMLHttpRequest.h"
12 #include "modules/serviceworkers/HeadersForEachCallback.h"
13 #include "wtf/NotFound.h"
14 #include "wtf/PassRefPtr.h"
15 #include "wtf/RefPtr.h"
16 #include "wtf/text/WTFString.h"
17
18 namespace WebCore {
19
20 PassRefPtr<Headers> Headers::create()
21 {
22 return adoptRef(new Headers);
23 }
24
25 PassRefPtr<Headers> Headers::create(ExceptionState&)
26 {
27 return create();
28 }
29
30 PassRefPtr<Headers> Headers::create(const Headers* init, ExceptionState& excepti onState)
31 {
32 // "The Headers(|init|) constructor, when invoked, must run these steps:"
33 // "1. Let |headers| be a new Headers object."
34 RefPtr<Headers> headers = create();
35 // "2. If |init| is given, fill headers with |init|. Rethrow any exception."
36 headers->fillWith(init, exceptionState);
37 // "3. Return |headers|."
38 return headers.release();
39 }
40
41 PassRefPtr<Headers> Headers::create(const Dictionary& init, ExceptionState& exce ptionState)
42 {
43 // "The Headers(|init|) constructor, when invoked, must run these steps:"
44 // "1. Let |headers| be a new Headers object."
45 RefPtr<Headers> headers = create();
46 // "2. If |init| is given, fill headers with |init|. Rethrow any exception."
47 headers->fillWith(init, exceptionState);
48 // "3. Return |headers|."
49 return headers.release();
50 }
51
52 // Called when creating Request.
53 PassRefPtr<Headers> Headers::create(FetchHeaderList* headerList)
54 {
55 return adoptRef(new Headers(headerList));
56 }
57
58 Headers::~Headers()
59 {
60 }
61
62 unsigned long Headers::size() const
63 {
64 return m_headerList->size();
65 }
66
67 void Headers::append(const String& name, const String& value, ExceptionState& ex ceptionState)
68 {
69 // "To append a name/value (|name|/|value|) pair to a Headers object
70 // (|headers|), run these steps:"
71 // "1. If |name| is not a name or |value| is not a value, throw a
72 // TypeError."
73 if (!FetchHeaderList::isValidHeaderName(name)) {
74 exceptionState.throwTypeError("Invalid name");
75 return;
76 }
77 if (!FetchHeaderList::isValidHeaderValue(value)) {
78 exceptionState.throwTypeError("Invalid value");
79 return;
80 }
81 // "2. If guard is |request|, throw a TypeError."
82 if (m_guard == ImmutableGuard) {
83 exceptionState.throwTypeError("Headers are immutable");
84 return;
85 }
86 // "3. Otherwise, if guard is |request| and |name| is a forbidden header
87 // name, return."
88 if (m_guard == RequestGuard && FetchHeaderList::isForbiddenHeaderName(name))
89 return;
90 // "4. Otherwise, if guard is |request-no-CORS| and |name|/|value| is not a
91 // simple header, return."
92 if (m_guard == RequestNoCORSGuard && !FetchHeaderList::isSimpleHeader(name, value))
93 return;
94 // "5. Otherwise, if guard is |response| and |name| is a forbidden response
95 // header name, return."
96 if (m_guard == ResponseGuard && FetchHeaderList::isForbiddenResponseHeaderNa me(name))
97 return;
98 // "6. Append |name|/|value| to header list."
99 m_headerList->append(name, value);
100 }
101
102 void Headers::remove(const String& name, ExceptionState& exceptionState)
103 {
104 // "The delete(|name|) method, when invoked, must run these steps:"
105 // "1. If name is not a name, throw a TypeError."
106 if (!FetchHeaderList::isValidHeaderName(name)) {
107 exceptionState.throwTypeError("Invalid name");
108 return;
109 }
110 // "2. If guard is |immutable|, throw a TypeError."
111 if (m_guard == ImmutableGuard) {
112 exceptionState.throwTypeError("Headers are immutable");
113 return;
114 }
115 // "3. Otherwise, if guard is |request| and |name| is a forbidden header
116 // name, return."
117 if (m_guard == RequestGuard && FetchHeaderList::isForbiddenHeaderName(name))
118 return;
119 // "4. Otherwise, if guard is |request-no-CORS| and |name|/`invalid` is not
120 // a simple header, return."
121 if (m_guard == RequestNoCORSGuard && !FetchHeaderList::isSimpleHeader(name, "invalid"))
122 return;
123 // "5. Otherwise, if guard is |response| and |name| is a forbidden response
124 // header name, return."
125 if (m_guard == ResponseGuard && FetchHeaderList::isForbiddenResponseHeaderNa me(name))
126 return;
127 // "6. Delete |name| from header list."
128 m_headerList->remove(name);
129 }
130
131 String Headers::get(const String& name, ExceptionState& exceptionState)
132 {
133 // "The get(|name|) method, when invoked, must run these steps:"
134 // "1. If |name| is not a name, throw a TypeError."
135 if (!FetchHeaderList::isValidHeaderName(name)) {
136 exceptionState.throwTypeError("Invalid name");
137 return String();
138 }
139 // "2. Return the value of the first header in header list whose name is
140 // |name|, and null otherwise."
141 String result;
142 m_headerList->get(name, result);
143 return result;
144 }
145
146 Vector<String> Headers::getAll(const String& name, ExceptionState& exceptionStat e)
147 {
148 // "The getAll(|name|) method, when invoked, must run these steps:"
149 // "1. If |name| is not a name, throw a TypeError."
150 if (!FetchHeaderList::isValidHeaderName(name)) {
151 exceptionState.throwTypeError("Invalid name");
152 return Vector<String>();
153 }
154 // "2. Return the values of all headers in header list whose name is |name|,
155 // in list order, and the empty sequence otherwise."
156 Vector<String> result;
157 m_headerList->getAll(name, result);
158 return result;
159 }
160
161 bool Headers::has(const String& name, ExceptionState& exceptionState)
162 {
163 // "The has(|name|) method, when invoked, must run these steps:"
164 // "1. If |name| is not a name, throw a TypeError."
165 if (!FetchHeaderList::isValidHeaderName(name)) {
166 exceptionState.throwTypeError("Invalid name");
167 return false;
168 }
169 // "2. Return true if there is a header in header list whose name is |name|,
170 // and false otherwise."
171 return m_headerList->has(name);
172 }
173
174 void Headers::set(const String& name, const String& value, ExceptionState& excep tionState)
175 {
176 // "The set(|name|, |value|) method, when invoked, must run these steps:"
177 // "1. If |name| is not a name or |value| is not a value, throw a
178 // TypeError."
179 if (!FetchHeaderList::isValidHeaderName(name)) {
180 exceptionState.throwTypeError("Invalid name");
181 return;
182 }
183 if (!FetchHeaderList::isValidHeaderValue(value)) {
184 exceptionState.throwTypeError("Invalid value");
185 return;
186 }
187 // "2. If guard is |immutable|, throw a TypeError."
188 if (m_guard == ImmutableGuard) {
189 exceptionState.throwTypeError("Headers are immutable");
190 return;
191 }
192 // "3. Otherwise, if guard is |request| and |name| is a forbidden header
193 // name, return."
194 if (m_guard == RequestGuard && FetchHeaderList::isForbiddenHeaderName(name))
195 return;
196 // "4. Otherwise, if guard is |request-no-CORS| and |name|/|value| is not a
197 // simple header, return."
198 if (m_guard == RequestNoCORSGuard && !FetchHeaderList::isSimpleHeader(name, value))
199 return;
200 // "5. Otherwise, if guard is |response| and |name| is a forbidden response
201 // header name, return."
202 if (m_guard == ResponseGuard && FetchHeaderList::isForbiddenResponseHeaderNa me(name))
203 return;
204 // "6. Set |name|/|value| in header list."
205 m_headerList->set(name, value);
206 }
207
208 void Headers::forEach(PassOwnPtr<HeadersForEachCallback> callback, ScriptValue& thisArg)
209 {
210 forEachInternal(callback, &thisArg);
211 }
212
213 void Headers::forEach(PassOwnPtr<HeadersForEachCallback> callback)
214 {
215 forEachInternal(callback, 0);
216 }
217
218 void Headers::fillWith(const Headers* object, ExceptionState& exceptionState)
219 {
220 ASSERT(m_headerList->size() == 0);
221 // "To fill a Headers object (|this|) with a given object (|object|), run
222 // these steps:"
223 // "1. If |object| is a Headers object, copy its header list as
224 // |headerListCopy| and then for each |header| in |headerListCopy|,
225 // retaining order, append header's |name|/|header|'s value to
226 // |headers|. Rethrow any exception."
227 for (size_t i = 0; i < object->m_headerList->list().size(); ++i) {
228 append(object->m_headerList->list()[i]->first, object->m_headerList->lis t()[i]->second, exceptionState);
229 if (exceptionState.hadException())
230 return;
231 }
232 }
233
234 void Headers::fillWith(const Dictionary& object, ExceptionState& exceptionState)
235 {
236 ASSERT(m_headerList->size() == 0);
237 Vector<String> keys;
238 object.getOwnPropertyNames(keys);
239 if (keys.size() == 0)
240 return;
241
242 // Because of the restrictions in IDL compiler of blink we recieve
243 // sequence<sequence<ByteString>> as a Dictionary, which is a type of union
244 // type of HeadersInit defined in the spec.
245 // http://fetch.spec.whatwg.org/#headers-class
246 // FIXME: Support sequence<sequence<ByteString>>.
247 Vector<String> keyValuePair;
248 if (object.get(keys[0], keyValuePair)) {
249 // "2. Otherwise, if |object| is a sequence, then for each |header| in
250 // |object|, run these substeps:
251 // 1. If |header| does not contain two items, throw a TypeError.
252 // 2. Append |header|'s first item/|header|'s second item to
253 // |headers|. Rethrow any exception."
254 for (size_t i = 0; i < keys.size(); ++i) {
255 // We've already got the keyValuePair for key[0].
256 if (i > 0) {
257 if (!object.get(keys[i], keyValuePair)) {
258 exceptionState.throwTypeError("Invalid value");
259 return;
260 }
261 }
262 if (keyValuePair.size() < 2) {
263 exceptionState.throwTypeError("Invalid value");
264 return;
265 }
266 append(keyValuePair[0], keyValuePair[1], exceptionState);
267 if (exceptionState.hadException())
268 return;
269 keyValuePair.clear();
270 }
271 return;
272 }
273 // "3. Otherwise, if |object| is an open-ended dictionary, then for each
274 // |header| in object, run these substeps:
275 // 1. Set |header|'s key to |header|'s key, converted to ByteString.
276 // Rethrow any exception.
277 // 2. Append |header|'s key/|header|'s value to |headers|. Rethrow any
278 // exception."
279 // FIXME: Support OpenEndedDictionary<ByteString>.
280 for (size_t i = 0; i < keys.size(); ++i) {
281 String value;
282 if (!object.get(keys[i], value)) {
283 exceptionState.throwTypeError("Invalid value");
284 return;
285 }
286 append(keys[i], value, exceptionState);
287 if (exceptionState.hadException())
288 return;
289 }
290 }
291
292 Headers::Headers()
293 : m_headerList(FetchHeaderList::create())
294 , m_guard(NoneGuard)
295 {
296 ScriptWrappable::init(this);
297 }
298
299 // Called when creating Request or Responce.
300 Headers::Headers(FetchHeaderList* headerList)
301 : m_headerList(headerList)
302 , m_guard(NoneGuard)
303 {
304 ScriptWrappable::init(this);
305 }
306
307 void Headers::forEachInternal(PassOwnPtr<HeadersForEachCallback> callback, Scrip tValue* thisArg)
308 {
309 TrackExceptionState exceptionState;
310 for (size_t i = 0; i < m_headerList->size(); ++i) {
311 if (thisArg)
312 callback->handleItem(*thisArg, m_headerList->list()[i]->second, m_he aderList->list()[i]->first, this);
313 else
314 callback->handleItem(m_headerList->list()[i]->second, m_headerList-> list()[i]->first, this);
315 if (exceptionState.hadException())
316 break;
317 }
318 }
319
320 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698