[WTF] Move currentCPUTime and sleep(Seconds) to CPUTime.h and Seconds.h respectively
[WebKit-https.git] / Source / WebCore / loader / cache / CachedCSSStyleSheet.cpp
1 /*
2     Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
3     Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
4     Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
5     Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
6     Copyright (C) 2004-2017 Apple Inc. All rights reserved.
7
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Library General Public
10     License as published by the Free Software Foundation; either
11     version 2 of the License, or (at your option) any later version.
12
13     This library is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16     Library General Public License for more details.
17
18     You should have received a copy of the GNU Library General Public License
19     along with this library; see the file COPYING.LIB.  If not, write to
20     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21     Boston, MA 02110-1301, USA.
22 */
23
24 #include "config.h"
25 #include "CachedCSSStyleSheet.h"
26
27 #include "CSSStyleSheet.h"
28 #include "CachedResourceClientWalker.h"
29 #include "CachedResourceRequest.h"
30 #include "CachedStyleSheetClient.h"
31 #include "HTTPHeaderNames.h"
32 #include "HTTPParsers.h"
33 #include "MemoryCache.h"
34 #include "SharedBuffer.h"
35 #include "StyleSheetContents.h"
36 #include "TextResourceDecoder.h"
37
38 namespace WebCore {
39
40 CachedCSSStyleSheet::CachedCSSStyleSheet(CachedResourceRequest&& request, PAL::SessionID sessionID)
41     : CachedResource(WTFMove(request), CSSStyleSheet, sessionID)
42     , m_decoder(TextResourceDecoder::create("text/css", request.charset()))
43 {
44 }
45
46 CachedCSSStyleSheet::~CachedCSSStyleSheet()
47 {
48     if (m_parsedStyleSheetCache)
49         m_parsedStyleSheetCache->removedFromMemoryCache();
50 }
51
52 void CachedCSSStyleSheet::didAddClient(CachedResourceClient& client)
53 {
54     ASSERT(client.resourceClientType() == CachedStyleSheetClient::expectedType());
55     // CachedResource::didAddClient() must be before setCSSStyleSheet(),
56     // because setCSSStyleSheet() may cause scripts to be executed, which could destroy 'c' if it is an instance of HTMLLinkElement.
57     // see the comment of HTMLLinkElement::setCSSStyleSheet.
58     CachedResource::didAddClient(client);
59
60     if (!isLoading())
61         static_cast<CachedStyleSheetClient&>(client).setCSSStyleSheet(m_resourceRequest.url(), m_response.url(), m_decoder->encoding().name(), this);
62 }
63
64 void CachedCSSStyleSheet::setEncoding(const String& chs)
65 {
66     m_decoder->setEncoding(chs, TextResourceDecoder::EncodingFromHTTPHeader);
67 }
68
69 String CachedCSSStyleSheet::encoding() const
70 {
71     return m_decoder->encoding().name();
72 }
73
74 const String CachedCSSStyleSheet::sheetText(MIMETypeCheckHint mimeTypeCheckHint, bool* hasValidMIMEType) const
75 {
76     if (!m_data || m_data->isEmpty() || !canUseSheet(mimeTypeCheckHint, hasValidMIMEType))
77         return String();
78
79     if (!m_decodedSheetText.isNull())
80         return m_decodedSheetText;
81
82     // Don't cache the decoded text, regenerating is cheap and it can use quite a bit of memory
83     return m_decoder->decodeAndFlush(m_data->data(), m_data->size());
84 }
85
86 void CachedCSSStyleSheet::setBodyDataFrom(const CachedResource& resource)
87 {
88     ASSERT(resource.type() == type());
89     const CachedCSSStyleSheet& sheet = static_cast<const CachedCSSStyleSheet&>(resource);
90
91     CachedResource::setBodyDataFrom(resource);
92
93     m_decoder = sheet.m_decoder;
94     m_decodedSheetText = sheet.m_decodedSheetText;
95     if (sheet.m_parsedStyleSheetCache)
96         saveParsedStyleSheet(*sheet.m_parsedStyleSheetCache);
97 }
98
99 void CachedCSSStyleSheet::finishLoading(SharedBuffer* data)
100 {
101     m_data = data;
102     setEncodedSize(data ? data->size() : 0);
103     // Decode the data to find out the encoding and keep the sheet text around during checkNotify()
104     if (data)
105         m_decodedSheetText = m_decoder->decodeAndFlush(data->data(), data->size());
106     setLoading(false);
107     checkNotify();
108     // Clear the decoded text as it is unlikely to be needed immediately again and is cheap to regenerate.
109     m_decodedSheetText = String();
110 }
111
112 void CachedCSSStyleSheet::checkNotify()
113 {
114     if (isLoading())
115         return;
116
117     CachedResourceClientWalker<CachedStyleSheetClient> w(m_clients);
118     while (CachedStyleSheetClient* c = w.next())
119         c->setCSSStyleSheet(m_resourceRequest.url(), m_response.url(), m_decoder->encoding().name(), this);
120 }
121
122 String CachedCSSStyleSheet::responseMIMEType() const
123 {
124     return extractMIMETypeFromMediaType(m_response.httpHeaderField(HTTPHeaderName::ContentType));
125 }
126
127 bool CachedCSSStyleSheet::mimeTypeAllowedByNosniff() const
128 {
129     return parseContentTypeOptionsHeader(m_response.httpHeaderField(HTTPHeaderName::XContentTypeOptions)) != ContentTypeOptionsNosniff || equalLettersIgnoringASCIICase(responseMIMEType(), "text/css");
130 }
131
132 bool CachedCSSStyleSheet::canUseSheet(MIMETypeCheckHint mimeTypeCheckHint, bool* hasValidMIMEType) const
133 {
134     if (errorOccurred())
135         return false;
136
137     if (!mimeTypeAllowedByNosniff()) {
138         if (hasValidMIMEType)
139             *hasValidMIMEType = false;
140         return false;
141     }
142
143     if (mimeTypeCheckHint == MIMETypeCheckHint::Lax)
144         return true;
145
146     // This check exactly matches Firefox.  Note that we grab the Content-Type
147     // header directly because we want to see what the value is BEFORE content
148     // sniffing.  Firefox does this by setting a "type hint" on the channel.
149     // This implementation should be observationally equivalent.
150     //
151     // This code defaults to allowing the stylesheet for non-HTTP protocols so
152     // folks can use standards mode for local HTML documents.
153     String mimeType = responseMIMEType();
154     bool typeOK = mimeType.isEmpty() || equalLettersIgnoringASCIICase(mimeType, "text/css") || equalLettersIgnoringASCIICase(mimeType, "application/x-unknown-content-type");
155     if (hasValidMIMEType)
156         *hasValidMIMEType = typeOK;
157     return typeOK;
158 }
159
160 void CachedCSSStyleSheet::destroyDecodedData()
161 {
162     if (!m_parsedStyleSheetCache)
163         return;
164
165     m_parsedStyleSheetCache->removedFromMemoryCache();
166     m_parsedStyleSheetCache = nullptr;
167
168     setDecodedSize(0);
169 }
170
171 RefPtr<StyleSheetContents> CachedCSSStyleSheet::restoreParsedStyleSheet(const CSSParserContext& context, CachePolicy cachePolicy, FrameLoader& loader)
172 {
173     if (!m_parsedStyleSheetCache)
174         return nullptr;
175     if (!m_parsedStyleSheetCache->subresourcesAllowReuse(cachePolicy, loader)) {
176         m_parsedStyleSheetCache->removedFromMemoryCache();
177         m_parsedStyleSheetCache = nullptr;
178         return nullptr;
179     }
180
181     ASSERT(m_parsedStyleSheetCache->isCacheable());
182     ASSERT(m_parsedStyleSheetCache->isInMemoryCache());
183
184     // Contexts must be identical so we know we would get the same exact result if we parsed again.
185     if (m_parsedStyleSheetCache->parserContext() != context)
186         return nullptr;
187
188     didAccessDecodedData(MonotonicTime::now());
189
190     return m_parsedStyleSheetCache;
191 }
192
193 void CachedCSSStyleSheet::saveParsedStyleSheet(Ref<StyleSheetContents>&& sheet)
194 {
195     ASSERT(sheet->isCacheable());
196
197     if (m_parsedStyleSheetCache)
198         m_parsedStyleSheetCache->removedFromMemoryCache();
199     m_parsedStyleSheetCache = WTFMove(sheet);
200     m_parsedStyleSheetCache->addedToMemoryCache();
201
202     setDecodedSize(m_parsedStyleSheetCache->estimatedSizeInBytes());
203 }
204
205 }