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

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: cleanup test 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 WebCore { 25 namespace WebCore {
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 performeHTTPFetch();
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;
81 return;
71 } 82 }
72 83
73 void FetchManager::Loader::didFinishLoading(unsigned long, double) 84 void FetchManager::Loader::didFinishLoading(unsigned long, double)
74 { 85 {
75 OwnPtr<BlobData> blobData = BlobData::create(); 86 OwnPtr<BlobData> blobData = BlobData::create();
76 String filePath = m_response.downloadedFilePath(); 87 String filePath = m_response.downloadedFilePath();
77 if (!filePath.isEmpty() && m_downloadedBlobLength) { 88 if (!filePath.isEmpty() && m_downloadedBlobLength) {
78 blobData->appendFile(filePath); 89 blobData->appendFile(filePath);
79 blobData->setContentType(m_response.mimeType()); 90 blobData->setContentType(m_response.mimeType());
80 } 91 }
81 ResponseInit responseInit; 92 RefPtr<FetchResponseData> response(FetchResponseData::create());
82 // FIXME: We may have to filter the status when we support CORS. 93 response->setStatus(m_response.httpStatusCode());
83 // http://fetch.spec.whatwg.org/#concept-filtered-response-opaque 94 response->setStatusMessage(m_response.httpStatusText());
84 responseInit.status = m_response.httpStatusCode(); 95 HTTPHeaderMap::const_iterator end = m_response.httpHeaderFields().end();
85 responseInit.statusText = m_response.httpStatusText(); 96 for (HTTPHeaderMap::const_iterator it = m_response.httpHeaderFields().begin( ); it != end; ++it) {
86 // FIXME: fill options. 97 response->headerList()->append(it->key, it->value);
87 RefPtrWillBeRawPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData .release(), m_downloadedBlobLength)); 98 }
88 // FIXME: Handle response status correctly. 99 response->setBlobDataHandle(BlobDataHandle::create(blobData.release(), m_dow nloadedBlobLength));
89 NonThrowableExceptionState exceptionState; 100 response->setURL(m_request->url());
90 m_resolver->resolve(Response::create(blob.get(), responseInit, exceptionStat e)); 101
102 switch (m_request->tainting()) {
103 case FetchRequestData::BasicTainting:
104 response = response->createBasicFilteredResponse();
105 break;
106 case FetchRequestData::CORSTainting:
107 response = response->createCORSFilteredResponse();
108 break;
109 case FetchRequestData::OpaqueTainting:
110 response = response->createOpaqueFilteredResponse();
111 break;
112 }
113 m_resolver->resolve(Response::create(response.release()));
91 notifyFinished(); 114 notifyFinished();
92 } 115 }
93 116
94 void FetchManager::Loader::didFail(const ResourceError& error) 117 void FetchManager::Loader::didFail(const ResourceError& error)
95 { 118 {
96 failed(); 119 failed();
97 } 120 }
98 121
99 void FetchManager::Loader::didFailAccessControlCheck(const ResourceError& error) 122 void FetchManager::Loader::didFailAccessControlCheck(const ResourceError& error)
100 { 123 {
101 failed(); 124 failed();
102 } 125 }
103 126
104 void FetchManager::Loader::didFailRedirectCheck() 127 void FetchManager::Loader::didFailRedirectCheck()
105 { 128 {
106 failed(); 129 failed();
107 } 130 }
108 131
109 void FetchManager::Loader::didDownloadData(int dataLength) 132 void FetchManager::Loader::didDownloadData(int dataLength)
110 { 133 {
111 m_downloadedBlobLength += dataLength; 134 m_downloadedBlobLength += dataLength;
112 } 135 }
113 136
114 void FetchManager::Loader::start() 137 void FetchManager::Loader::start()
115 { 138 {
116 m_request->setDownloadToFile(true); 139
117 ThreadableLoaderOptions options; 140 // "1. If |request|'s url contains a Known HSTS Host, modify it perthe
118 // FIXME: Fill options. 141 // requirements of the 'URI [sic] Loading and Port Mapping' chapter of HTTP
119 ResourceLoaderOptions resourceLoaderOptions; 142 // Strict Transport Security."
120 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; 143 // FIXME: Implement this.
121 // FIXME: Fill resourceLoaderOptions. 144
122 m_loader = ThreadableLoader::create(*m_executionContext, this, *m_request, o ptions, resourceLoaderOptions); 145 // "2. If |request|'s referrer is not none, set |request|'s referrer to the
146 // result of invoking determine |request|'s referrer."
147 // We set the referrer using workerGlobalScope's URL in
148 // WorkerThreadableLoader.
149
150 // "3. If |request|'s synchronous flag is unset and fetch is not invoked
151 // recursively, run the remaining steps asynchronously."
152 // FIXME: We don't support synchronous flag.
153
154 // "4. Let response be the value corresponding to the first matching
155 // statement:"
156
157 // "- should fetching |request| be blocked as mixed content returns blocked
158 // - should fetching |request| be blocked as content security returns
159 // blocked
160 // A network error."
161 // We do mixed content checking and CSP checking in ResourceFetcher.
162
163 // "- |request|'s url's origin is |request|'s origin and the |CORS flag| is unset
164 // "- |request|'s url's scheme is 'data' and |request|'s same-origin data UR L
165 // 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().protocol() == "data" && m_request->sameOriginDataUR LFlag())
169 || (m_request->url().protocol() == "about")) {
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().protocol() != "http" && m_request->url().protocol() != "https") {
193 // "A network error."
194 performNetworkError();
195 return;
196 }
197
198 // "- |request|'s mode is |CORS-with-forced-preflight|.
199 if (m_request->mode() == FetchRequestData::CORSWithForcedPreflight) {
200 // "Set |request|'s response tainting to |CORS|."
201 m_request->setResponseTainting(FetchRequestData::CORSTainting);
202 // "The result of performing an HTTP fetch using |request| with the
203 // |CORS flag| and |CORS preflight flag| set."
204 m_corsFlag = true;
205 m_corsPreflightFlag = true;
206 performeHTTPFetch();
207 return;
208 }
209
210 // "- |request|'s unsafe request flag is set and either |request|'s method
211 // is not a simple method or a header in |request|'s header list is not a
212 // simple header"
213 if (m_request->unsafeRequestFlag()
214 && (!isSimpleMethod(m_request->method())
215 || m_request->headerList()->containsNonSimpleHeader())) {
216 // "Set |request|'s response tainting to |CORS|."
217 m_request->setResponseTainting(FetchRequestData::CORSTainting);
218 // "The result of performing an HTTP fetch using |request| with the
219 // |CORS flag| and |CORS preflight flag| set."
220 m_corsFlag = true;
221 m_corsPreflightFlag = true;
222 performeHTTPFetch();
223 return;
224 }
225
226 // "- Otherwise
227 // Set |request|'s response tainting to |CORS|."
228 m_request->setResponseTainting(FetchRequestData::CORSTainting);
229 // "The result of performing an HTTP fetch using |request| with the
230 // |CORS flag| set."
231 m_corsFlag = true;
232 m_corsPreflightFlag = false;
233 performeHTTPFetch();
123 } 234 }
124 235
125 void FetchManager::Loader::cleanup() 236 void FetchManager::Loader::cleanup()
126 { 237 {
127 // Prevent notification 238 // Prevent notification
128 m_fetchManager = 0; 239 m_fetchManager = 0;
129 240
130 if (m_loader) { 241 if (m_loader) {
131 m_loader->cancel(); 242 m_loader->cancel();
132 m_loader.clear(); 243 m_loader.clear();
133 } 244 }
134 } 245 }
135 246
247 void FetchManager::Loader::performBasicFetch()
248 {
249 // "To perform a basic fetch using |request|, switch on |request|'s url's
250 // scheme, and run the associated steps:"
251 String protocol(m_request->url().protocol());
252 if (protocol == "about") {
253 // FIXME: implement this.
254 performNetworkError();
255 } else if (protocol == "blob") {
256 // FIXME: implement this.
257 performNetworkError();
258 } else if (protocol == "data") {
259 // FIXME: implement this.
260 performNetworkError();
261 } else if (protocol == "file" || protocol == "ftp") {
262 // "For now, unfortunate as it is, file and ftp URLs are left as an
263 // exercise for the reader. When in doubt, return a network error."
264 // FIXME: implement this.
265 performNetworkError();
266 } else if (protocol == "http" || protocol == "https") {
267 // "Return the result of performing an HTTP fetch using |request|."
268 m_corsFlag = false;
269 m_corsPreflightFlag = false;
270 performeHTTPFetch();
271 } else {
272 // "Return a network error."
273 performNetworkError();
274 }
275 }
276
277 void FetchManager::Loader::performNetworkError()
278 {
279 failed();
280 }
281
282 void FetchManager::Loader::performeHTTPFetch()
283 {
284 // "1. Let |HTTPRequest| be a copy of |request|, except that |HTTPRequest|'s
285 // body is a tee of |request|'s body."
286 // We use ResourceRequest class for HTTPRequest.
287 // FIXME: Support body.
288 ResourceRequest request(m_request->url());
289 request.setRequestContext(blink::WebURLRequest::RequestContextFetch);
290 request.setDownloadToFile(true);
291 request.setHTTPMethod(m_request->method());
292 const Vector<OwnPtr<FetchHeaderList::Header> >& list = m_request->headerList ()->list();
293 for (size_t i = 0; i < list.size(); ++i) {
294 request.addHTTPHeaderField(AtomicString(list[i]->first), AtomicString(li st[i]->second));
295 }
296
297 // "2. Append `Referer`/empty byte sequence, if |HTTPRequest|'s |referrer|
298 // is none, and `Referer`/|HTTPRequest|'s referrer, serialized and utf-8
299 // encoded, otherwise, to HTTPRequest's header list.
300 // We set the referrer using workerGlobalScope's URL in
301 // WorkerThreadableLoader.
302
303 // "3. Append `Host`, ..."
304 // FIXME: Implement this when the spec is fixed.
305
306 // "4.If |HTTPRequest|'s force Origin header flag is set, append `Origin`/
307 // |HTTPRequest|'s origin, serialized and utf-8 encoded, to |HTTPRequest|'s
308 // header list."
309 // FIXME: We don't support Origin header yet.
310
311 // "5. Let |credentials flag| be set if either |HTTPRequest|'s credentials
312 // mode is |include|, or |HTTPRequest|'s credentials mode is |same-origin|
313 // and the |CORS flag| is unset, and unset otherwise.
314 ResourceLoaderOptions resourceLoaderOptions;
315 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
316 if (m_request->credentials() == FetchRequestData::IncludeCredentials
317 || (m_request->credentials() == FetchRequestData::SameOriginCredentials && !m_corsFlag)) {
318 resourceLoaderOptions.allowCredentials = AllowStoredCredentials;
319 }
320 if (m_request->credentials() == FetchRequestData::IncludeCredentials)
321 resourceLoaderOptions.credentialsRequested = ClientRequestedCredentials;
322
323 ThreadableLoaderOptions threadableLoaderOptions;
324 if (m_corsPreflightFlag)
325 threadableLoaderOptions.preflightPolicy = ForcePreflight;
326 if (m_corsFlag)
327 threadableLoaderOptions.crossOriginRequestPolicy = UseAccessControl;
328 else
329 threadableLoaderOptions.crossOriginRequestPolicy = AllowCrossOriginReque sts;
330
331
332 m_loader = ThreadableLoader::create(*m_executionContext, this, request, thre adableLoaderOptions, resourceLoaderOptions);
333 }
334
136 void FetchManager::Loader::failed() 335 void FetchManager::Loader::failed()
137 { 336 {
138 if (m_failed) 337 if (m_failed)
139 return; 338 return;
140 m_failed = true; 339 m_failed = true;
141 ScriptState* state = m_resolver->scriptState(); 340 ScriptState* state = m_resolver->scriptState();
142 ScriptState::Scope scope(state); 341 ScriptState::Scope scope(state);
143 m_resolver->reject(V8ThrowException::createTypeError("Failed to fetch", stat e->isolate())); 342 m_resolver->reject(V8ThrowException::createTypeError("Failed to fetch", stat e->isolate()));
144 notifyFinished(); 343 notifyFinished();
145 } 344 }
146 345
147 void FetchManager::Loader::notifyFinished() 346 void FetchManager::Loader::notifyFinished()
148 { 347 {
149 if (m_fetchManager) 348 if (m_fetchManager)
150 m_fetchManager->onLoaderFinished(this); 349 m_fetchManager->onLoaderFinished(this);
151 } 350 }
152 351
153 FetchManager::FetchManager(ExecutionContext* executionContext) 352 FetchManager::FetchManager(ExecutionContext* executionContext)
154 : m_executionContext(executionContext) 353 : m_executionContext(executionContext)
155 { 354 {
156 } 355 }
157 356
158 FetchManager::~FetchManager() 357 FetchManager::~FetchManager()
159 { 358 {
160 for (HashSet<OwnPtr<Loader> >::iterator it = m_loaders.begin(); it != m_load ers.end(); ++it) { 359 for (HashSet<OwnPtr<Loader> >::iterator it = m_loaders.begin(); it != m_load ers.end(); ++it) {
161 (*it)->cleanup(); 360 (*it)->cleanup();
162 } 361 }
163 } 362 }
164 363
165 ScriptPromise FetchManager::fetch(ScriptState* scriptState, PassOwnPtr<ResourceR equest> request) 364 ScriptPromise FetchManager::fetch(ScriptState* scriptState, PassRefPtr<FetchRequ estData> request)
166 { 365 {
167 RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scrip tState); 366 RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scrip tState);
168 ScriptPromise promise = resolver->promise(); 367 ScriptPromise promise = resolver->promise();
169 368
170 OwnPtr<Loader> loader(adoptPtr(new Loader(m_executionContext, this, resolver .release(), request))); 369 OwnPtr<Loader> ownLoader(adoptPtr(new Loader(m_executionContext, this, resol ver.release(), request)));
171 (*m_loaders.add(loader.release()).storedValue)->start(); 370 Loader* loader = m_loaders.add(ownLoader.release()).storedValue->get();
371 loader->start();
172 return promise; 372 return promise;
173 } 373 }
174 374
175 void FetchManager::onLoaderFinished(Loader* loader) 375 void FetchManager::onLoaderFinished(Loader* loader)
176 { 376 {
177 m_loaders.remove(loader); 377 m_loaders.remove(loader);
178 } 378 }
179 379
180 bool FetchManager::isSimpleMethod(const String& method) 380 bool FetchManager::isSimpleMethod(const String& method)
181 { 381 {
182 // "A simple method is a method that is `GET`, `HEAD`, or `POST`." 382 // "A simple method is a method that is `GET`, `HEAD`, or `POST`."
183 return isOnAccessControlSimpleRequestMethodWhitelist(method); 383 return isOnAccessControlSimpleRequestMethodWhitelist(method);
184 } 384 }
185 385
186 bool FetchManager::isForbiddenMethod(const String& method) 386 bool FetchManager::isForbiddenMethod(const String& method)
187 { 387 {
188 // "A forbidden method is a method that is a byte case-insensitive match for one of `CONNECT`, `TRACE`, and `TRACK`." 388 // "A forbidden method is a method that is a byte case-insensitive match for
389 // one of `CONNECT`, `TRACE`, and `TRACK`."
189 return !XMLHttpRequest::isAllowedHTTPMethod(method); 390 return !XMLHttpRequest::isAllowedHTTPMethod(method);
190 } 391 }
191 392
192 bool FetchManager::isUsefulMethod(const String& method) 393 bool FetchManager::isUsefulMethod(const String& method)
193 { 394 {
194 // "A useful method is a method that is not a forbidden method." 395 // "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`." 396 // "A forbidden method is a method that is a byte case-insensitive match for
397 // one of `CONNECT`, `TRACE`, and `TRACK`."
196 return XMLHttpRequest::isAllowedHTTPMethod(method); 398 return XMLHttpRequest::isAllowedHTTPMethod(method);
197 } 399 }
198 400
199 } // namespace WebCore 401 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/modules/serviceworkers/FetchManager.h ('k') | Source/modules/serviceworkers/FetchRequestData.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698