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
32namespace blink {
33
34double ResourceRequest::s_defaultTimeoutInterval = INT_MAX;
35
36PassOwnPtr<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
63PassOwnPtr<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
91bool ResourceRequest::isEmpty() const
92{
93    return m_url.isEmpty();
94}
95
96bool ResourceRequest::isNull() const
97{
98    return m_url.isNull();
99}
100
101const KURL& ResourceRequest::url() const
102{
103    return m_url;
104}
105
106void ResourceRequest::setURL(const KURL& url)
107{
108    m_url = url;
109}
110
111void 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
120ResourceRequestCachePolicy ResourceRequest::cachePolicy() const
121{
122    return m_cachePolicy;
123}
124
125void ResourceRequest::setCachePolicy(ResourceRequestCachePolicy cachePolicy)
126{
127    m_cachePolicy = cachePolicy;
128}
129
130double ResourceRequest::timeoutInterval() const
131{
132    return m_timeoutInterval;
133}
134
135void ResourceRequest::setTimeoutInterval(double timeoutInterval)
136{
137    m_timeoutInterval = timeoutInterval;
138}
139
140const KURL& ResourceRequest::firstPartyForCookies() const
141{
142    return m_firstPartyForCookies;
143}
144
145void ResourceRequest::setFirstPartyForCookies(const KURL& firstPartyForCookies)
146{
147    m_firstPartyForCookies = firstPartyForCookies;
148}
149
150const AtomicString& ResourceRequest::httpMethod() const
151{
152    return m_httpMethod;
153}
154
155void ResourceRequest::setHTTPMethod(const AtomicString& httpMethod)
156{
157    m_httpMethod = httpMethod;
158}
159
160const HTTPHeaderMap& ResourceRequest::httpHeaderFields() const
161{
162    return m_httpHeaderFields;
163}
164
165const AtomicString& ResourceRequest::httpHeaderField(const AtomicString& name) const
166{
167    return m_httpHeaderFields.get(name);
168}
169
170const AtomicString& ResourceRequest::httpHeaderField(const char* name) const
171{
172    return m_httpHeaderFields.get(name);
173}
174
175void ResourceRequest::setHTTPHeaderField(const AtomicString& name, const AtomicString& value)
176{
177    m_httpHeaderFields.set(name, value);
178}
179
180void ResourceRequest::setHTTPHeaderField(const char* name, const AtomicString& value)
181{
182    setHTTPHeaderField(AtomicString(name), value);
183}
184
185void ResourceRequest::clearHTTPAuthorization()
186{
187    m_httpHeaderFields.remove("Authorization");
188}
189
190void ResourceRequest::clearHTTPReferrer()
191{
192    m_httpHeaderFields.remove("Referer");
193    m_referrerPolicy = ReferrerPolicyDefault;
194}
195
196void ResourceRequest::clearHTTPOrigin()
197{
198    m_httpHeaderFields.remove("Origin");
199}
200
201void 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
227void ResourceRequest::clearHTTPUserAgent()
228{
229    m_httpHeaderFields.remove("User-Agent");
230}
231
232FormData* ResourceRequest::httpBody() const
233{
234    return m_httpBody.get();
235}
236
237void ResourceRequest::setHTTPBody(PassRefPtr<FormData> httpBody)
238{
239    m_httpBody = httpBody;
240}
241
242bool ResourceRequest::allowStoredCredentials() const
243{
244    return m_allowStoredCredentials;
245}
246
247void ResourceRequest::setAllowStoredCredentials(bool allowCredentials)
248{
249    m_allowStoredCredentials = allowCredentials;
250}
251
252ResourceLoadPriority ResourceRequest::priority() const
253{
254    return m_priority;
255}
256
257void ResourceRequest::setPriority(ResourceLoadPriority priority, int intraPriorityValue)
258{
259    m_priority = priority;
260    m_intraPriorityValue = intraPriorityValue;
261}
262
263void 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
270void 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
277void ResourceRequest::clearHTTPHeaderField(const AtomicString& name)
278{
279    m_httpHeaderFields.remove(name);
280}
281
282bool 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
322bool 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
333bool 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
343static const AtomicString& cacheControlHeaderString()
344{
345    DEFINE_STATIC_LOCAL(const AtomicString, cacheControlHeader, ("cache-control", AtomicString::ConstructFromLiteral));
346    return cacheControlHeader;
347}
348
349static const AtomicString& pragmaHeaderString()
350{
351    DEFINE_STATIC_LOCAL(const AtomicString, pragmaHeader, ("pragma", AtomicString::ConstructFromLiteral));
352    return pragmaHeader;
353}
354
355const 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
362bool ResourceRequest::cacheControlContainsNoCache() const
363{
364    return cacheControlHeader().containsNoCache;
365}
366
367bool ResourceRequest::cacheControlContainsNoStore() const
368{
369    return cacheControlHeader().containsNoStore;
370}
371
372bool 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
379double ResourceRequest::defaultTimeoutInterval()
380{
381    return s_defaultTimeoutInterval;
382}
383
384void ResourceRequest::setDefaultTimeoutInterval(double timeoutInterval)
385{
386    s_defaultTimeoutInterval = timeoutInterval;
387}
388
389void 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.
412unsigned 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