Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / platform / network / ResourceResponseBase.cpp
1 /*
2  * Copyright (C) 2006, 2008 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 #include "config.h"
28 #include "ResourceResponseBase.h"
29
30 #include "CacheValidation.h"
31 #include "HTTPHeaderNames.h"
32 #include "HTTPParsers.h"
33 #include "ResourceResponse.h"
34 #include <wtf/CurrentTime.h>
35 #include <wtf/MathExtras.h>
36 #include <wtf/StdLibExtras.h>
37 #include <wtf/text/StringView.h>
38
39 namespace WebCore {
40
41 inline const ResourceResponse& ResourceResponseBase::asResourceResponse() const
42 {
43     return *static_cast<const ResourceResponse*>(this);
44 }
45
46 ResourceResponseBase::ResourceResponseBase()
47     : m_isNull(true)
48     , m_expectedContentLength(0)
49     , m_includesCertificateInfo(false)
50     , m_httpStatusCode(0)
51 {
52 }
53
54 ResourceResponseBase::ResourceResponseBase(const URL& url, const String& mimeType, long long expectedLength, const String& textEncodingName)
55     : m_isNull(false)
56     , m_url(url)
57     , m_mimeType(mimeType)
58     , m_expectedContentLength(expectedLength)
59     , m_textEncodingName(textEncodingName)
60     , m_includesCertificateInfo(true) // Empty but valid for synthetic responses.
61     , m_httpStatusCode(0)
62 {
63 }
64
65 std::unique_ptr<ResourceResponse> ResourceResponseBase::adopt(std::unique_ptr<CrossThreadResourceResponseData> data)
66 {
67     auto response = std::make_unique<ResourceResponse>();
68     response->setURL(data->m_url);
69     response->setMimeType(data->m_mimeType);
70     response->setExpectedContentLength(data->m_expectedContentLength);
71     response->setTextEncodingName(data->m_textEncodingName);
72
73     response->setHTTPStatusCode(data->m_httpStatusCode);
74     response->setHTTPStatusText(data->m_httpStatusText);
75
76     response->lazyInit(AllFields);
77     response->m_httpHeaderFields.adopt(WTFMove(data->m_httpHeaders));
78     response->m_resourceLoadTiming = data->m_resourceLoadTiming;
79     response->doPlatformAdopt(WTFMove(data));
80     return response;
81 }
82
83 std::unique_ptr<CrossThreadResourceResponseData> ResourceResponseBase::copyData() const
84 {
85     auto data = std::make_unique<CrossThreadResourceResponseData>();
86     data->m_url = url().isolatedCopy();
87     data->m_mimeType = mimeType().isolatedCopy();
88     data->m_expectedContentLength = expectedContentLength();
89     data->m_textEncodingName = textEncodingName().isolatedCopy();
90     data->m_httpStatusCode = httpStatusCode();
91     data->m_httpStatusText = httpStatusText().isolatedCopy();
92     data->m_httpHeaders = httpHeaderFields().copyData();
93     data->m_resourceLoadTiming = m_resourceLoadTiming;
94     return asResourceResponse().doPlatformCopyData(WTFMove(data));
95 }
96
97 bool ResourceResponseBase::isHTTP() const
98 {
99     lazyInit(CommonFieldsOnly);
100
101     String protocol = m_url.protocol();
102
103     return equalIgnoringCase(protocol, "http")  || equalIgnoringCase(protocol, "https");
104 }
105
106 const URL& ResourceResponseBase::url() const
107 {
108     lazyInit(CommonFieldsOnly);
109
110     return m_url; 
111 }
112
113 void ResourceResponseBase::setURL(const URL& url)
114 {
115     lazyInit(CommonFieldsOnly);
116     m_isNull = false;
117
118     m_url = url;
119
120     // FIXME: Should invalidate or update platform response if present.
121 }
122
123 const String& ResourceResponseBase::mimeType() const
124 {
125     lazyInit(CommonFieldsOnly);
126
127     return m_mimeType; 
128 }
129
130 void ResourceResponseBase::setMimeType(const String& mimeType)
131 {
132     lazyInit(CommonFieldsOnly);
133     m_isNull = false;
134
135     // FIXME: MIME type is determined by HTTP Content-Type header. We should update the header, so that it doesn't disagree with m_mimeType.
136     m_mimeType = mimeType;
137
138     // FIXME: Should invalidate or update platform response if present.
139 }
140
141 long long ResourceResponseBase::expectedContentLength() const 
142 {
143     lazyInit(CommonFieldsOnly);
144
145     return m_expectedContentLength;
146 }
147
148 void ResourceResponseBase::setExpectedContentLength(long long expectedContentLength)
149 {
150     lazyInit(CommonFieldsOnly);
151     m_isNull = false;
152
153     // FIXME: Content length is determined by HTTP Content-Length header. We should update the header, so that it doesn't disagree with m_expectedContentLength.
154     m_expectedContentLength = expectedContentLength; 
155
156     // FIXME: Should invalidate or update platform response if present.
157 }
158
159 const String& ResourceResponseBase::textEncodingName() const
160 {
161     lazyInit(CommonFieldsOnly);
162
163     return m_textEncodingName;
164 }
165
166 void ResourceResponseBase::setTextEncodingName(const String& encodingName)
167 {
168     lazyInit(CommonFieldsOnly);
169     m_isNull = false;
170
171     // FIXME: Text encoding is determined by HTTP Content-Type header. We should update the header, so that it doesn't disagree with m_textEncodingName.
172     m_textEncodingName = encodingName;
173
174     // FIXME: Should invalidate or update platform response if present.
175 }
176
177 void ResourceResponseBase::includeCertificateInfo() const
178 {
179     if (m_includesCertificateInfo)
180         return;
181     m_certificateInfo = static_cast<const ResourceResponse*>(this)->platformCertificateInfo();
182     m_includesCertificateInfo = true;
183 }
184
185 CertificateInfo ResourceResponseBase::certificateInfo() const
186 {
187     return m_certificateInfo;
188 }
189
190 String ResourceResponseBase::suggestedFilename() const
191 {
192     return static_cast<const ResourceResponse*>(this)->platformSuggestedFilename();
193 }
194
195 int ResourceResponseBase::httpStatusCode() const
196 {
197     lazyInit(CommonFieldsOnly);
198
199     return m_httpStatusCode;
200 }
201
202 void ResourceResponseBase::setHTTPStatusCode(int statusCode)
203 {
204     lazyInit(CommonFieldsOnly);
205
206     m_httpStatusCode = statusCode;
207
208     // FIXME: Should invalidate or update platform response if present.
209 }
210
211 const String& ResourceResponseBase::httpStatusText() const 
212 {
213     lazyInit(AllFields);
214
215     return m_httpStatusText; 
216 }
217
218 void ResourceResponseBase::setHTTPStatusText(const String& statusText) 
219 {
220     lazyInit(AllFields);
221
222     m_httpStatusText = statusText; 
223
224     // FIXME: Should invalidate or update platform response if present.
225 }
226
227 String ResourceResponseBase::httpHeaderField(const String& name) const
228 {
229     lazyInit(CommonFieldsOnly);
230
231     // If we already have the header, just return it instead of consuming memory by grabing all headers.
232     String value = m_httpHeaderFields.get(name);
233     if (!value.isEmpty())        
234         return value;
235
236     lazyInit(AllFields);
237
238     return m_httpHeaderFields.get(name); 
239 }
240
241 String ResourceResponseBase::httpHeaderField(HTTPHeaderName name) const
242 {
243     lazyInit(CommonFieldsOnly);
244
245     // If we already have the header, just return it instead of consuming memory by grabing all headers.
246     String value = m_httpHeaderFields.get(name);
247     if (!value.isEmpty())
248         return value;
249
250     lazyInit(AllFields);
251
252     return m_httpHeaderFields.get(name); 
253 }
254
255 void ResourceResponseBase::updateHeaderParsedState(HTTPHeaderName name)
256 {
257     switch (name) {
258     case HTTPHeaderName::Age:
259         m_haveParsedAgeHeader = false;
260         break;
261
262     case HTTPHeaderName::CacheControl:
263     case HTTPHeaderName::Pragma:
264         m_haveParsedCacheControlHeader = false;
265         break;
266
267     case HTTPHeaderName::Date:
268         m_haveParsedDateHeader = false;
269         break;
270
271     case HTTPHeaderName::Expires:
272         m_haveParsedExpiresHeader = false;
273         break;
274
275     case HTTPHeaderName::LastModified:
276         m_haveParsedLastModifiedHeader = false;
277         break;
278
279     default:
280         break;
281     }
282 }
283
284 void ResourceResponseBase::setHTTPHeaderField(const String& name, const String& value)
285 {
286     lazyInit(AllFields);
287
288     HTTPHeaderName headerName;
289     if (findHTTPHeaderName(name, headerName))
290         updateHeaderParsedState(headerName);
291
292     m_httpHeaderFields.set(name, value);
293
294     // FIXME: Should invalidate or update platform response if present.
295 }
296
297 void ResourceResponseBase::setHTTPHeaderField(HTTPHeaderName name, const String& value)
298 {
299     lazyInit(AllFields);
300
301     updateHeaderParsedState(name);
302
303     m_httpHeaderFields.set(name, value);
304
305     // FIXME: Should invalidate or update platform response if present.
306 }
307
308 void ResourceResponseBase::addHTTPHeaderField(const String& name, const String& value)
309 {
310     lazyInit(AllFields);
311
312     HTTPHeaderName headerName;
313     if (findHTTPHeaderName(name, headerName))
314         updateHeaderParsedState(headerName);
315
316     m_httpHeaderFields.add(name, value);
317 }
318
319 const HTTPHeaderMap& ResourceResponseBase::httpHeaderFields() const
320 {
321     lazyInit(AllFields);
322
323     return m_httpHeaderFields;
324 }
325
326 void ResourceResponseBase::parseCacheControlDirectives() const
327 {
328     ASSERT(!m_haveParsedCacheControlHeader);
329
330     lazyInit(CommonFieldsOnly);
331
332     m_cacheControlDirectives = WebCore::parseCacheControlDirectives(m_httpHeaderFields);
333     m_haveParsedCacheControlHeader = true;
334 }
335     
336 bool ResourceResponseBase::cacheControlContainsNoCache() const
337 {
338     if (!m_haveParsedCacheControlHeader)
339         parseCacheControlDirectives();
340     return m_cacheControlDirectives.noCache;
341 }
342
343 bool ResourceResponseBase::cacheControlContainsNoStore() const
344 {
345     if (!m_haveParsedCacheControlHeader)
346         parseCacheControlDirectives();
347     return m_cacheControlDirectives.noStore;
348 }
349
350 bool ResourceResponseBase::cacheControlContainsMustRevalidate() const
351 {
352     if (!m_haveParsedCacheControlHeader)
353         parseCacheControlDirectives();
354     return m_cacheControlDirectives.mustRevalidate;
355 }
356
357 bool ResourceResponseBase::hasCacheValidatorFields() const
358 {
359     lazyInit(CommonFieldsOnly);
360
361     return !m_httpHeaderFields.get(HTTPHeaderName::LastModified).isEmpty() || !m_httpHeaderFields.get(HTTPHeaderName::ETag).isEmpty();
362 }
363
364 Optional<std::chrono::microseconds> ResourceResponseBase::cacheControlMaxAge() const
365 {
366     if (!m_haveParsedCacheControlHeader)
367         parseCacheControlDirectives();
368     return m_cacheControlDirectives.maxAge;
369 }
370
371 static Optional<std::chrono::system_clock::time_point> parseDateValueInHeader(const HTTPHeaderMap& headers, HTTPHeaderName headerName)
372 {
373     String headerValue = headers.get(headerName);
374     if (headerValue.isEmpty())
375         return { };
376     // This handles all date formats required by RFC2616:
377     // Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
378     // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
379     // Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
380     return parseHTTPDate(headerValue);
381 }
382
383 Optional<std::chrono::system_clock::time_point> ResourceResponseBase::date() const
384 {
385     lazyInit(CommonFieldsOnly);
386
387     if (!m_haveParsedDateHeader) {
388         m_date = parseDateValueInHeader(m_httpHeaderFields, HTTPHeaderName::Date);
389         m_haveParsedDateHeader = true;
390     }
391     return m_date;
392 }
393
394 Optional<std::chrono::microseconds> ResourceResponseBase::age() const
395 {
396     using namespace std::chrono;
397
398     lazyInit(CommonFieldsOnly);
399
400     if (!m_haveParsedAgeHeader) {
401         String headerValue = m_httpHeaderFields.get(HTTPHeaderName::Age);
402         bool ok;
403         double ageDouble = headerValue.toDouble(&ok);
404         if (ok)
405             m_age = duration_cast<microseconds>(duration<double>(ageDouble));
406         m_haveParsedAgeHeader = true;
407     }
408     return m_age;
409 }
410
411 Optional<std::chrono::system_clock::time_point> ResourceResponseBase::expires() const
412 {
413     lazyInit(CommonFieldsOnly);
414
415     if (!m_haveParsedExpiresHeader) {
416         m_expires = parseDateValueInHeader(m_httpHeaderFields, HTTPHeaderName::Expires);
417         m_haveParsedExpiresHeader = true;
418     }
419     return m_expires;
420 }
421
422 Optional<std::chrono::system_clock::time_point> ResourceResponseBase::lastModified() const
423 {
424     lazyInit(CommonFieldsOnly);
425
426     if (!m_haveParsedLastModifiedHeader) {
427         m_lastModified = parseDateValueInHeader(m_httpHeaderFields, HTTPHeaderName::LastModified);
428 #if PLATFORM(COCOA)
429         // CFNetwork converts malformed dates into Epoch so we need to treat Epoch as
430         // an invalid value (rdar://problem/22352838).
431         const std::chrono::system_clock::time_point epoch;
432         if (m_lastModified && m_lastModified.value() == epoch)
433             m_lastModified = Nullopt;
434 #endif
435         m_haveParsedLastModifiedHeader = true;
436     }
437     return m_lastModified;
438 }
439
440 bool ResourceResponseBase::isAttachment() const
441 {
442     lazyInit(AllFields);
443
444     String value = m_httpHeaderFields.get(HTTPHeaderName::ContentDisposition);
445     size_t loc = value.find(';');
446     if (loc != notFound)
447         value = value.left(loc);
448     value = value.stripWhiteSpace();
449
450     return equalIgnoringCase(value, "attachment");
451 }
452   
453 ResourceResponseBase::Source ResourceResponseBase::source() const
454 {
455     lazyInit(AllFields);
456
457     return m_source;
458 }
459
460 void ResourceResponseBase::setSource(Source source)
461 {
462     m_source = source;
463 }
464
465 void ResourceResponseBase::lazyInit(InitLevel initLevel) const
466 {
467     const_cast<ResourceResponse*>(static_cast<const ResourceResponse*>(this))->platformLazyInit(initLevel);
468 }
469
470 bool ResourceResponseBase::compare(const ResourceResponse& a, const ResourceResponse& b)
471 {
472     if (a.isNull() != b.isNull())
473         return false;  
474     if (a.url() != b.url())
475         return false;
476     if (a.mimeType() != b.mimeType())
477         return false;
478     if (a.expectedContentLength() != b.expectedContentLength())
479         return false;
480     if (a.textEncodingName() != b.textEncodingName())
481         return false;
482     if (a.suggestedFilename() != b.suggestedFilename())
483         return false;
484     if (a.httpStatusCode() != b.httpStatusCode())
485         return false;
486     if (a.httpStatusText() != b.httpStatusText())
487         return false;
488     if (a.httpHeaderFields() != b.httpHeaderFields())
489         return false;
490     if (a.resourceLoadTiming() != b.resourceLoadTiming())
491         return false;
492     return ResourceResponse::platformCompare(a, b);
493 }
494
495 }