1/*
2 * Copyright (C) 2006, 2008, 2016 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 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 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 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#pragma once
28
29#include "CacheValidation.h"
30#include "CertificateInfo.h"
31#include "HTTPHeaderMap.h"
32#include "NetworkLoadMetrics.h"
33#include "ParsedContentRange.h"
34#include <wtf/Markable.h>
35#include <wtf/URL.h>
36#include <wtf/WallTime.h>
37
38namespace WebCore {
39
40class ResourceResponse;
41
42bool isScriptAllowedByNosniff(const ResourceResponse&);
43
44// Do not use this class directly, use the class ResponseResponse instead
45class ResourceResponseBase {
46 WTF_MAKE_FAST_ALLOCATED;
47public:
48 enum class Type : uint8_t { Basic, Cors, Default, Error, Opaque, Opaqueredirect };
49 enum class Tainting : uint8_t { Basic, Cors, Opaque, Opaqueredirect };
50
51 static bool isRedirectionStatusCode(int code) { return code == 301 || code == 302 || code == 303 || code == 307 || code == 308; }
52
53 struct CrossThreadData {
54 CrossThreadData(const CrossThreadData&) = delete;
55 CrossThreadData& operator=(const CrossThreadData&) = delete;
56 CrossThreadData() = default;
57 CrossThreadData(CrossThreadData&&) = default;
58
59 URL url;
60 String mimeType;
61 long long expectedContentLength;
62 String textEncodingName;
63 int httpStatusCode;
64 String httpStatusText;
65 String httpVersion;
66 HTTPHeaderMap httpHeaderFields;
67 NetworkLoadMetrics networkLoadMetrics;
68 Type type;
69 Tainting tainting;
70 bool isRedirected;
71 };
72
73 CrossThreadData crossThreadData() const;
74 static ResourceResponse fromCrossThreadData(CrossThreadData&&);
75
76 bool isNull() const { return m_isNull; }
77 WEBCORE_EXPORT bool isHTTP() const;
78 WEBCORE_EXPORT bool isSuccessful() const;
79
80 WEBCORE_EXPORT const URL& url() const;
81 WEBCORE_EXPORT void setURL(const URL&);
82
83 WEBCORE_EXPORT const String& mimeType() const;
84 WEBCORE_EXPORT void setMimeType(const String& mimeType);
85
86 WEBCORE_EXPORT long long expectedContentLength() const;
87 WEBCORE_EXPORT void setExpectedContentLength(long long expectedContentLength);
88
89 WEBCORE_EXPORT const String& textEncodingName() const;
90 WEBCORE_EXPORT void setTextEncodingName(const String& name);
91
92 WEBCORE_EXPORT int httpStatusCode() const;
93 WEBCORE_EXPORT void setHTTPStatusCode(int);
94 WEBCORE_EXPORT bool isRedirection() const;
95
96 WEBCORE_EXPORT const String& httpStatusText() const;
97 WEBCORE_EXPORT void setHTTPStatusText(const String&);
98
99 WEBCORE_EXPORT const String& httpVersion() const;
100 WEBCORE_EXPORT void setHTTPVersion(const String&);
101 WEBCORE_EXPORT bool isHTTP09() const;
102
103 WEBCORE_EXPORT const HTTPHeaderMap& httpHeaderFields() const;
104 void setHTTPHeaderFields(HTTPHeaderMap&&);
105
106 enum class SanitizationType { Redirection, RemoveCookies, CrossOriginSafe };
107 WEBCORE_EXPORT void sanitizeHTTPHeaderFields(SanitizationType);
108
109 String httpHeaderField(const String& name) const;
110 WEBCORE_EXPORT String httpHeaderField(HTTPHeaderName) const;
111 WEBCORE_EXPORT void setHTTPHeaderField(const String& name, const String& value);
112 WEBCORE_EXPORT void setHTTPHeaderField(HTTPHeaderName, const String& value);
113
114 WEBCORE_EXPORT void addHTTPHeaderField(HTTPHeaderName, const String& value);
115 WEBCORE_EXPORT void addHTTPHeaderField(const String& name, const String& value);
116
117 // Instead of passing a string literal to any of these functions, just use a HTTPHeaderName instead.
118 template<size_t length> String httpHeaderField(const char (&)[length]) const = delete;
119 template<size_t length> void setHTTPHeaderField(const char (&)[length], const String&) = delete;
120 template<size_t length> void addHTTPHeaderField(const char (&)[length], const String&) = delete;
121
122 bool isMultipart() const { return mimeType() == "multipart/x-mixed-replace"; }
123
124 WEBCORE_EXPORT bool isAttachment() const;
125 WEBCORE_EXPORT bool isAttachmentWithFilename() const;
126 WEBCORE_EXPORT String suggestedFilename() const;
127 WEBCORE_EXPORT static String sanitizeSuggestedFilename(const String&);
128
129 WEBCORE_EXPORT void includeCertificateInfo() const;
130 const Optional<CertificateInfo>& certificateInfo() const { return m_certificateInfo; };
131
132 // These functions return parsed values of the corresponding response headers.
133 WEBCORE_EXPORT bool cacheControlContainsNoCache() const;
134 WEBCORE_EXPORT bool cacheControlContainsNoStore() const;
135 WEBCORE_EXPORT bool cacheControlContainsMustRevalidate() const;
136 WEBCORE_EXPORT bool cacheControlContainsImmutable() const;
137 WEBCORE_EXPORT bool hasCacheValidatorFields() const;
138 WEBCORE_EXPORT Optional<Seconds> cacheControlMaxAge() const;
139 WEBCORE_EXPORT Optional<WallTime> date() const;
140 WEBCORE_EXPORT Optional<Seconds> age() const;
141 WEBCORE_EXPORT Optional<WallTime> expires() const;
142 WEBCORE_EXPORT Optional<WallTime> lastModified() const;
143 const ParsedContentRange& contentRange() const;
144
145 enum class Source : uint8_t { Unknown, Network, DiskCache, DiskCacheAfterValidation, MemoryCache, MemoryCacheAfterValidation, ServiceWorker, ApplicationCache };
146 WEBCORE_EXPORT Source source() const;
147 void setSource(Source source)
148 {
149 ASSERT(source != Source::Unknown);
150 m_source = source;
151 }
152
153 // FIXME: This should be eliminated from ResourceResponse.
154 // Network loading metrics should be delivered via didFinishLoad
155 // and should not be part of the ResourceResponse.
156 NetworkLoadMetrics& deprecatedNetworkLoadMetrics() const { return m_networkLoadMetrics; }
157
158 // The ResourceResponse subclass may "shadow" this method to provide platform-specific memory usage information
159 unsigned memoryUsage() const
160 {
161 // average size, mostly due to URL and Header Map strings
162 return 1280;
163 }
164
165 WEBCORE_EXPORT void setType(Type);
166 Type type() const { return m_type; }
167
168 void setRedirected(bool isRedirected) { m_isRedirected = isRedirected; }
169 bool isRedirected() const { return m_isRedirected; }
170
171 void setTainting(Tainting tainting) { m_tainting = tainting; }
172 Tainting tainting() const { return m_tainting; }
173
174 static ResourceResponse filter(const ResourceResponse&);
175
176 WEBCORE_EXPORT static ResourceResponse syntheticRedirectResponse(const URL& fromURL, const URL& toURL);
177
178 static bool compare(const ResourceResponse&, const ResourceResponse&);
179
180 template<class Encoder> void encode(Encoder&) const;
181 template<class Decoder> static bool decode(Decoder&, ResourceResponseBase&);
182
183protected:
184 enum InitLevel {
185 Uninitialized,
186 CommonFieldsOnly,
187 AllFields
188 };
189
190 WEBCORE_EXPORT ResourceResponseBase();
191 WEBCORE_EXPORT ResourceResponseBase(const URL&, const String& mimeType, long long expectedLength, const String& textEncodingName);
192
193 WEBCORE_EXPORT void lazyInit(InitLevel) const;
194
195 // The ResourceResponse subclass should shadow these functions to lazily initialize platform specific fields
196 void platformLazyInit(InitLevel) { }
197 CertificateInfo platformCertificateInfo() const { return CertificateInfo(); };
198 String platformSuggestedFileName() const { return String(); }
199
200 static bool platformCompare(const ResourceResponse&, const ResourceResponse&) { return true; }
201
202private:
203 void parseCacheControlDirectives() const;
204 void updateHeaderParsedState(HTTPHeaderName);
205 void sanitizeHTTPHeaderFieldsAccordingToTainting();
206
207protected:
208 URL m_url;
209 AtomString m_mimeType;
210 long long m_expectedContentLength { 0 };
211 AtomString m_textEncodingName;
212 AtomString m_httpStatusText;
213 AtomString m_httpVersion;
214 HTTPHeaderMap m_httpHeaderFields;
215 mutable NetworkLoadMetrics m_networkLoadMetrics;
216
217 mutable Optional<CertificateInfo> m_certificateInfo;
218
219private:
220 mutable Markable<Seconds, Seconds::MarkableTraits> m_age;
221 mutable Markable<WallTime, WallTime::MarkableTraits> m_date;
222 mutable Markable<WallTime, WallTime::MarkableTraits> m_expires;
223 mutable Markable<WallTime, WallTime::MarkableTraits> m_lastModified;
224 mutable ParsedContentRange m_contentRange;
225 mutable CacheControlDirectives m_cacheControlDirectives;
226
227 mutable bool m_haveParsedCacheControlHeader : 1;
228 mutable bool m_haveParsedAgeHeader : 1;
229 mutable bool m_haveParsedDateHeader : 1;
230 mutable bool m_haveParsedExpiresHeader : 1;
231 mutable bool m_haveParsedLastModifiedHeader : 1;
232 mutable bool m_haveParsedContentRangeHeader : 1;
233 bool m_isRedirected : 1;
234protected:
235 bool m_isNull : 1;
236
237private:
238 Source m_source { Source::Unknown };
239 Type m_type { Type::Default };
240 Tainting m_tainting { Tainting::Basic };
241
242protected:
243 int m_httpStatusCode { 0 };
244};
245
246inline bool operator==(const ResourceResponse& a, const ResourceResponse& b) { return ResourceResponseBase::compare(a, b); }
247inline bool operator!=(const ResourceResponse& a, const ResourceResponse& b) { return !(a == b); }
248
249template<class Encoder>
250void ResourceResponseBase::encode(Encoder& encoder) const
251{
252 encoder << m_isNull;
253 if (m_isNull)
254 return;
255 lazyInit(AllFields);
256
257 encoder << m_url;
258 encoder << m_mimeType;
259 encoder << static_cast<int64_t>(m_expectedContentLength);
260 encoder << m_textEncodingName;
261 encoder << m_httpStatusText;
262 encoder << m_httpVersion;
263 encoder << m_httpHeaderFields;
264
265 // We don't want to put the networkLoadMetrics info
266 // into the disk cache, because we will never use the old info.
267 if (Encoder::isIPCEncoder)
268 encoder << m_networkLoadMetrics;
269
270 encoder << m_httpStatusCode;
271 encoder << m_certificateInfo;
272 encoder.encodeEnum(m_source);
273 encoder.encodeEnum(m_type);
274 encoder.encodeEnum(m_tainting);
275 encoder << m_isRedirected;
276}
277
278template<class Decoder>
279bool ResourceResponseBase::decode(Decoder& decoder, ResourceResponseBase& response)
280{
281 ASSERT(response.m_isNull);
282 bool responseIsNull;
283 if (!decoder.decode(responseIsNull))
284 return false;
285 if (responseIsNull)
286 return true;
287
288 if (!decoder.decode(response.m_url))
289 return false;
290 if (!decoder.decode(response.m_mimeType))
291 return false;
292 int64_t expectedContentLength;
293 if (!decoder.decode(expectedContentLength))
294 return false;
295 response.m_expectedContentLength = expectedContentLength;
296 if (!decoder.decode(response.m_textEncodingName))
297 return false;
298 if (!decoder.decode(response.m_httpStatusText))
299 return false;
300 if (!decoder.decode(response.m_httpVersion))
301 return false;
302 if (!decoder.decode(response.m_httpHeaderFields))
303 return false;
304 // The networkLoadMetrics info is only send over IPC and not stored in disk cache.
305 if (Decoder::isIPCDecoder && !decoder.decode(response.m_networkLoadMetrics))
306 return false;
307 if (!decoder.decode(response.m_httpStatusCode))
308 return false;
309 if (!decoder.decode(response.m_certificateInfo))
310 return false;
311 if (!decoder.decodeEnum(response.m_source))
312 return false;
313 if (!decoder.decodeEnum(response.m_type))
314 return false;
315 if (!decoder.decodeEnum(response.m_tainting))
316 return false;
317 bool isRedirected = false;
318 if (!decoder.decode(isRedirected))
319 return false;
320 response.m_isRedirected = isRedirected;
321 response.m_isNull = false;
322
323 return true;
324}
325
326} // namespace WebCore
327