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

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

Issue 399543002: [ServiceWorker] Make fetch() method better conformance with the spec. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: indent and comment fix 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
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "config.h" 5 #include "config.h"
6 #include "FetchManager.h" 6 #include "FetchManager.h"
7 7
8 #include "bindings/core/v8/ExceptionState.h" 8 #include "bindings/core/v8/ExceptionState.h"
9 #include "bindings/core/v8/ScriptPromiseResolver.h" 9 #include "bindings/core/v8/ScriptPromiseResolver.h"
10 #include "bindings/core/v8/ScriptState.h" 10 #include "bindings/core/v8/ScriptState.h"
11 #include "bindings/core/v8/V8ThrowException.h" 11 #include "bindings/core/v8/V8ThrowException.h"
12 #include "core/dom/ExceptionCode.h" 12 #include "core/dom/ExceptionCode.h"
13 #include "core/fileapi/Blob.h" 13 #include "core/fileapi/Blob.h"
14 #include "core/loader/ThreadableLoader.h" 14 #include "core/loader/ThreadableLoader.h"
15 #include "core/loader/ThreadableLoaderClient.h" 15 #include "core/loader/ThreadableLoaderClient.h"
16 #include "core/xml/XMLHttpRequest.h" 16 #include "core/xml/XMLHttpRequest.h"
17 #include "modules/serviceworkers/FetchRequestData.h"
17 #include "modules/serviceworkers/Response.h" 18 #include "modules/serviceworkers/Response.h"
18 #include "modules/serviceworkers/ResponseInit.h" 19 #include "modules/serviceworkers/ResponseInit.h"
19 #include "platform/network/ResourceRequest.h" 20 #include "platform/network/ResourceRequest.h"
21 #include "platform/weborigin/SecurityOrigin.h"
22 #include "public/platform/WebURLRequest.h"
20 #include "wtf/HashSet.h" 23 #include "wtf/HashSet.h"
21 24
22 namespace blink { 25 namespace blink {
23 26
24 class FetchManager::Loader : public ThreadableLoaderClient { 27 class FetchManager::Loader : public ThreadableLoaderClient {
25 public: 28 public:
26 Loader(ExecutionContext*, FetchManager*, PassRefPtr<ScriptPromiseResolver>, PassOwnPtr<ResourceRequest>); 29 Loader(ExecutionContext*, FetchManager*, PassRefPtr<ScriptPromiseResolver>, PassRefPtr<FetchRequestData>);
27 ~Loader(); 30 ~Loader();
28 virtual void didReceiveResponse(unsigned long, const ResourceResponse&); 31 virtual void didReceiveResponse(unsigned long, const ResourceResponse&);
29 virtual void didFinishLoading(unsigned long, double); 32 virtual void didFinishLoading(unsigned long, double);
30 virtual void didFail(const ResourceError&); 33 virtual void didFail(const ResourceError&);
31 virtual void didFailAccessControlCheck(const ResourceError&); 34 virtual void didFailAccessControlCheck(const ResourceError&);
32 virtual void didFailRedirectCheck(); 35 virtual void didFailRedirectCheck();
33 virtual void didDownloadData(int); 36 virtual void didDownloadData(int);
34 37
35 void start(); 38 void start();
36 void cleanup(); 39 void cleanup();
37 40
38 private: 41 private:
42 void performBasicFetch();
43 void performNetworkError();
44 void performHTTPFetch();
39 void failed(); 45 void failed();
40 void notifyFinished(); 46 void notifyFinished();
41 47
42 ExecutionContext* m_executionContext; 48 ExecutionContext* m_executionContext;
43 FetchManager* m_fetchManager; 49 FetchManager* m_fetchManager;
44 RefPtr<ScriptPromiseResolver> m_resolver; 50 RefPtr<ScriptPromiseResolver> m_resolver;
45 OwnPtr<ResourceRequest> m_request; 51 RefPtr<FetchRequestData> m_request;
46 RefPtr<ThreadableLoader> m_loader; 52 RefPtr<ThreadableLoader> m_loader;
47 ResourceResponse m_response; 53 ResourceResponse m_response;
48 long long m_downloadedBlobLength; 54 long long m_downloadedBlobLength;
55 bool m_corsFlag;
56 bool m_corsPreflightFlag;
49 bool m_failed; 57 bool m_failed;
50 }; 58 };
51 59
52 FetchManager::Loader::Loader(ExecutionContext* executionContext, FetchManager* f etchManager, PassRefPtr<ScriptPromiseResolver> resolver, PassOwnPtr<ResourceRequ est> request) 60 FetchManager::Loader::Loader(ExecutionContext* executionContext, FetchManager* f etchManager, PassRefPtr<ScriptPromiseResolver> resolver, PassRefPtr<FetchRequest Data> request)
53 : m_executionContext(executionContext) 61 : m_executionContext(executionContext)
54 , m_fetchManager(fetchManager) 62 , m_fetchManager(fetchManager)
55 , m_resolver(resolver) 63 , m_resolver(resolver)
56 , m_request(request) 64 , m_request(request->createCopy())
57 , m_downloadedBlobLength(0) 65 , m_downloadedBlobLength(0)
66 , m_corsFlag(false)
67 , m_corsPreflightFlag(false)
58 , m_failed(false) 68 , m_failed(false)
59 { 69 {
60 } 70 }
61 71
62 FetchManager::Loader::~Loader() 72 FetchManager::Loader::~Loader()
63 { 73 {
64 if (m_loader) 74 if (m_loader)
65 m_loader->cancel(); 75 m_loader->cancel();
66 } 76 }
67 77
68 void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo nse& response) 78 void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo nse& response)
69 { 79 {
70 m_response = response; 80 m_response = response;
71 } 81 }
72 82
73 void FetchManager::Loader::didFinishLoading(unsigned long, double) 83 void FetchManager::Loader::didFinishLoading(unsigned long, double)
74 { 84 {
75 OwnPtr<BlobData> blobData = BlobData::create(); 85 OwnPtr<BlobData> blobData = BlobData::create();
76 String filePath = m_response.downloadedFilePath(); 86 String filePath = m_response.downloadedFilePath();
77 if (!filePath.isEmpty() && m_downloadedBlobLength) { 87 if (!filePath.isEmpty() && m_downloadedBlobLength) {
78 blobData->appendFile(filePath); 88 blobData->appendFile(filePath);
79 blobData->setContentType(m_response.mimeType()); 89 blobData->setContentType(m_response.mimeType());
80 } 90 }
81 ResponseInit responseInit; 91 RefPtr<FetchResponseData> response(FetchResponseData::create());
82 // FIXME: We may have to filter the status when we support CORS. 92 response->setStatus(m_response.httpStatusCode());
83 // http://fetch.spec.whatwg.org/#concept-filtered-response-opaque 93 response->setStatusMessage(m_response.httpStatusText());
84 responseInit.status = m_response.httpStatusCode(); 94 HTTPHeaderMap::const_iterator end = m_response.httpHeaderFields().end();
85 responseInit.statusText = m_response.httpStatusText(); 95 for (HTTPHeaderMap::const_iterator it = m_response.httpHeaderFields().begin( ); it != end; ++it) {
86 // FIXME: fill options. 96 response->headerList()->append(it->key, it->value);
87 RefPtrWillBeRawPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData .release(), m_downloadedBlobLength)); 97 }
88 // FIXME: Handle response status correctly. 98 response->setBlobDataHandle(BlobDataHandle::create(blobData.release(), m_dow nloadedBlobLength));
89 NonThrowableExceptionState exceptionState; 99 response->setURL(m_request->url());
90 m_resolver->resolve(Response::create(blob.get(), responseInit, exceptionStat e)); 100
101 switch (m_request->tainting()) {
102 case FetchRequestData::BasicTainting:
103 response = response->createBasicFilteredResponse();
104 break;
105 case FetchRequestData::CORSTainting:
106 response = response->createCORSFilteredResponse();
107 break;
108 case FetchRequestData::OpaqueTainting:
109 response = response->createOpaqueFilteredResponse();
110 break;
111 }
112 m_resolver->resolve(Response::create(response.release()));
91 notifyFinished(); 113 notifyFinished();
92 } 114 }
93 115
94 void FetchManager::Loader::didFail(const ResourceError& error) 116 void FetchManager::Loader::didFail(const ResourceError& error)
95 { 117 {
96 failed(); 118 failed();
97 } 119 }
98 120
99 void FetchManager::Loader::didFailAccessControlCheck(const ResourceError& error) 121 void FetchManager::Loader::didFailAccessControlCheck(const ResourceError& error)
100 { 122 {
101 failed(); 123 failed();
102 } 124 }
103 125
104 void FetchManager::Loader::didFailRedirectCheck() 126 void FetchManager::Loader::didFailRedirectCheck()
105 { 127 {
106 failed(); 128 failed();
107 } 129 }
108 130
109 void FetchManager::Loader::didDownloadData(int dataLength) 131 void FetchManager::Loader::didDownloadData(int dataLength)
110 { 132 {
111 m_downloadedBlobLength += dataLength; 133 m_downloadedBlobLength += dataLength;
112 } 134 }
113 135
114 void FetchManager::Loader::start() 136 void FetchManager::Loader::start()
115 { 137 {
116 m_request->setDownloadToFile(true); 138
117 ThreadableLoaderOptions options; 139 // "1. If |request|'s url contains a Known HSTS Host, modify it perthe
falken 2014/07/25 05:41:29 s/perthe/per the/
horo 2014/07/25 06:00:56 Done.
118 // FIXME: Fill options. 140 // requirements of the 'URI [sic] Loading and Port Mapping' chapter of HTTP
119 ResourceLoaderOptions resourceLoaderOptions; 141 // Strict Transport Security."
120 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; 142 // FIXME: Implement this.
121 // FIXME: Fill resourceLoaderOptions. 143
122 m_loader = ThreadableLoader::create(*m_executionContext, this, *m_request, o ptions, resourceLoaderOptions); 144 // "2. If |request|'s referrer is not none, set |request|'s referrer to the
145 // result of invoking determine |request|'s referrer."
146 // We set the referrer using workerGlobalScope's URL in
147 // WorkerThreadableLoader.
148
149 // "3. If |request|'s synchronous flag is unset and fetch is not invoked
150 // recursively, run the remaining steps asynchronously."
151 // We don't support synchronous flag.
152
153 // "4. Let response be the value corresponding to the first matching
154 // statement:"
155
156 // "- should fetching |request| be blocked as mixed content returns blocked
157 // - should fetching |request| be blocked as content security returns
158 // blocked
159 // A network error."
160 // We do mixed content checking and CSP checking in ResourceFetcher.
161
162 // "- |request|'s url's origin is |request|'s origin and the |CORS flag| is
163 // unset"
164 // "- |request|'s url's scheme is 'data' and |request|'s same-origin data
165 // URL flag is set"
166 // "- |request|'s url's scheme is 'about'"
167 if ((SecurityOrigin::create(m_request->url())->isSameSchemeHostPort(m_reques t->origin().get()) && !m_corsFlag)
168 || (m_request->url().protocolIsData() && m_request->sameOriginDataURLFla g())
169 || (m_request->url().protocolIsAbout())) {
170 // "The result of performing a basic fetch using request."
171 performBasicFetch();
172 return;
173 }
174
175 // "- |request|'s mode is |same-origin|"
176 if (m_request->mode() == FetchRequestData::SameOriginMode) {
177 // "A network error."
178 performNetworkError();
179 return;
180 }
181
182 // "- |request|'s mode is |no CORS|"
183 if (m_request->mode() == FetchRequestData::NoCORSMode) {
184 // "Set |request|'s response tainting to |opaque|."
185 m_request->setResponseTainting(FetchRequestData::OpaqueTainting);
186 // "The result of performing a basic fetch using |request|."
187 performBasicFetch();
188 return;
189 }
190
191 // "- |request|'s url's scheme is not one of 'http' and 'https'"
192 if (!m_request->url().protocolIsInHTTPFamily()) {
193 // "A network error."
194 performNetworkError();
195 return;
196 }
197
198 // "- |request|'s mode is |CORS-with-forced-preflight|.
199 // "- |request|'s unsafe request flag is set and either |request|'s method
200 // is not a simple method or a header in |request|'s header list is not a
201 // simple header"
202 if (m_request->mode() == FetchRequestData::CORSWithForcedPreflight
203 || (m_request->unsafeRequestFlag()
204 && (!isSimpleMethod(m_request->method())
205 || m_request->headerList()->containsNonSimpleHeader()))) {
206 // "Set |request|'s response tainting to |CORS|."
207 m_request->setResponseTainting(FetchRequestData::CORSTainting);
208 // "The result of performing an HTTP fetch using |request| with the
209 // |CORS flag| and |CORS preflight flag| set."
210 m_corsFlag = true;
211 m_corsPreflightFlag = true;
212 performHTTPFetch();
213 return;
214 }
215
216 // "- Otherwise
217 // Set |request|'s response tainting to |CORS|."
218 m_request->setResponseTainting(FetchRequestData::CORSTainting);
219 // "The result of performing an HTTP fetch using |request| with the
220 // |CORS flag| set."
221 m_corsFlag = true;
222 m_corsPreflightFlag = false;
223 performHTTPFetch();
123 } 224 }
124 225
125 void FetchManager::Loader::cleanup() 226 void FetchManager::Loader::cleanup()
126 { 227 {
127 // Prevent notification 228 // Prevent notification
128 m_fetchManager = 0; 229 m_fetchManager = 0;
129 230
130 if (m_loader) { 231 if (m_loader) {
131 m_loader->cancel(); 232 m_loader->cancel();
132 m_loader.clear(); 233 m_loader.clear();
133 } 234 }
134 } 235 }
135 236
237 void FetchManager::Loader::performBasicFetch()
238 {
239 // "To perform a basic fetch using |request|, switch on |request|'s url's
240 // scheme, and run the associated steps:"
241 if (m_request->url().protocolIsInHTTPFamily()) {
242 // "Return the result of performing an HTTP fetch using |request|."
243 m_corsFlag = false;
244 m_corsPreflightFlag = false;
245 performHTTPFetch();
246 } else {
247 // FIXME: implement other protocols.
248 performNetworkError();
249 }
250 }
251
252 void FetchManager::Loader::performNetworkError()
253 {
254 failed();
255 }
256
257 void FetchManager::Loader::performHTTPFetch()
258 {
259 // CORS preflight fetch procedure is implemented inside DocumentThreadableLo ader.
260
261 // "1. Let |HTTPRequest| be a copy of |request|, except that |HTTPRequest|'s
262 // body is a tee of |request|'s body."
263 // We use ResourceRequest class for HTTPRequest.
264 // FIXME: Support body.
265 ResourceRequest request(m_request->url());
266 request.setRequestContext(blink::WebURLRequest::RequestContextFetch);
267 request.setDownloadToFile(true);
268 request.setHTTPMethod(m_request->method());
269 const Vector<OwnPtr<FetchHeaderList::Header> >& list = m_request->headerList ()->list();
270 for (size_t i = 0; i < list.size(); ++i) {
271 request.addHTTPHeaderField(AtomicString(list[i]->first), AtomicString(li st[i]->second));
272 }
273
274 // "2. Append `Referer`/empty byte sequence, if |HTTPRequest|'s |referrer|
275 // is none, and `Referer`/|HTTPRequest|'s referrer, serialized and utf-8
276 // encoded, otherwise, to HTTPRequest's header list.
277 // We set the referrer using workerGlobalScope's URL in
278 // WorkerThreadableLoader.
279
280 // "3. Append `Host`, ..."
281 // FIXME: Implement this when the spec is fixed.
282
283 // "4.If |HTTPRequest|'s force Origin header flag is set, append `Origin`/
284 // |HTTPRequest|'s origin, serialized and utf-8 encoded, to |HTTPRequest|'s
285 // header list."
286 // We set Origin header in updateRequestForAccessControl() called from
287 // DocumentThreadableLoader::makeCrossOriginAccessRequest
288
289 // "5. Let |credentials flag| be set if either |HTTPRequest|'s credentials
290 // mode is |include|, or |HTTPRequest|'s credentials mode is |same-origin|
291 // and the |CORS flag| is unset, and unset otherwise.
292 ResourceLoaderOptions resourceLoaderOptions;
293 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
294 if (m_request->credentials() == FetchRequestData::IncludeCredentials
295 || (m_request->credentials() == FetchRequestData::SameOriginCredentials && !m_corsFlag)) {
296 resourceLoaderOptions.allowCredentials = AllowStoredCredentials;
297 }
298
299 ThreadableLoaderOptions threadableLoaderOptions;
300 if (m_corsPreflightFlag)
301 threadableLoaderOptions.preflightPolicy = ForcePreflight;
302 if (m_corsFlag)
303 threadableLoaderOptions.crossOriginRequestPolicy = UseAccessControl;
304 else
305 threadableLoaderOptions.crossOriginRequestPolicy = AllowCrossOriginReque sts;
306
307
308 m_loader = ThreadableLoader::create(*m_executionContext, this, request, thre adableLoaderOptions, resourceLoaderOptions);
309 }
310
136 void FetchManager::Loader::failed() 311 void FetchManager::Loader::failed()
137 { 312 {
138 if (m_failed) 313 if (m_failed)
139 return; 314 return;
140 m_failed = true; 315 m_failed = true;
141 ScriptState* state = m_resolver->scriptState(); 316 ScriptState* state = m_resolver->scriptState();
142 ScriptState::Scope scope(state); 317 ScriptState::Scope scope(state);
143 m_resolver->reject(V8ThrowException::createTypeError("Failed to fetch", stat e->isolate())); 318 m_resolver->reject(V8ThrowException::createTypeError("Failed to fetch", stat e->isolate()));
144 notifyFinished(); 319 notifyFinished();
145 } 320 }
146 321
147 void FetchManager::Loader::notifyFinished() 322 void FetchManager::Loader::notifyFinished()
148 { 323 {
149 if (m_fetchManager) 324 if (m_fetchManager)
150 m_fetchManager->onLoaderFinished(this); 325 m_fetchManager->onLoaderFinished(this);
151 } 326 }
152 327
153 FetchManager::FetchManager(ExecutionContext* executionContext) 328 FetchManager::FetchManager(ExecutionContext* executionContext)
154 : m_executionContext(executionContext) 329 : m_executionContext(executionContext)
155 { 330 {
156 } 331 }
157 332
158 FetchManager::~FetchManager() 333 FetchManager::~FetchManager()
159 { 334 {
160 for (HashSet<OwnPtr<Loader> >::iterator it = m_loaders.begin(); it != m_load ers.end(); ++it) { 335 for (HashSet<OwnPtr<Loader> >::iterator it = m_loaders.begin(); it != m_load ers.end(); ++it) {
161 (*it)->cleanup(); 336 (*it)->cleanup();
162 } 337 }
163 } 338 }
164 339
165 ScriptPromise FetchManager::fetch(ScriptState* scriptState, PassOwnPtr<ResourceR equest> request) 340 ScriptPromise FetchManager::fetch(ScriptState* scriptState, PassRefPtr<FetchRequ estData> request)
166 { 341 {
167 RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scrip tState); 342 RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scrip tState);
168 ScriptPromise promise = resolver->promise(); 343 ScriptPromise promise = resolver->promise();
169 344
170 OwnPtr<Loader> loader(adoptPtr(new Loader(m_executionContext, this, resolver .release(), request))); 345 OwnPtr<Loader> ownLoader(adoptPtr(new Loader(m_executionContext, this, resol ver.release(), request)));
171 (*m_loaders.add(loader.release()).storedValue)->start(); 346 Loader* loader = m_loaders.add(ownLoader.release()).storedValue->get();
347 loader->start();
172 return promise; 348 return promise;
173 } 349 }
174 350
175 void FetchManager::onLoaderFinished(Loader* loader) 351 void FetchManager::onLoaderFinished(Loader* loader)
176 { 352 {
177 m_loaders.remove(loader); 353 m_loaders.remove(loader);
178 } 354 }
179 355
180 bool FetchManager::isSimpleMethod(const String& method) 356 bool FetchManager::isSimpleMethod(const String& method)
181 { 357 {
182 // "A simple method is a method that is `GET`, `HEAD`, or `POST`." 358 // "A simple method is a method that is `GET`, `HEAD`, or `POST`."
183 return isOnAccessControlSimpleRequestMethodWhitelist(method); 359 return isOnAccessControlSimpleRequestMethodWhitelist(method);
184 } 360 }
185 361
186 bool FetchManager::isForbiddenMethod(const String& method) 362 bool FetchManager::isForbiddenMethod(const String& method)
187 { 363 {
188 // "A forbidden method is a method that is a byte case-insensitive match for one of `CONNECT`, `TRACE`, and `TRACK`." 364 // "A forbidden method is a method that is a byte case-insensitive match for
365 // one of `CONNECT`, `TRACE`, and `TRACK`."
189 return !XMLHttpRequest::isAllowedHTTPMethod(method); 366 return !XMLHttpRequest::isAllowedHTTPMethod(method);
190 } 367 }
191 368
192 bool FetchManager::isUsefulMethod(const String& method) 369 bool FetchManager::isUsefulMethod(const String& method)
193 { 370 {
194 // "A useful method is a method that is not a forbidden method." 371 // "A useful method is a method that is not a forbidden method."
195 // "A forbidden method is a method that is a byte case-insensitive match for one of `CONNECT`, `TRACE`, and `TRACK`." 372 // "A forbidden method is a method that is a byte case-insensitive match for
373 // one of `CONNECT`, `TRACE`, and `TRACK`."
196 return XMLHttpRequest::isAllowedHTTPMethod(method); 374 return XMLHttpRequest::isAllowedHTTPMethod(method);
197 } 375 }
198 376
199 } // namespace blink 377 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698