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

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: rebase Created 6 years, 6 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* input, ExceptionState& except ionState)
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(input, exceptionState);
37 // 3. Return headers.
38 return headers.release();
39 }
40
41 PassRefPtr<Headers> Headers::create(const Dictionary& input, ExceptionState& exc eptionState)
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(input, 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 (headers),
70 // run these steps:
71 // 1. If name is not a name or value is not a value, throw a TypeError.
72 if (!FetchHeaderList::isValidHeaderName(name)) {
73 exceptionState.throwTypeError("Invalid name");
74 return;
75 }
76 if (!FetchHeaderList::isValidHeaderValue(value)) {
77 exceptionState.throwTypeError("Invalid value");
78 return;
79 }
80 // 2. If guard is immutable, throw a TypeError.
81 if (m_guard == ImmutableGuard) {
82 exceptionState.throwTypeError("Headers are immutable");
83 return;
84 }
85 // 3. Otherwise, if guard is request and name is a forbidden header name,
86 // return.
87 if (m_guard == RequestGuard && FetchHeaderList::isForbiddenHeaderName(name))
88 return;
89 // 4. Otherwise, if guard is request-no-CORS and name/value is not a simple
90 // header, return.
91 if (m_guard == RequestNoCORSGuard && !FetchHeaderList::isSimpleHeader(name, value))
92 return;
93 // 5. Otherwise, if guard is response and name is a forbidden response
94 // header name, return.
95 if (m_guard == ResponseGuard && FetchHeaderList::isForbiddenResponseHeaderNa me(name))
96 return;
97 // 6. Append name/value to header list.
98 m_headerList->append(name, value);
99 }
100
101 void Headers::remove(const String& name, ExceptionState& exceptionState)
102 {
103 // The delete(name) method, when invoked, must run these steps:
104 // 1. If name is not a name, throw a TypeError.
105 if (!FetchHeaderList::isValidHeaderName(name)) {
106 exceptionState.throwTypeError("Invalid name");
107 return;
108 }
109 // 2. If guard is immutable, throw a TypeError.
110 if (m_guard == ImmutableGuard) {
111 exceptionState.throwTypeError("Headers are immutable");
112 return;
113 }
114 // 3. Otherwise, if guard is request and name is a forbidden header name,
115 // return.
116 if (m_guard == RequestGuard && FetchHeaderList::isForbiddenHeaderName(name))
117 return;
118 // 4. Otherwise, if guard is request-no-CORS and name/value is not a simple
119 // header, return.
120 if (m_guard == RequestNoCORSGuard && !FetchHeaderList::isSimpleHeader(name, "invalid"))
121 return;
122 // 5. Otherwise, if guard is response and name is a forbidden response
123 // header name, return.
124 if (m_guard == ResponseGuard && FetchHeaderList::isForbiddenResponseHeaderNa me(name))
125 return;
126 // 6. Remove all headers whose name is name from header list.
127 m_headerList->remove(name);
128 }
129
130 String Headers::get(const String& name, ExceptionState& exceptionState)
131 {
132 // The get(name) method, when invoked, must run these steps:
133 // 1. If name is not a name, throw a TypeError.
134 if (!FetchHeaderList::isValidHeaderName(name)) {
135 exceptionState.throwTypeError("Invalid name");
136 return String();
137 }
138 // 2. Return the value of the first header in header list whose name is
139 // name, and null otherwise.
140 String result;
141 if (m_headerList->get(name, result))
142 return result;
143 return String();
falken 2014/06/27 02:08:06 could this just be return result like getAll below
horo 2014/06/27 04:19:10 Done.
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, in
155 // 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 TypeError.
178 if (!FetchHeaderList::isValidHeaderName(name)) {
179 exceptionState.throwTypeError("Invalid name");
180 return;
181 }
182 if (!FetchHeaderList::isValidHeaderValue(value)) {
183 exceptionState.throwTypeError("Invalid value");
184 return;
185 }
186 // 2. If guard is immutable, throw a TypeError.
187 if (m_guard == ImmutableGuard) {
188 exceptionState.throwTypeError("Headers are immutable");
189 return;
190 }
191 // 3. Otherwise, if guard is request and name is a forbidden header name,
192 // return.
193 if (m_guard == RequestGuard && FetchHeaderList::isForbiddenHeaderName(name))
194 return;
195 // 4. Otherwise, if guard is request-no-CORS and name/value is not a simple
196 // header, return.
197 if (m_guard == RequestNoCORSGuard && !FetchHeaderList::isSimpleHeader(name, value))
198 return;
199 // 5. Otherwise, if guard is response and name is a forbidden response
200 // header name, return.
201 if (m_guard == ResponseGuard && FetchHeaderList::isForbiddenResponseHeaderNa me(name))
202 return;
203 // 6. Set name/value in header list.
204 m_headerList->set(name, value);
205 }
206
207 void Headers::forEach(PassOwnPtr<HeadersForEachCallback> callback, ScriptValue& thisArg)
208 {
209 forEachInternal(callback, &thisArg);
210 }
211
212 void Headers::forEach(PassOwnPtr<HeadersForEachCallback> callback)
213 {
214 forEachInternal(callback, 0);
215 }
216
217 void Headers::fillWith(const Headers* headers, ExceptionState& exceptionState)
218 {
219 ASSERT(m_headerList->size() == 0);
220 // To fill a Headers object (headers) with a given object (object), run
221 // these steps:
222 // 1. If object is a Headers object, copy its header list as headerListCopy
223 // and then for each header in headerListCopy, retaining order, append
224 // header's name/header's value to headers. Rethrow any exception.
225 for (size_t i = 0; i < headers->m_headerList->list().size(); ++i) {
226 append(headers->m_headerList->list()[i]->first, headers->m_headerList->l ist()[i]->second, exceptionState);
227 if (exceptionState.hadException())
228 return;
229 }
230 }
231
232 void Headers::fillWith(const Dictionary& dictionary, ExceptionState& exceptionSt ate)
233 {
234 ASSERT(m_headerList->size() == 0);
235 Vector<String> keys;
236 dictionary.getOwnPropertyNames(keys);
237 if (keys.size() == 0)
238 return;
239
240 // Because of the restrictions in IDL compiler of blink we recieve
241 // sequence<sequence<ByteString>> as a Dictionary, which is a type of union
242 // type of HeadersInit defined in the spec.
243 // http://fetch.spec.whatwg.org/#headers-class
244 // FIXME: Support sequence<sequence<ByteString>>.
245 Vector<String> keyValuePair;
246 if (dictionary.get(keys[0], keyValuePair)) {
247 // 2. Otherwise, if object is a sequence, then for each header in
248 // object, run these substeps:
249 // 1. If header does not contain two items, throw a TypeError.
falken 2014/06/27 02:08:06 spec is a unclear if this means exactly two items
horo 2014/06/27 04:19:10 Thank you.
250 // 2. Append header's first item/header's second time to headers.
falken 2014/06/27 02:08:06 spec has a typo: s/time/item. I filed a spec bug.
horo 2014/06/27 04:19:10 Done.
251 // Rethrow any exception.
252 for (size_t i = 0; i < keys.size(); ++i) {
253 // We've already got the keyValuePair for key[0].
254 if (i > 0) {
255 if (!dictionary.get(keys[i], keyValuePair)) {
256 exceptionState.throwTypeError("Invalid value");
257 return;
258 }
259 }
260 if (keyValuePair.size() < 2) {
261 exceptionState.throwTypeError("Invalid value");
262 return;
263 }
264 append(keyValuePair[0], keyValuePair[1], exceptionState);
265 if (exceptionState.hadException())
266 return;
267 keyValuePair.clear();
268 }
269 return;
270 }
271 // 3. Otherwise, if object is an open-ended dictionary, then for each header
272 // in object, run these substeps:
273 // 1. Set header's key to header's key, converted to ByteString. Rethrow
274 // any exception.
275 // 2. Append header's key/header's value to headers. Rethrow any
276 // exception.
277 // FIXME: Support OpenEndedDictionary<ByteString>.
278 for (size_t i = 0; i < keys.size(); ++i) {
279 String value;
280 if (!dictionary.get(keys[i], value)) {
281 exceptionState.throwTypeError("Invalid value");
282 return;
283 }
284 append(keys[i], value, exceptionState);
285 if (exceptionState.hadException())
286 return;
287 }
288 }
289
290 Headers::Headers()
291 : m_headerList(FetchHeaderList::create())
292 , m_guard(NoneGuard)
293 {
294 ScriptWrappable::init(this);
295 }
296
297 // Called when creating Request or Responce.
298 Headers::Headers(FetchHeaderList* headerList)
299 : m_headerList(headerList)
300 , m_guard(NoneGuard)
301 {
302 ScriptWrappable::init(this);
303 }
304
305 void Headers::forEachInternal(PassOwnPtr<HeadersForEachCallback> callback, Scrip tValue* thisArg)
306 {
307 TrackExceptionState exceptionState;
308 for (size_t i = 0; i < m_headerList->size(); ++i) {
309 if (thisArg)
310 callback->handleItem(*thisArg, m_headerList->list()[i]->second, m_he aderList->list()[i]->first, this);
311 else
312 callback->handleItem(m_headerList->list()[i]->second, m_headerList-> list()[i]->first, this);
313 if (exceptionState.hadException())
314 break;
315 }
316 }
317
318 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698