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 "Request.h" | |
7 | |
8 #include "bindings/core/v8/Dictionary.h" | |
9 #include "core/dom/Document.h" | |
10 #include "core/dom/ExecutionContext.h" | |
11 #include "core/fetch/FetchUtils.h" | |
12 #include "core/fetch/ResourceLoaderOptions.h" | |
13 #include "core/loader/ThreadableLoader.h" | |
14 #include "modules/serviceworkers/FetchManager.h" | |
15 #include "modules/serviceworkers/RequestInit.h" | |
16 #include "platform/network/HTTPParsers.h" | |
17 #include "platform/network/ResourceRequest.h" | |
18 #include "platform/weborigin/Referrer.h" | |
19 #include "public/platform/WebServiceWorkerRequest.h" | |
20 #include "public/platform/WebURLRequest.h" | |
21 | |
22 namespace blink { | |
23 | |
24 FetchRequestData* createCopyOfFetchRequestDataForFetch(ExecutionContext* context
, const FetchRequestData* original) | |
25 { | |
26 FetchRequestData* request = FetchRequestData::create(); | |
27 request->setURL(original->url()); | |
28 request->setMethod(original->method()); | |
29 request->setHeaderList(original->headerList()->createCopy()); | |
30 request->setUnsafeRequestFlag(true); | |
31 request->setBlobDataHandle(original->blobDataHandle()); | |
32 // FIXME: Set client. | |
33 request->setOrigin(SecurityOrigin::create(context->url())); | |
34 // FIXME: Set ForceOriginHeaderFlag. | |
35 request->setSameOriginDataURLFlag(true); | |
36 request->mutableReferrer()->setClient(); | |
37 request->setContext(WebURLRequest::RequestContextFetch); | |
38 request->setMode(original->mode()); | |
39 request->setCredentials(original->credentials()); | |
40 // FIXME: Set cache mode. | |
41 return request; | |
42 } | |
43 | |
44 Request* Request::createRequestWithRequestOrString(ExecutionContext* context, Re
quest* inputRequest, const String& inputString, const RequestInit& init, Excepti
onState& exceptionState) | |
45 { | |
46 // "1. If input is a Request object, run these substeps:" | |
47 if (inputRequest) { | |
48 // "1. If input's used flag is set, throw a TypeError." | |
49 if (inputRequest->bodyUsed()) { | |
50 exceptionState.throwTypeError("Cannot construct a Request with a Req
uest object that has already been used."); | |
51 return 0; | |
52 } | |
53 // "2. Set input's used flag." | |
54 inputRequest->setBodyUsed(); | |
55 } | |
56 | |
57 // "2. Let |request| be |input|'s associated request, if |input| is a | |
58 // Request object, and a new request otherwise." | |
59 // "3. Set |request| to a new request whose url is |request|'s url, method | |
60 // is |request|'s method, header list is a copy of |request|'s header list, | |
61 // unsafe request flag is set, body is |request|'s body, client is entry | |
62 // settings object, origin is entry settings object's origin, force Origin | |
63 // header flag is set, same-origin data URL flag is set, referrer is client, | |
64 // context is fetch, mode is |request|'s mode, credentials mode is | |
65 // |request|'s credentials mode, and cache mode is |request|'s cache mode." | |
66 FetchRequestData* request = createCopyOfFetchRequestDataForFetch(context, in
putRequest ? inputRequest->request() : FetchRequestData::create()); | |
67 | |
68 // "4. Let |fallbackMode| be null." | |
69 // "5. Let |fallbackCredentials| be null." | |
70 // "6. Let |fallbackCache| be null." | |
71 // We don't use fallback values. We set these flags directly in below. | |
72 | |
73 // "7. If |input| is a string, run these substeps:" | |
74 if (!inputRequest) { | |
75 // "1. Let |parsedURL| be the result of parsing |input| with entry | |
76 // settings object's API base URL." | |
77 KURL parsedURL = context->completeURL(inputString); | |
78 // "2. If |parsedURL| is failure, throw a TypeError." | |
79 if (!parsedURL.isValid()) { | |
80 exceptionState.throwTypeError("Failed to parse URL from " + inputStr
ing); | |
81 return 0; | |
82 } | |
83 // "3. Set |request|'s url to |parsedURL|." | |
84 request->setURL(parsedURL); | |
85 // "4. Set |fallbackMode| to CORS." | |
86 // "5. Set |fallbackCredentials| to omit." | |
87 // "6. Set |fallbackCache| to default." | |
88 // We don't use fallback values. We set these flags directly in below. | |
89 } | |
90 | |
91 // "8. Let |mode| be |init|'s mode member if it is present, and | |
92 // |fallbackMode| otherwise." | |
93 // "9. If |mode| is non-null, set |request|'s mode to |mode|." | |
94 if (init.mode == "same-origin") { | |
95 request->setMode(WebURLRequest::FetchRequestModeSameOrigin); | |
96 } else if (init.mode == "no-cors") { | |
97 request->setMode(WebURLRequest::FetchRequestModeNoCORS); | |
98 } else if (init.mode == "cors") { | |
99 request->setMode(WebURLRequest::FetchRequestModeCORS); | |
100 } else { | |
101 if (!inputRequest) | |
102 request->setMode(WebURLRequest::FetchRequestModeCORS); | |
103 } | |
104 | |
105 // "10. Let |credentials| be |init|'s credentials member if it is present, | |
106 // and |fallbackCredentials| otherwise." | |
107 // "11. If |credentials| is non-null, set |request|'s credentials mode to | |
108 // |credentials|. | |
109 if (init.credentials == "omit") { | |
110 request->setCredentials(WebURLRequest::FetchCredentialsModeOmit); | |
111 } else if (init.credentials == "same-origin") { | |
112 request->setCredentials(WebURLRequest::FetchCredentialsModeSameOrigin); | |
113 } else if (init.credentials == "include") { | |
114 request->setCredentials(WebURLRequest::FetchCredentialsModeInclude); | |
115 } else { | |
116 if (!inputRequest) | |
117 request->setCredentials(WebURLRequest::FetchCredentialsModeOmit); | |
118 } | |
119 | |
120 // FIXME: "12. Let |cache| be |init|'s cache member if it is present, and | |
121 // |fallbackCache| otherwise." | |
122 // FIXME: "13. If |cache| is non-null, set |request|'s cache mode to | |
123 // |cache|." | |
124 | |
125 // "14. If |init|'s method member is present, let |method| be it and run | |
126 // these substeps:" | |
127 if (!init.method.isEmpty()) { | |
128 // "1. If |method| is not a method or method is a forbidden method, | |
129 // throw a TypeError." | |
130 if (!isValidHTTPToken(init.method)) { | |
131 exceptionState.throwTypeError("'" + init.method + "' is not a valid
HTTP method."); | |
132 return 0; | |
133 } | |
134 if (FetchUtils::isForbiddenMethod(init.method)) { | |
135 exceptionState.throwTypeError("'" + init.method + "' HTTP method is
unsupported."); | |
136 return 0; | |
137 } | |
138 // "2. Normalize |method|." | |
139 // "3. Set |request|'s method to |method|." | |
140 request->setMethod(FetchUtils::normalizeMethod(AtomicString(init.method)
)); | |
141 } | |
142 // "15. Let |r| be a new Request object associated with |request|, and a new | |
143 // Headers object." | |
144 Request* r = Request::create(context, request); | |
145 // "16. Let |headers| be a copy of |r|'s Headers object." | |
146 // "17. If |init|'s headers member is present, set |headers| to |init|'s | |
147 // headers member." | |
148 // We don't create a copy of r's Headers object when init's headers member | |
149 // is present. | |
150 Headers* headers = 0; | |
151 if (!init.headers && init.headersDictionary.isUndefinedOrNull()) { | |
152 headers = r->headers()->createCopy(); | |
153 } | |
154 // "18. Empty |r|'s request's header list." | |
155 r->clearHeaderList(); | |
156 // "19. If |r|'s request's mode is no CORS, run these substeps: | |
157 if (r->request()->mode() == WebURLRequest::FetchRequestModeNoCORS) { | |
158 // "1. If |r|'s request's method is not a simple method, throw a | |
159 // TypeError." | |
160 if (!FetchUtils::isSimpleMethod(r->request()->method())) { | |
161 exceptionState.throwTypeError("'" + r->request()->method() + "' is u
nsupported in no-cors mode."); | |
162 return 0; | |
163 } | |
164 // "Set |r|'s Headers object's guard to |request-no-CORS|. | |
165 r->headers()->setGuard(Headers::RequestNoCORSGuard); | |
166 } | |
167 // "20. Fill |r|'s Headers object with |headers|. Rethrow any exceptions." | |
168 if (init.headers) { | |
169 ASSERT(init.headersDictionary.isUndefinedOrNull()); | |
170 r->headers()->fillWith(init.headers.get(), exceptionState); | |
171 } else if (!init.headersDictionary.isUndefinedOrNull()) { | |
172 r->headers()->fillWith(init.headersDictionary, exceptionState); | |
173 } else { | |
174 ASSERT(headers); | |
175 r->headers()->fillWith(headers, exceptionState); | |
176 } | |
177 if (exceptionState.hadException()) | |
178 return 0; | |
179 | |
180 // "21. If |init|'s body member is present, run these substeps:" | |
181 if (init.bodyBlobHandle) { | |
182 // "1. Let |stream| and |Content-Type| be the result of extracting | |
183 // |init|'s body member." | |
184 // "2. Set |r|'s request's body to |stream|." | |
185 // "3.If |Content-Type| is non-null and |r|'s request's header list | |
186 // contains no header named `Content-Type`, append | |
187 // `Content-Type`/|Content-Type| to |r|'s Headers object. Rethrow any | |
188 // exception." | |
189 r->setBodyBlobHandle(init.bodyBlobHandle); | |
190 if (!init.bodyBlobHandle->type().isEmpty() && !r->headers()->has("Conten
t-Type", exceptionState)) { | |
191 r->headers()->append("Content-Type", init.bodyBlobHandle->type(), ex
ceptionState); | |
192 } | |
193 if (exceptionState.hadException()) | |
194 return 0; | |
195 } | |
196 // "22. Set |r|'s MIME type to the result of extracting a MIME type from | |
197 // |r|'s request's header list." | |
198 // FIXME: We don't have MIME type in Request object yet. | |
199 | |
200 // "23. Return |r|." | |
201 return r; | |
202 } | |
203 | |
204 Request* Request::create(ExecutionContext* context, const RequestInfo& input, co
nst Dictionary& init, ExceptionState& exceptionState) | |
205 { | |
206 ASSERT(!input.isNull()); | |
207 if (input.isUSVString()) | |
208 return create(context, input.getAsUSVString(), init, exceptionState); | |
209 return create(context, input.getAsRequest(), init, exceptionState); | |
210 } | |
211 | |
212 Request* Request::create(ExecutionContext* context, const String& input, Excepti
onState& exceptionState) | |
213 { | |
214 return create(context, input, Dictionary(), exceptionState); | |
215 } | |
216 | |
217 Request* Request::create(ExecutionContext* context, const String& input, const D
ictionary& init, ExceptionState& exceptionState) | |
218 { | |
219 return createRequestWithRequestOrString(context, 0, input, RequestInit(conte
xt, init, exceptionState), exceptionState); | |
220 } | |
221 | |
222 Request* Request::create(ExecutionContext* context, Request* input, ExceptionSta
te& exceptionState) | |
223 { | |
224 return create(context, input, Dictionary(), exceptionState); | |
225 } | |
226 | |
227 Request* Request::create(ExecutionContext* context, Request* input, const Dictio
nary& init, ExceptionState& exceptionState) | |
228 { | |
229 return createRequestWithRequestOrString(context, input, String(), RequestIni
t(context, init, exceptionState), exceptionState); | |
230 } | |
231 | |
232 Request* Request::create(ExecutionContext* context, FetchRequestData* request) | |
233 { | |
234 Request* r = new Request(context, request); | |
235 r->suspendIfNeeded(); | |
236 return r; | |
237 } | |
238 | |
239 Request::Request(ExecutionContext* context, FetchRequestData* request) | |
240 : Body(context) | |
241 , m_request(request) | |
242 , m_headers(Headers::create(m_request->headerList())) | |
243 { | |
244 m_headers->setGuard(Headers::RequestGuard); | |
245 } | |
246 | |
247 Request* Request::create(ExecutionContext* context, const WebServiceWorkerReques
t& webRequest) | |
248 { | |
249 Request* r = new Request(context, webRequest); | |
250 r->suspendIfNeeded(); | |
251 return r; | |
252 } | |
253 | |
254 Request* Request::create(const Request& copyFrom) | |
255 { | |
256 Request* r = new Request(copyFrom); | |
257 r->suspendIfNeeded(); | |
258 return r; | |
259 } | |
260 | |
261 Request::Request(ExecutionContext* context, const WebServiceWorkerRequest& webRe
quest) | |
262 : Body(context) | |
263 , m_request(FetchRequestData::create(webRequest)) | |
264 , m_headers(Headers::create(m_request->headerList())) | |
265 { | |
266 m_headers->setGuard(Headers::RequestGuard); | |
267 } | |
268 | |
269 Request::Request(const Request& copy_from) | |
270 : Body(copy_from) | |
271 , m_request(copy_from.m_request->createCopy()) | |
272 , m_headers(Headers::create(m_request->headerList())) | |
273 { | |
274 } | |
275 | |
276 | |
277 String Request::method() const | |
278 { | |
279 // "The method attribute's getter must return request's method." | |
280 return m_request->method(); | |
281 } | |
282 | |
283 String Request::url() const | |
284 { | |
285 // The url attribute's getter must return request's url, serialized with the
exclude fragment flag set. | |
286 if (!m_request->url().hasFragmentIdentifier()) | |
287 return m_request->url(); | |
288 KURL url(m_request->url()); | |
289 url.removeFragmentIdentifier(); | |
290 return url; | |
291 } | |
292 | |
293 String Request::referrer() const | |
294 { | |
295 // "The referrer attribute's getter must return the empty string if | |
296 // request's referrer is no referrer, "about:client" if request's referrer | |
297 // is client and request's referrer, serialized, otherwise." | |
298 if (m_request->referrer().isNoReferrer()) | |
299 return String(); | |
300 if (m_request->referrer().isClient()) | |
301 return String("about:client"); | |
302 return m_request->referrer().referrer().referrer; | |
303 } | |
304 | |
305 String Request::mode() const | |
306 { | |
307 // "The mode attribute's getter must return the value corresponding to the | |
308 // first matching statement, switching on request's mode:" | |
309 switch (m_request->mode()) { | |
310 case WebURLRequest::FetchRequestModeSameOrigin: | |
311 return "same-origin"; | |
312 case WebURLRequest::FetchRequestModeNoCORS: | |
313 return "no-cors"; | |
314 case WebURLRequest::FetchRequestModeCORS: | |
315 case WebURLRequest::FetchRequestModeCORSWithForcedPreflight: | |
316 return "cors"; | |
317 } | |
318 ASSERT_NOT_REACHED(); | |
319 return ""; | |
320 } | |
321 | |
322 String Request::credentials() const | |
323 { | |
324 // "The credentials attribute's getter must return the value corresponding | |
325 // to the first matching statement, switching on request's credentials | |
326 // mode:" | |
327 switch (m_request->credentials()) { | |
328 case WebURLRequest::FetchCredentialsModeOmit: | |
329 return "omit"; | |
330 case WebURLRequest::FetchCredentialsModeSameOrigin: | |
331 return "same-origin"; | |
332 case WebURLRequest::FetchCredentialsModeInclude: | |
333 return "include"; | |
334 } | |
335 ASSERT_NOT_REACHED(); | |
336 return ""; | |
337 } | |
338 | |
339 Request* Request::clone(ExceptionState& exceptionState) const | |
340 { | |
341 if (bodyUsed()) { | |
342 exceptionState.throwTypeError("Request body is already used"); | |
343 return nullptr; | |
344 } | |
345 if (streamAccessed()) { | |
346 // FIXME: Support clone() of the stream accessed Request. | |
347 exceptionState.throwTypeError("clone() of the Request which .body is acc
essed is not supported."); | |
348 return nullptr; | |
349 } | |
350 return Request::create(*this); | |
351 } | |
352 | |
353 void Request::populateWebServiceWorkerRequest(WebServiceWorkerRequest& webReques
t) const | |
354 { | |
355 webRequest.setMethod(method()); | |
356 webRequest.setURL(m_request->url()); | |
357 | |
358 const FetchHeaderList* headerList = m_headers->headerList(); | |
359 for (size_t i = 0, size = headerList->size(); i < size; ++i) { | |
360 const FetchHeaderList::Header& header = headerList->entry(i); | |
361 webRequest.appendHeader(header.first, header.second); | |
362 } | |
363 | |
364 webRequest.setReferrer(m_request->referrer().referrer().referrer, static_cas
t<WebReferrerPolicy>(m_request->referrer().referrer().referrerPolicy)); | |
365 // FIXME: How can we set isReload properly? What is the correct place to loa
d it in to the Request object? We should investigate the right way | |
366 // to plumb this information in to here. | |
367 } | |
368 | |
369 void Request::setBodyBlobHandle(PassRefPtr<BlobDataHandle> blobDataHandle) | |
370 { | |
371 m_request->setBlobDataHandle(blobDataHandle); | |
372 } | |
373 | |
374 void Request::clearHeaderList() | |
375 { | |
376 m_request->headerList()->clearList(); | |
377 } | |
378 | |
379 PassRefPtr<BlobDataHandle> Request::blobDataHandle() const | |
380 { | |
381 return m_request->blobDataHandle(); | |
382 } | |
383 | |
384 BodyStreamBuffer* Request::buffer() const | |
385 { | |
386 return nullptr; | |
387 } | |
388 | |
389 String Request::contentTypeForBuffer() const | |
390 { | |
391 // We don't support BodyStreamBuffer for Request yet. | |
392 ASSERT_NOT_REACHED(); | |
393 return String(); | |
394 } | |
395 | |
396 void Request::trace(Visitor* visitor) | |
397 { | |
398 Body::trace(visitor); | |
399 visitor->trace(m_request); | |
400 visitor->trace(m_headers); | |
401 } | |
402 | |
403 } // namespace blink | |
OLD | NEW |