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
38namespace WebCore {
39
40static bool shouldForceContentSniffing;
41
42ResourceHandle::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
56PassRefPtr<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
77void ResourceHandle::scheduleFailure(FailureType type)
78{
79    d->m_scheduledFailureType = type;
80    d->m_failureTimer.startOneShot(0);
81}
82
83void 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
105ResourceHandleClient* ResourceHandle::client() const
106{
107    return d->m_client;
108}
109
110void ResourceHandle::setClient(ResourceHandleClient* client)
111{
112    d->m_client = client;
113}
114
115ResourceRequest& ResourceHandle::firstRequest()
116{
117    return d->m_firstRequest;
118}
119
120const String& ResourceHandle::lastHTTPMethod() const
121{
122    return d->m_lastHTTPMethod;
123}
124
125bool ResourceHandle::hasAuthenticationChallenge() const
126{
127    return !d->m_currentWebChallenge.isNull();
128}
129
130void ResourceHandle::clearAuthentication()
131{
132#if PLATFORM(MAC)
133    d->m_currentMacChallenge = nil;
134#endif
135    d->m_currentWebChallenge.nullify();
136}
137
138bool ResourceHandle::shouldContentSniff() const
139{
140    return d->m_shouldContentSniff;
141}
142
143bool 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
153void ResourceHandle::forceContentSniffing()
154{
155    shouldForceContentSniffing = true;
156}
157
158void 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)
178void ResourceHandle::prepareForURL(const KURL& url)
179{
180    return prefetchDNS(url.host());
181}
182#endif
183
184void ResourceHandle::cacheMetadata(const ResourceResponse&, const Vector<char>&)
185{
186    // Optionally implemented by platform.
187}
188
189#if USE(CFURLSTORAGESESSIONS)
190
191static RetainPtr<CFURLStorageSessionRef>& privateStorageSession()
192{
193    DEFINE_STATIC_LOCAL(RetainPtr<CFURLStorageSessionRef>, storageSession, ());
194    return storageSession;
195}
196
197static String& privateBrowsingStorageSessionIdentifierBase()
198{
199    DEFINE_STATIC_LOCAL(String, base, ());
200    return base;
201}
202
203void 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
219CFURLStorageSessionRef ResourceHandle::privateBrowsingStorageSession()
220{
221    return privateStorageSession().get();
222}
223
224void ResourceHandle::setPrivateBrowsingStorageSessionIdentifierBase(const String& identifier)
225{
226    privateBrowsingStorageSessionIdentifierBase() = identifier;
227}
228
229#endif // USE(CFURLSTORAGESESSIONS)
230
231} // namespace WebCore
232