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, 2005, 2006 Apple Computer, Inc.
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 This class provides all functionality needed for loading images, style sheets and html
24 pages from the web. It has a memory cache for these objects.
25 */
26
27 #include "config.h"
28 #include "CachedCSSStyleSheet.h"
29
30 #include "MemoryCache.h"
31 #include "CachedResourceClient.h"
32 #include "CachedResourceClientWalker.h"
33 #include "HTTPParsers.h"
34 #include "TextResourceDecoder.h"
35 #include "SharedBuffer.h"
36 #include <wtf/Vector.h>
37
38 namespace WebCore {
39
CachedCSSStyleSheet(const String & url,const String & charset)40 CachedCSSStyleSheet::CachedCSSStyleSheet(const String& url, const String& charset)
41 : CachedResource(url, CSSStyleSheet)
42 , m_decoder(TextResourceDecoder::create("text/css", charset))
43 {
44 // Prefer text/css but accept any type (dell.com serves a stylesheet
45 // as text/html; see <http://bugs.webkit.org/show_bug.cgi?id=11451>).
46 setAccept("text/css,*/*;q=0.1");
47 }
48
~CachedCSSStyleSheet()49 CachedCSSStyleSheet::~CachedCSSStyleSheet()
50 {
51 }
52
didAddClient(CachedResourceClient * c)53 void CachedCSSStyleSheet::didAddClient(CachedResourceClient *c)
54 {
55 if (!isLoading())
56 c->setCSSStyleSheet(m_url, m_response.url(), m_decoder->encoding().name(), this);
57 }
58
allClientsRemoved()59 void CachedCSSStyleSheet::allClientsRemoved()
60 {
61 if (!MemoryCache::shouldMakeResourcePurgeableOnEviction() && isSafeToMakePurgeable())
62 makePurgeable(true);
63 }
64
setEncoding(const String & chs)65 void CachedCSSStyleSheet::setEncoding(const String& chs)
66 {
67 m_decoder->setEncoding(chs, TextResourceDecoder::EncodingFromHTTPHeader);
68 }
69
encoding() const70 String CachedCSSStyleSheet::encoding() const
71 {
72 return m_decoder->encoding().name();
73 }
74
sheetText(bool enforceMIMEType,bool * hasValidMIMEType) const75 const String CachedCSSStyleSheet::sheetText(bool enforceMIMEType, bool* hasValidMIMEType) const
76 {
77 ASSERT(!isPurgeable());
78
79 if (!m_data || m_data->isEmpty() || !canUseSheet(enforceMIMEType, hasValidMIMEType))
80 return String();
81
82 if (!m_decodedSheetText.isNull())
83 return m_decodedSheetText;
84
85 // Don't cache the decoded text, regenerating is cheap and it can use quite a bit of memory
86 String sheetText = m_decoder->decode(m_data->data(), m_data->size());
87 sheetText += m_decoder->flush();
88 return sheetText;
89 }
90
data(PassRefPtr<SharedBuffer> data,bool allDataReceived)91 void CachedCSSStyleSheet::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
92 {
93 if (!allDataReceived)
94 return;
95
96 m_data = data;
97 setEncodedSize(m_data.get() ? m_data->size() : 0);
98 // Decode the data to find out the encoding and keep the sheet text around during checkNotify()
99 if (m_data) {
100 m_decodedSheetText = m_decoder->decode(m_data->data(), m_data->size());
101 m_decodedSheetText += m_decoder->flush();
102 }
103 setLoading(false);
104 checkNotify();
105 // Clear the decoded text as it is unlikely to be needed immediately again and is cheap to regenerate.
106 m_decodedSheetText = String();
107 }
108
checkNotify()109 void CachedCSSStyleSheet::checkNotify()
110 {
111 if (isLoading())
112 return;
113
114 CachedResourceClientWalker w(m_clients);
115 while (CachedResourceClient *c = w.next())
116 c->setCSSStyleSheet(m_url, m_response.url(), m_decoder->encoding().name(), this);
117 }
118
error(CachedResource::Status status)119 void CachedCSSStyleSheet::error(CachedResource::Status status)
120 {
121 setStatus(status);
122 ASSERT(errorOccurred());
123 setLoading(false);
124 checkNotify();
125 }
126
canUseSheet(bool enforceMIMEType,bool * hasValidMIMEType) const127 bool CachedCSSStyleSheet::canUseSheet(bool enforceMIMEType, bool* hasValidMIMEType) const
128 {
129 if (errorOccurred())
130 return false;
131
132 if (!enforceMIMEType && !hasValidMIMEType)
133 return true;
134
135 // This check exactly matches Firefox. Note that we grab the Content-Type
136 // header directly because we want to see what the value is BEFORE content
137 // sniffing. Firefox does this by setting a "type hint" on the channel.
138 // This implementation should be observationally equivalent.
139 //
140 // This code defaults to allowing the stylesheet for non-HTTP protocols so
141 // folks can use standards mode for local HTML documents.
142 String mimeType = extractMIMETypeFromMediaType(response().httpHeaderField("Content-Type"));
143 bool typeOK = mimeType.isEmpty() || equalIgnoringCase(mimeType, "text/css") || equalIgnoringCase(mimeType, "application/x-unknown-content-type");
144 if (hasValidMIMEType)
145 *hasValidMIMEType = typeOK;
146 if (!enforceMIMEType)
147 return true;
148 return typeOK;
149 }
150
151 }
152