1 /*
2 * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
3 * Copyright (C) 2009, 2012 Google Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "config.h"
28 #include "platform/network/ResourceRequest.h"
29 #include "platform/weborigin/SecurityOrigin.h"
30 #include "public/platform/WebURLRequest.h"
31
32 namespace blink {
33
34 double ResourceRequest::s_defaultTimeoutInterval = INT_MAX;
35
adopt(PassOwnPtr<CrossThreadResourceRequestData> data)36 PassOwnPtr<ResourceRequest> ResourceRequest::adopt(PassOwnPtr<CrossThreadResourceRequestData> data)
37 {
38 OwnPtr<ResourceRequest> request = adoptPtr(new ResourceRequest());
39 request->setURL(data->m_url);
40 request->setCachePolicy(data->m_cachePolicy);
41 request->setTimeoutInterval(data->m_timeoutInterval);
42 request->setFirstPartyForCookies(data->m_firstPartyForCookies);
43 request->setHTTPMethod(AtomicString(data->m_httpMethod));
44 request->setPriority(data->m_priority, data->m_intraPriorityValue);
45
46 request->m_httpHeaderFields.adopt(data->m_httpHeaders.release());
47
48 request->setHTTPBody(data->m_httpBody);
49 request->setAllowStoredCredentials(data->m_allowStoredCredentials);
50 request->setReportUploadProgress(data->m_reportUploadProgress);
51 request->setHasUserGesture(data->m_hasUserGesture);
52 request->setDownloadToFile(data->m_downloadToFile);
53 request->setSkipServiceWorker(data->m_skipServiceWorker);
54 request->setRequestorID(data->m_requestorID);
55 request->setRequestorProcessID(data->m_requestorProcessID);
56 request->setAppCacheHostID(data->m_appCacheHostID);
57 request->setRequestContext(data->m_requestContext);
58 request->setFrameType(data->m_frameType);
59 request->m_referrerPolicy = data->m_referrerPolicy;
60 return request.release();
61 }
62
copyData() const63 PassOwnPtr<CrossThreadResourceRequestData> ResourceRequest::copyData() const
64 {
65 OwnPtr<CrossThreadResourceRequestData> data = adoptPtr(new CrossThreadResourceRequestData());
66 data->m_url = url().copy();
67 data->m_cachePolicy = cachePolicy();
68 data->m_timeoutInterval = timeoutInterval();
69 data->m_firstPartyForCookies = firstPartyForCookies().copy();
70 data->m_httpMethod = httpMethod().string().isolatedCopy();
71 data->m_httpHeaders = httpHeaderFields().copyData();
72 data->m_priority = priority();
73 data->m_intraPriorityValue = m_intraPriorityValue;
74
75 if (m_httpBody)
76 data->m_httpBody = m_httpBody->deepCopy();
77 data->m_allowStoredCredentials = m_allowStoredCredentials;
78 data->m_reportUploadProgress = m_reportUploadProgress;
79 data->m_hasUserGesture = m_hasUserGesture;
80 data->m_downloadToFile = m_downloadToFile;
81 data->m_skipServiceWorker = m_skipServiceWorker;
82 data->m_requestorID = m_requestorID;
83 data->m_requestorProcessID = m_requestorProcessID;
84 data->m_appCacheHostID = m_appCacheHostID;
85 data->m_requestContext = m_requestContext;
86 data->m_frameType = m_frameType;
87 data->m_referrerPolicy = m_referrerPolicy;
88 return data.release();
89 }
90
isEmpty() const91 bool ResourceRequest::isEmpty() const
92 {
93 return m_url.isEmpty();
94 }
95
isNull() const96 bool ResourceRequest::isNull() const
97 {
98 return m_url.isNull();
99 }
100
url() const101 const KURL& ResourceRequest::url() const
102 {
103 return m_url;
104 }
105
setURL(const KURL & url)106 void ResourceRequest::setURL(const KURL& url)
107 {
108 m_url = url;
109 }
110
removeCredentials()111 void ResourceRequest::removeCredentials()
112 {
113 if (m_url.user().isEmpty() && m_url.pass().isEmpty())
114 return;
115
116 m_url.setUser(String());
117 m_url.setPass(String());
118 }
119
cachePolicy() const120 ResourceRequestCachePolicy ResourceRequest::cachePolicy() const
121 {
122 return m_cachePolicy;
123 }
124
setCachePolicy(ResourceRequestCachePolicy cachePolicy)125 void ResourceRequest::setCachePolicy(ResourceRequestCachePolicy cachePolicy)
126 {
127 m_cachePolicy = cachePolicy;
128 }
129
timeoutInterval() const130 double ResourceRequest::timeoutInterval() const
131 {
132 return m_timeoutInterval;
133 }
134
setTimeoutInterval(double timeoutInterval)135 void ResourceRequest::setTimeoutInterval(double timeoutInterval)
136 {
137 m_timeoutInterval = timeoutInterval;
138 }
139
firstPartyForCookies() const140 const KURL& ResourceRequest::firstPartyForCookies() const
141 {
142 return m_firstPartyForCookies;
143 }
144
setFirstPartyForCookies(const KURL & firstPartyForCookies)145 void ResourceRequest::setFirstPartyForCookies(const KURL& firstPartyForCookies)
146 {
147 m_firstPartyForCookies = firstPartyForCookies;
148 }
149
httpMethod() const150 const AtomicString& ResourceRequest::httpMethod() const
151 {
152 return m_httpMethod;
153 }
154
setHTTPMethod(const AtomicString & httpMethod)155 void ResourceRequest::setHTTPMethod(const AtomicString& httpMethod)
156 {
157 m_httpMethod = httpMethod;
158 }
159
httpHeaderFields() const160 const HTTPHeaderMap& ResourceRequest::httpHeaderFields() const
161 {
162 return m_httpHeaderFields;
163 }
164
httpHeaderField(const AtomicString & name) const165 const AtomicString& ResourceRequest::httpHeaderField(const AtomicString& name) const
166 {
167 return m_httpHeaderFields.get(name);
168 }
169
httpHeaderField(const char * name) const170 const AtomicString& ResourceRequest::httpHeaderField(const char* name) const
171 {
172 return m_httpHeaderFields.get(name);
173 }
174
setHTTPHeaderField(const AtomicString & name,const AtomicString & value)175 void ResourceRequest::setHTTPHeaderField(const AtomicString& name, const AtomicString& value)
176 {
177 m_httpHeaderFields.set(name, value);
178 }
179
setHTTPHeaderField(const char * name,const AtomicString & value)180 void ResourceRequest::setHTTPHeaderField(const char* name, const AtomicString& value)
181 {
182 setHTTPHeaderField(AtomicString(name), value);
183 }
184
clearHTTPAuthorization()185 void ResourceRequest::clearHTTPAuthorization()
186 {
187 m_httpHeaderFields.remove("Authorization");
188 }
189
clearHTTPReferrer()190 void ResourceRequest::clearHTTPReferrer()
191 {
192 m_httpHeaderFields.remove("Referer");
193 m_referrerPolicy = ReferrerPolicyDefault;
194 }
195
clearHTTPOrigin()196 void ResourceRequest::clearHTTPOrigin()
197 {
198 m_httpHeaderFields.remove("Origin");
199 }
200
addHTTPOriginIfNeeded(const AtomicString & origin)201 void ResourceRequest::addHTTPOriginIfNeeded(const AtomicString& origin)
202 {
203 if (!httpOrigin().isEmpty())
204 return; // Request already has an Origin header.
205
206 // Don't send an Origin header for GET or HEAD to avoid privacy issues.
207 // For example, if an intranet page has a hyperlink to an external web
208 // site, we don't want to include the Origin of the request because it
209 // will leak the internal host name. Similar privacy concerns have lead
210 // to the widespread suppression of the Referer header at the network
211 // layer.
212 if (httpMethod() == "GET" || httpMethod() == "HEAD")
213 return;
214
215 // For non-GET and non-HEAD methods, always send an Origin header so the
216 // server knows we support this feature.
217
218 if (origin.isEmpty()) {
219 // If we don't know what origin header to attach, we attach the value
220 // for an empty origin.
221 setHTTPOrigin(SecurityOrigin::createUnique()->toAtomicString());
222 return;
223 }
224 setHTTPOrigin(origin);
225 }
226
clearHTTPUserAgent()227 void ResourceRequest::clearHTTPUserAgent()
228 {
229 m_httpHeaderFields.remove("User-Agent");
230 }
231
httpBody() const232 FormData* ResourceRequest::httpBody() const
233 {
234 return m_httpBody.get();
235 }
236
setHTTPBody(PassRefPtr<FormData> httpBody)237 void ResourceRequest::setHTTPBody(PassRefPtr<FormData> httpBody)
238 {
239 m_httpBody = httpBody;
240 }
241
allowStoredCredentials() const242 bool ResourceRequest::allowStoredCredentials() const
243 {
244 return m_allowStoredCredentials;
245 }
246
setAllowStoredCredentials(bool allowCredentials)247 void ResourceRequest::setAllowStoredCredentials(bool allowCredentials)
248 {
249 m_allowStoredCredentials = allowCredentials;
250 }
251
priority() const252 ResourceLoadPriority ResourceRequest::priority() const
253 {
254 return m_priority;
255 }
256
setPriority(ResourceLoadPriority priority,int intraPriorityValue)257 void ResourceRequest::setPriority(ResourceLoadPriority priority, int intraPriorityValue)
258 {
259 m_priority = priority;
260 m_intraPriorityValue = intraPriorityValue;
261 }
262
addHTTPHeaderField(const AtomicString & name,const AtomicString & value)263 void ResourceRequest::addHTTPHeaderField(const AtomicString& name, const AtomicString& value)
264 {
265 HTTPHeaderMap::AddResult result = m_httpHeaderFields.add(name, value);
266 if (!result.isNewEntry)
267 result.storedValue->value = result.storedValue->value + ',' + value;
268 }
269
addHTTPHeaderFields(const HTTPHeaderMap & headerFields)270 void ResourceRequest::addHTTPHeaderFields(const HTTPHeaderMap& headerFields)
271 {
272 HTTPHeaderMap::const_iterator end = headerFields.end();
273 for (HTTPHeaderMap::const_iterator it = headerFields.begin(); it != end; ++it)
274 addHTTPHeaderField(it->key, it->value);
275 }
276
clearHTTPHeaderField(const AtomicString & name)277 void ResourceRequest::clearHTTPHeaderField(const AtomicString& name)
278 {
279 m_httpHeaderFields.remove(name);
280 }
281
equalIgnoringHeaderFields(const ResourceRequest & a,const ResourceRequest & b)282 bool equalIgnoringHeaderFields(const ResourceRequest& a, const ResourceRequest& b)
283 {
284 if (a.url() != b.url())
285 return false;
286
287 if (a.cachePolicy() != b.cachePolicy())
288 return false;
289
290 if (a.timeoutInterval() != b.timeoutInterval())
291 return false;
292
293 if (a.firstPartyForCookies() != b.firstPartyForCookies())
294 return false;
295
296 if (a.httpMethod() != b.httpMethod())
297 return false;
298
299 if (a.allowStoredCredentials() != b.allowStoredCredentials())
300 return false;
301
302 if (a.priority() != b.priority())
303 return false;
304
305 if (a.referrerPolicy() != b.referrerPolicy())
306 return false;
307
308 FormData* formDataA = a.httpBody();
309 FormData* formDataB = b.httpBody();
310
311 if (!formDataA)
312 return !formDataB;
313 if (!formDataB)
314 return !formDataA;
315
316 if (*formDataA != *formDataB)
317 return false;
318
319 return true;
320 }
321
compare(const ResourceRequest & a,const ResourceRequest & b)322 bool ResourceRequest::compare(const ResourceRequest& a, const ResourceRequest& b)
323 {
324 if (!equalIgnoringHeaderFields(a, b))
325 return false;
326
327 if (a.httpHeaderFields() != b.httpHeaderFields())
328 return false;
329
330 return true;
331 }
332
isConditional() const333 bool ResourceRequest::isConditional() const
334 {
335 return (m_httpHeaderFields.contains("If-Match")
336 || m_httpHeaderFields.contains("If-Modified-Since")
337 || m_httpHeaderFields.contains("If-None-Match")
338 || m_httpHeaderFields.contains("If-Range")
339 || m_httpHeaderFields.contains("If-Unmodified-Since"));
340 }
341
342
cacheControlHeaderString()343 static const AtomicString& cacheControlHeaderString()
344 {
345 DEFINE_STATIC_LOCAL(const AtomicString, cacheControlHeader, ("cache-control", AtomicString::ConstructFromLiteral));
346 return cacheControlHeader;
347 }
348
pragmaHeaderString()349 static const AtomicString& pragmaHeaderString()
350 {
351 DEFINE_STATIC_LOCAL(const AtomicString, pragmaHeader, ("pragma", AtomicString::ConstructFromLiteral));
352 return pragmaHeader;
353 }
354
cacheControlHeader() const355 const CacheControlHeader& ResourceRequest::cacheControlHeader() const
356 {
357 if (!m_cacheControlHeaderCache.parsed)
358 m_cacheControlHeaderCache = parseCacheControlDirectives(m_httpHeaderFields.get(cacheControlHeaderString()), m_httpHeaderFields.get(pragmaHeaderString()));
359 return m_cacheControlHeaderCache;
360 }
361
cacheControlContainsNoCache() const362 bool ResourceRequest::cacheControlContainsNoCache() const
363 {
364 return cacheControlHeader().containsNoCache;
365 }
366
cacheControlContainsNoStore() const367 bool ResourceRequest::cacheControlContainsNoStore() const
368 {
369 return cacheControlHeader().containsNoStore;
370 }
371
hasCacheValidatorFields() const372 bool ResourceRequest::hasCacheValidatorFields() const
373 {
374 DEFINE_STATIC_LOCAL(const AtomicString, lastModifiedHeader, ("last-modified", AtomicString::ConstructFromLiteral));
375 DEFINE_STATIC_LOCAL(const AtomicString, eTagHeader, ("etag", AtomicString::ConstructFromLiteral));
376 return !m_httpHeaderFields.get(lastModifiedHeader).isEmpty() || !m_httpHeaderFields.get(eTagHeader).isEmpty();
377 }
378
defaultTimeoutInterval()379 double ResourceRequest::defaultTimeoutInterval()
380 {
381 return s_defaultTimeoutInterval;
382 }
383
setDefaultTimeoutInterval(double timeoutInterval)384 void ResourceRequest::setDefaultTimeoutInterval(double timeoutInterval)
385 {
386 s_defaultTimeoutInterval = timeoutInterval;
387 }
388
initialize(const KURL & url,ResourceRequestCachePolicy cachePolicy)389 void ResourceRequest::initialize(const KURL& url, ResourceRequestCachePolicy cachePolicy)
390 {
391 m_url = url;
392 m_cachePolicy = cachePolicy;
393 m_timeoutInterval = s_defaultTimeoutInterval;
394 m_httpMethod = "GET";
395 m_allowStoredCredentials = true;
396 m_reportUploadProgress = false;
397 m_reportRawHeaders = false;
398 m_hasUserGesture = false;
399 m_downloadToFile = false;
400 m_skipServiceWorker = false;
401 m_priority = ResourceLoadPriorityLow;
402 m_intraPriorityValue = 0;
403 m_requestorID = 0;
404 m_requestorProcessID = 0;
405 m_appCacheHostID = 0;
406 m_requestContext = blink::WebURLRequest::RequestContextUnspecified;
407 m_frameType = blink::WebURLRequest::FrameTypeNone;
408 m_referrerPolicy = ReferrerPolicyDefault;
409 }
410
411 // This is used by the loader to control the number of issued parallel load requests.
initializeMaximumHTTPConnectionCountPerHost()412 unsigned initializeMaximumHTTPConnectionCountPerHost()
413 {
414 // The chromium network stack already handles limiting the number of
415 // parallel requests per host, so there's no need to do it here. Therefore,
416 // this is set to a high value that should never be hit in practice.
417 return 10000;
418 }
419
420 }
421