OLD | NEW |
---|---|
(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/FetchManager.h" | |
13 #include "modules/serviceworkers/HeadersForEachCallback.h" | |
14 #include "wtf/NotFound.h" | |
15 #include "wtf/PassRefPtr.h" | |
16 #include "wtf/RefPtr.h" | |
17 #include "wtf/text/WTFString.h" | |
18 | |
19 namespace WebCore { | |
20 | |
21 PassRefPtr<Headers> Headers::create() | |
22 { | |
23 return adoptRef(new Headers); | |
24 } | |
25 | |
26 PassRefPtr<Headers> Headers::create(ExceptionState&) | |
27 { | |
28 return create(); | |
29 } | |
30 | |
31 PassRefPtr<Headers> Headers::create(const Headers* input, ExceptionState& except ionState) | |
32 { | |
33 // The Headers(init) constructor, when invoked, must run these steps: | |
34 // 1. Let headers be a new Headers object. | |
35 RefPtr<Headers> headers = create(); | |
36 // 2. If init is given, fill headers with init. Rethrow any exception. | |
37 headers->fillWith(input, exceptionState); | |
38 // 3. Return headers. | |
39 return headers.release(); | |
40 } | |
41 | |
42 PassRefPtr<Headers> Headers::create(const Dictionary& input, ExceptionState& exc eptionState) | |
43 { | |
44 // The Headers(init) constructor, when invoked, must run these steps: | |
45 // 1. Let headers be a new Headers object. | |
46 RefPtr<Headers> headers = create(); | |
47 // 2. If init is given, fill headers with init. Rethrow any exception. | |
48 headers->fillWith(input, exceptionState); | |
49 // 3. Return headers. | |
50 return headers.release(); | |
51 } | |
52 | |
53 // Called when creating Request. | |
54 PassRefPtr<Headers> Headers::create(FetchHeaderList* headerList) | |
55 { | |
56 return adoptRef(new Headers(headerList)); | |
57 } | |
58 | |
59 Headers::~Headers() | |
60 { | |
61 } | |
62 | |
63 unsigned long Headers::size() const | |
64 { | |
65 return m_headerList->size(); | |
66 } | |
67 | |
68 void Headers::append(const String& name, const String& value, ExceptionState& ex ceptionState) | |
69 { | |
70 // To append a name/value (name/value) pair to a Headers object (headers), | |
71 // run these steps: | |
72 // 1. If name is not a name or value is not a value, throw a 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 immutable, 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 name, | |
87 // 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 simple | |
91 // 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 name, | |
116 // return. | |
117 if (m_guard == RequestGuard && FetchHeaderList::isForbiddenHeaderName(name)) | |
118 return; | |
119 // 4. Otherwise, if guard is request-no-CORS and name/value is not a simple | |
120 // 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. Remove all headers whose name is 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 if (m_headerList->get(name, result)) | |
143 return result; | |
144 return String(); | |
145 } | |
146 | |
147 Vector<String> Headers::getAll(const String& name, ExceptionState& exceptionStat e) | |
148 { | |
149 // The getAll(name) method, when invoked, must run these steps: | |
150 // 1. If name is not a name, throw a TypeError. | |
151 if (!FetchHeaderList::isValidHeaderName(name)) { | |
152 exceptionState.throwTypeError("Invalid name"); | |
153 return Vector<String>(); | |
154 } | |
155 // 2. Return the values of all headers in header list whose name is name, in | |
156 // list order, and the empty sequence otherwise. | |
157 Vector<String> result; | |
158 m_headerList->getAll(name, result); | |
159 return result; | |
160 } | |
161 | |
162 bool Headers::has(const String& name, ExceptionState& exceptionState) | |
163 { | |
164 // The has(name) method, when invoked, must run these steps: | |
165 // 1. If name is not a name, throw a TypeError. | |
166 if (!FetchHeaderList::isValidHeaderName(name)) { | |
167 exceptionState.throwTypeError("Invalid name"); | |
168 return false; | |
169 } | |
170 // 2. Return true if there is a header in header list whose name is name, | |
171 // and false otherwise. | |
172 return m_headerList->has(name); | |
173 } | |
174 | |
175 void Headers::set(const String& name, const String& value, ExceptionState& excep tionState) | |
176 { | |
177 // The set(name, value) method, when invoked, must run these steps: | |
178 // 1. If name is not a name or value is not a value, throw a 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 name, | |
193 // 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 simple | |
197 // 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::clearHeaderList() | |
219 { | |
220 m_headerList->clearList(); | |
221 } | |
222 | |
223 void Headers::fillWith(const Headers* headers, ExceptionState& exceptionState) | |
224 { | |
yhirano
2014/06/26 07:22:13
Can this method be called when |this| is not empty
horo
2014/06/26 08:30:08
Added
ASSERT(m_headerList->size() == 0);
| |
225 // To fill a Headers object (headers) with a given object (object), run | |
226 // these steps: | |
227 // 1. If object is a Headers object, copy its header list as headerListCopy | |
228 // and then for each header in headerListCopy, retaining order, append | |
229 // header's name/header's value to headers. Rethrow any exception. | |
230 for (size_t i = 0; i < headers->list()->list().size(); ++i) { | |
231 append(headers->list()->list()[i]->first, headers->list()->list()[i]->se cond, exceptionState); | |
232 if (exceptionState.hadException()) | |
233 return; | |
234 } | |
235 } | |
236 | |
237 void Headers::fillWith(const Dictionary& dictionary, ExceptionState& exceptionSt ate) | |
238 { | |
yhirano
2014/06/26 07:22:13
ditto
horo
2014/06/26 08:30:08
Done.
| |
239 Vector<String> keys; | |
240 dictionary.getOwnPropertyNames(keys); | |
241 if (keys.size() == 0) | |
242 return; | |
243 | |
244 // Because of the restrictions in IDL compiler of blink we recieve | |
245 // sequence<sequence<ByteString>> as a Dictionary, which is a type of union | |
246 // type of HeadersInit defined in the spec. | |
247 // http://fetch.spec.whatwg.org/#headers-class | |
248 // FIXME: Support sequence<sequence<ByteString>>. | |
249 Vector<String> keyValuePair; | |
250 if (dictionary.get(keys[0], keyValuePair)) { | |
251 // 2. Otherwise, if object is a sequence, then for each header in | |
252 // object, run these substeps: | |
253 // 1. If header does not contain two items, throw a TypeError. | |
254 // 2. Append header's first item/header's second time to headers. | |
255 // Rethrow any exception. | |
256 for (size_t i = 0; i < keys.size(); ++i) { | |
257 if (i != 0 && !dictionary.get(keys[i], keyValuePair)) { | |
yhirano
2014/06/26 07:22:13
[optional] I would split these conditions.
// We'
horo
2014/06/26 08:30:08
Done.
| |
258 exceptionState.throwTypeError("Invalid value"); | |
259 return; | |
260 } | |
261 if (keyValuePair.size() != 2) { | |
yhirano
2014/06/26 07:22:13
I'm not sure whether the spec says the size must b
horo
2014/06/26 08:30:08
Done.
| |
262 exceptionState.throwTypeError("Invalid value"); | |
263 return; | |
264 } | |
265 append(keyValuePair[0], keyValuePair[1], exceptionState); | |
266 if (exceptionState.hadException()) | |
267 return; | |
268 keyValuePair.clear(); | |
269 } | |
270 return; | |
271 } | |
272 // 3. Otherwise, if object is an open-ended dictionary, then for each header | |
273 // in object, run these substeps: | |
274 // 1. Set header's key to header's key, converted to ByteString. Rethrow | |
275 // any exception. | |
276 // 2. Append header's key/header's value to headers. Rethrow any | |
277 // exception. | |
278 // FIXME: Support OpenEndedDictionary<ByteString>. | |
279 for (size_t i = 0; i < keys.size(); ++i) { | |
280 String value; | |
281 if (!dictionary.get(keys[i], value)) { | |
282 exceptionState.throwTypeError("Invalid value"); | |
283 return; | |
284 } | |
285 append(keys[i], value, exceptionState); | |
286 if (exceptionState.hadException()) | |
287 return; | |
288 } | |
289 } | |
290 | |
291 Headers::Headers() | |
292 : m_headerList(FetchHeaderList::create()) | |
293 , m_guard(NoneGuard) | |
294 { | |
295 ScriptWrappable::init(this); | |
296 } | |
297 | |
298 // Called when creating Request or Responce. | |
299 Headers::Headers(FetchHeaderList* headerList) | |
300 : m_headerList(headerList) | |
301 , m_guard(NoneGuard) | |
302 { | |
303 ScriptWrappable::init(this); | |
304 } | |
305 | |
306 void Headers::forEachInternal(PassOwnPtr<HeadersForEachCallback> callback, Scrip tValue* thisArg) | |
307 { | |
308 TrackExceptionState exceptionState; | |
309 for (size_t i = 0; i < m_headerList->size(); ++i) { | |
310 if (thisArg) | |
311 callback->handleItem(*thisArg, m_headerList->list()[i]->first, m_hea derList->list()[i]->second, this); | |
312 else | |
313 callback->handleItem(m_headerList->list()[i]->first, m_headerList->l ist()[i]->second, this); | |
314 if (exceptionState.hadException()) | |
315 break; | |
316 } | |
317 } | |
318 | |
319 } // namespace WebCore | |
OLD | NEW |