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

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

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

Powered by Google App Engine
This is Rietveld 408576698