1 /*
2 * Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010 Apple 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 APPLE COMPUTER, 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 COMPUTER, 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 "ResourceHandle.h"
28 #include "ResourceHandleInternal.h"
29
30 #include "BlobRegistry.h"
31 #include "DNS.h"
32 #include "Logging.h"
33 #include "ResourceHandleClient.h"
34 #include "Timer.h"
35 #include <algorithm>
36 #include <wtf/text/CString.h>
37
38 namespace WebCore {
39
40 static bool shouldForceContentSniffing;
41
ResourceHandle(const ResourceRequest & request,ResourceHandleClient * client,bool defersLoading,bool shouldContentSniff)42 ResourceHandle::ResourceHandle(const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff)
43 : d(new ResourceHandleInternal(this, request, client, defersLoading, shouldContentSniff && shouldContentSniffURL(request.url())))
44 {
45 if (!request.url().isValid()) {
46 scheduleFailure(InvalidURLFailure);
47 return;
48 }
49
50 if (!portAllowed(request.url())) {
51 scheduleFailure(BlockedFailure);
52 return;
53 }
54 }
55
create(NetworkingContext * context,const ResourceRequest & request,ResourceHandleClient * client,bool defersLoading,bool shouldContentSniff)56 PassRefPtr<ResourceHandle> ResourceHandle::create(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff)
57 {
58 #if ENABLE(BLOB)
59 if (request.url().protocolIs("blob")) {
60 PassRefPtr<ResourceHandle> handle = blobRegistry().createResourceHandle(request, client);
61 if (handle)
62 return handle;
63 }
64 #endif
65
66 RefPtr<ResourceHandle> newHandle(adoptRef(new ResourceHandle(request, client, defersLoading, shouldContentSniff)));
67
68 if (newHandle->d->m_scheduledFailureType != NoFailure)
69 return newHandle.release();
70
71 if (newHandle->start(context))
72 return newHandle.release();
73
74 return 0;
75 }
76
scheduleFailure(FailureType type)77 void ResourceHandle::scheduleFailure(FailureType type)
78 {
79 d->m_scheduledFailureType = type;
80 d->m_failureTimer.startOneShot(0);
81 }
82
fireFailure(Timer<ResourceHandle> *)83 void ResourceHandle::fireFailure(Timer<ResourceHandle>*)
84 {
85 if (!client())
86 return;
87
88 switch (d->m_scheduledFailureType) {
89 case NoFailure:
90 ASSERT_NOT_REACHED();
91 return;
92 case BlockedFailure:
93 d->m_scheduledFailureType = NoFailure;
94 client()->wasBlocked(this);
95 return;
96 case InvalidURLFailure:
97 d->m_scheduledFailureType = NoFailure;
98 client()->cannotShowURL(this);
99 return;
100 }
101
102 ASSERT_NOT_REACHED();
103 }
104
client() const105 ResourceHandleClient* ResourceHandle::client() const
106 {
107 return d->m_client;
108 }
109
setClient(ResourceHandleClient * client)110 void ResourceHandle::setClient(ResourceHandleClient* client)
111 {
112 d->m_client = client;
113 }
114
firstRequest()115 ResourceRequest& ResourceHandle::firstRequest()
116 {
117 return d->m_firstRequest;
118 }
119
lastHTTPMethod() const120 const String& ResourceHandle::lastHTTPMethod() const
121 {
122 return d->m_lastHTTPMethod;
123 }
124
hasAuthenticationChallenge() const125 bool ResourceHandle::hasAuthenticationChallenge() const
126 {
127 return !d->m_currentWebChallenge.isNull();
128 }
129
clearAuthentication()130 void ResourceHandle::clearAuthentication()
131 {
132 #if PLATFORM(MAC)
133 d->m_currentMacChallenge = nil;
134 #endif
135 d->m_currentWebChallenge.nullify();
136 }
137
shouldContentSniff() const138 bool ResourceHandle::shouldContentSniff() const
139 {
140 return d->m_shouldContentSniff;
141 }
142
shouldContentSniffURL(const KURL & url)143 bool ResourceHandle::shouldContentSniffURL(const KURL& url)
144 {
145 #if PLATFORM(MAC)
146 if (shouldForceContentSniffing)
147 return true;
148 #endif
149 // We shouldn't content sniff file URLs as their MIME type should be established via their extension.
150 return !url.protocolIs("file");
151 }
152
forceContentSniffing()153 void ResourceHandle::forceContentSniffing()
154 {
155 shouldForceContentSniffing = true;
156 }
157
setDefersLoading(bool defers)158 void ResourceHandle::setDefersLoading(bool defers)
159 {
160 LOG(Network, "Handle %p setDefersLoading(%s)", this, defers ? "true" : "false");
161
162 ASSERT(d->m_defersLoading != defers); // Deferring is not counted, so calling setDefersLoading() repeatedly is likely to be in error.
163 d->m_defersLoading = defers;
164
165 if (defers) {
166 ASSERT(d->m_failureTimer.isActive() == (d->m_scheduledFailureType != NoFailure));
167 if (d->m_failureTimer.isActive())
168 d->m_failureTimer.stop();
169 } else if (d->m_scheduledFailureType != NoFailure) {
170 ASSERT(!d->m_failureTimer.isActive());
171 d->m_failureTimer.startOneShot(0);
172 }
173
174 platformSetDefersLoading(defers);
175 }
176
177 #if !USE(SOUP)
prepareForURL(const KURL & url)178 void ResourceHandle::prepareForURL(const KURL& url)
179 {
180 return prefetchDNS(url.host());
181 }
182 #endif
183
cacheMetadata(const ResourceResponse &,const Vector<char> &)184 void ResourceHandle::cacheMetadata(const ResourceResponse&, const Vector<char>&)
185 {
186 // Optionally implemented by platform.
187 }
188
189 #if USE(CFURLSTORAGESESSIONS)
190
privateStorageSession()191 static RetainPtr<CFURLStorageSessionRef>& privateStorageSession()
192 {
193 DEFINE_STATIC_LOCAL(RetainPtr<CFURLStorageSessionRef>, storageSession, ());
194 return storageSession;
195 }
196
privateBrowsingStorageSessionIdentifierBase()197 static String& privateBrowsingStorageSessionIdentifierBase()
198 {
199 DEFINE_STATIC_LOCAL(String, base, ());
200 return base;
201 }
202
setPrivateBrowsingEnabled(bool enabled)203 void ResourceHandle::setPrivateBrowsingEnabled(bool enabled)
204 {
205 if (!enabled) {
206 privateStorageSession() = nullptr;
207 return;
208 }
209
210 if (privateStorageSession())
211 return;
212
213 String base = privateBrowsingStorageSessionIdentifierBase().isNull() ? privateBrowsingStorageSessionIdentifierDefaultBase() : privateBrowsingStorageSessionIdentifierBase();
214 RetainPtr<CFStringRef> cfIdentifier(AdoptCF, String::format("%s.PrivateBrowsing", base.utf8().data()).createCFString());
215
216 privateStorageSession() = createPrivateBrowsingStorageSession(cfIdentifier.get());
217 }
218
privateBrowsingStorageSession()219 CFURLStorageSessionRef ResourceHandle::privateBrowsingStorageSession()
220 {
221 return privateStorageSession().get();
222 }
223
setPrivateBrowsingStorageSessionIdentifierBase(const String & identifier)224 void ResourceHandle::setPrivateBrowsingStorageSessionIdentifierBase(const String& identifier)
225 {
226 privateBrowsingStorageSessionIdentifierBase() = identifier;
227 }
228
229 #endif // USE(CFURLSTORAGESESSIONS)
230
231 } // namespace WebCore
232