bacca19878f1aed52818ef5d235c4ed4c09d9776
[WebKit-https.git] / Source / WebCore / loader / cache / CachedResourceRequest.cpp
1 /*
2  * Copyright (C) 2012 Google, Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "CachedResourceRequest.h"
28
29 #include "CachedResourceLoader.h"
30 #include "ContentExtensionActions.h"
31 #include "CrossOriginAccessControl.h"
32 #include "Document.h"
33 #include "Element.h"
34 #include "HTTPHeaderValues.h"
35 #include "MemoryCache.h"
36 #include <wtf/NeverDestroyed.h>
37
38 namespace WebCore {
39
40 CachedResourceRequest::CachedResourceRequest(ResourceRequest&& resourceRequest, const ResourceLoaderOptions& options, Optional<ResourceLoadPriority> priority, String&& charset)
41     : m_resourceRequest(WTFMove(resourceRequest))
42     , m_charset(WTFMove(charset))
43     , m_options(options)
44     , m_priority(priority)
45     , m_fragmentIdentifier(splitFragmentIdentifierFromRequestURL(m_resourceRequest))
46 {
47 }
48
49 String CachedResourceRequest::splitFragmentIdentifierFromRequestURL(ResourceRequest& request)
50 {
51     if (!MemoryCache::shouldRemoveFragmentIdentifier(request.url()))
52         return { };
53     URL url = request.url();
54     String fragmentIdentifier = url.fragmentIdentifier();
55     url.removeFragmentIdentifier();
56     request.setURL(url);
57     return fragmentIdentifier;
58 }
59
60 void CachedResourceRequest::setInitiator(PassRefPtr<Element> element)
61 {
62     ASSERT(!m_initiatorElement && m_initiatorName.isEmpty());
63     m_initiatorElement = element;
64 }
65
66 void CachedResourceRequest::setInitiator(const AtomicString& name)
67 {
68     ASSERT(!m_initiatorElement && m_initiatorName.isEmpty());
69     m_initiatorName = name;
70 }
71
72 const AtomicString& CachedResourceRequest::initiatorName() const
73 {
74     if (m_initiatorElement)
75         return m_initiatorElement->localName();
76     if (!m_initiatorName.isEmpty())
77         return m_initiatorName;
78
79     static NeverDestroyed<AtomicString> defaultName("resource", AtomicString::ConstructFromLiteral);
80     return defaultName;
81 }
82
83 void CachedResourceRequest::setAsPotentiallyCrossOrigin(const String& mode, Document& document)
84 {
85     ASSERT(m_options.mode == FetchOptions::Mode::NoCors);
86     ASSERT(document.securityOrigin());
87
88     m_origin = document.securityOrigin();
89
90     if (mode.isNull())
91         return;
92     m_options.mode = FetchOptions::Mode::Cors;
93     m_options.credentials = equalLettersIgnoringASCIICase(mode, "use-credentials") ? FetchOptions::Credentials::Include : FetchOptions::Credentials::SameOrigin;
94     m_options.allowCredentials = equalLettersIgnoringASCIICase(mode, "use-credentials") ? AllowStoredCredentials : DoNotAllowStoredCredentials;
95
96     WebCore::updateRequestForAccessControl(m_resourceRequest, *document.securityOrigin(), m_options.allowCredentials);
97 }
98
99 void CachedResourceRequest::updateForAccessControl(Document& document)
100 {
101     ASSERT(m_options.mode == FetchOptions::Mode::Cors);
102     ASSERT(document.securityOrigin());
103
104     m_origin = document.securityOrigin();
105     WebCore::updateRequestForAccessControl(m_resourceRequest, *document.securityOrigin(), m_options.allowCredentials);
106 }
107
108 void upgradeInsecureResourceRequestIfNeeded(ResourceRequest& request, Document& document)
109 {
110     URL url = request.url();
111
112     ASSERT(document.contentSecurityPolicy());
113     document.contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(url, ContentSecurityPolicy::InsecureRequestType::Load);
114
115     if (url == request.url())
116         return;
117
118     request.setURL(url);
119 }
120
121 void CachedResourceRequest::upgradeInsecureRequestIfNeeded(Document& document)
122 {
123     upgradeInsecureResourceRequestIfNeeded(m_resourceRequest, document);
124 }
125
126 #if ENABLE(CACHE_PARTITIONING)
127 void CachedResourceRequest::setDomainForCachePartition(Document& document)
128 {
129     ASSERT(document.topOrigin());
130     m_resourceRequest.setDomainForCachePartition(document.topOrigin()->domainForCachePartition());
131 }
132 #endif
133
134 static inline String acceptHeaderValueFromType(CachedResource::Type type)
135 {
136     switch (type) {
137     case CachedResource::Type::MainResource:
138         return ASCIILiteral("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
139     case CachedResource::Type::ImageResource:
140         return ASCIILiteral("image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5");
141     case CachedResource::Type::CSSStyleSheet:
142         return ASCIILiteral("text/css,*/*;q=0.1");
143     case CachedResource::Type::SVGDocumentResource:
144         return ASCIILiteral("image/svg+xml");
145 #if ENABLE(XSLT)
146     case CachedResource::Type::XSLStyleSheet:
147         // FIXME: This should accept more general xml formats */*+xml, image/svg+xml for example.
148         return ASCIILiteral("text/xml,application/xml,application/xhtml+xml,text/xsl,application/rss+xml,application/atom+xml");
149 #endif
150     default:
151         return ASCIILiteral("*/*");
152     }
153 }
154
155 void CachedResourceRequest::setAcceptHeaderIfNone(CachedResource::Type type)
156 {
157     if (!m_resourceRequest.hasHTTPHeader(HTTPHeaderName::Accept))
158         m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::Accept, acceptHeaderValueFromType(type));
159 }
160
161 void CachedResourceRequest::updateAccordingCacheMode()
162 {
163     if (m_options.cache == FetchOptions::Cache::Default
164         && (m_resourceRequest.hasHTTPHeaderField(HTTPHeaderName::IfModifiedSince)
165             || m_resourceRequest.hasHTTPHeaderField(HTTPHeaderName::IfNoneMatch)
166             || m_resourceRequest.hasHTTPHeaderField(HTTPHeaderName::IfUnmodifiedSince)
167             || m_resourceRequest.hasHTTPHeaderField(HTTPHeaderName::IfMatch)
168             || m_resourceRequest.hasHTTPHeaderField(HTTPHeaderName::IfRange)))
169         m_options.cache = FetchOptions::Cache::NoStore;
170
171     switch (m_options.cache) {
172     case FetchOptions::Cache::NoCache:
173         m_resourceRequest.setCachePolicy(RefreshAnyCacheData);
174         m_resourceRequest.addHTTPHeaderFieldIfNotPresent(HTTPHeaderName::CacheControl, HTTPHeaderValues::maxAge0());
175         break;
176     case FetchOptions::Cache::NoStore:
177         m_options.cachingPolicy = CachingPolicy::DisallowCaching;
178         m_resourceRequest.setCachePolicy(DoNotUseAnyCache);
179         m_resourceRequest.addHTTPHeaderFieldIfNotPresent(HTTPHeaderName::Pragma, HTTPHeaderValues::noCache());
180         m_resourceRequest.addHTTPHeaderFieldIfNotPresent(HTTPHeaderName::CacheControl, HTTPHeaderValues::noCache());
181         break;
182     case FetchOptions::Cache::Reload:
183         m_resourceRequest.setCachePolicy(ReloadIgnoringCacheData);
184         m_resourceRequest.addHTTPHeaderFieldIfNotPresent(HTTPHeaderName::Pragma, HTTPHeaderValues::noCache());
185         m_resourceRequest.addHTTPHeaderFieldIfNotPresent(HTTPHeaderName::CacheControl, HTTPHeaderValues::noCache());
186         break;
187     case FetchOptions::Cache::Default:
188         break;
189     case FetchOptions::Cache::ForceCache:
190         m_resourceRequest.setCachePolicy(ReturnCacheDataElseLoad);
191         break;
192     case FetchOptions::Cache::OnlyIfCached:
193         m_resourceRequest.setCachePolicy(ReturnCacheDataDontLoad);
194         break;
195     }
196 }
197
198 void CachedResourceRequest::removeFragmentIdentifierIfNeeded()
199 {
200     URL url = MemoryCache::removeFragmentIdentifierIfNeeded(m_resourceRequest.url());
201     if (url.string() != m_resourceRequest.url())
202         m_resourceRequest.setURL(url);
203 }
204
205 #if ENABLE(CONTENT_EXTENSIONS)
206 void CachedResourceRequest::applyBlockedStatus(const ContentExtensions::BlockedStatus& blockedStatus)
207 {
208     ContentExtensions::applyBlockedStatusToRequest(blockedStatus, m_resourceRequest);
209 }
210 #endif
211
212 } // namespace WebCore