1/*
2 * Copyright (C) 2012, 2013 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 INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebResourceLoader.h"
28
29#if ENABLE(NETWORK_PROCESS)
30
31#include "DataReference.h"
32#include "Logging.h"
33#include "NetworkProcessConnection.h"
34#include "NetworkResourceLoaderMessages.h"
35#include "WebCoreArgumentCoders.h"
36#include "WebErrors.h"
37#include "WebProcess.h"
38#include <WebCore/ApplicationCacheHost.h>
39#include <WebCore/CertificateInfo.h>
40#include <WebCore/DocumentLoader.h>
41#include <WebCore/ResourceBuffer.h>
42#include <WebCore/ResourceError.h>
43#include <WebCore/ResourceLoader.h>
44
45using namespace WebCore;
46
47namespace WebKit {
48
49PassRefPtr<WebResourceLoader> WebResourceLoader::create(PassRefPtr<ResourceLoader> coreLoader)
50{
51    return adoptRef(new WebResourceLoader(coreLoader));
52}
53
54WebResourceLoader::WebResourceLoader(PassRefPtr<WebCore::ResourceLoader> coreLoader)
55    : m_coreLoader(coreLoader)
56{
57}
58
59WebResourceLoader::~WebResourceLoader()
60{
61}
62
63IPC::Connection* WebResourceLoader::messageSenderConnection()
64{
65    return WebProcess::shared().networkConnection()->connection();
66}
67
68uint64_t WebResourceLoader::messageSenderDestinationID()
69{
70    return m_coreLoader->identifier();
71}
72
73void WebResourceLoader::cancelResourceLoader()
74{
75    m_coreLoader->cancel();
76}
77
78void WebResourceLoader::detachFromCoreLoader()
79{
80    m_coreLoader = 0;
81}
82
83void WebResourceLoader::willSendRequest(const ResourceRequest& proposedRequest, const ResourceResponse& redirectResponse)
84{
85    LOG(Network, "(WebProcess) WebResourceLoader::willSendRequest to '%s'", proposedRequest.url().string().utf8().data());
86
87    Ref<WebResourceLoader> protect(*this);
88
89    ResourceRequest newRequest = proposedRequest;
90    if (m_coreLoader->documentLoader()->applicationCacheHost()->maybeLoadFallbackForRedirect(m_coreLoader.get(), newRequest, redirectResponse))
91        return;
92    m_coreLoader->willSendRequest(newRequest, redirectResponse);
93
94    if (!m_coreLoader)
95        return;
96
97    send(Messages::NetworkResourceLoader::ContinueWillSendRequest(newRequest));
98}
99
100void WebResourceLoader::didSendData(uint64_t bytesSent, uint64_t totalBytesToBeSent)
101{
102    m_coreLoader->didSendData(bytesSent, totalBytesToBeSent);
103}
104
105void WebResourceLoader::didReceiveResponseWithCertificateInfo(const ResourceResponse& response, const CertificateInfo& certificateInfo, bool needsContinueDidReceiveResponseMessage)
106{
107    LOG(Network, "(WebProcess) WebResourceLoader::didReceiveResponseWithCertificateInfo for '%s'. Status %d.", m_coreLoader->url().string().utf8().data(), response.httpStatusCode());
108
109    Ref<WebResourceLoader> protect(*this);
110
111    ResourceResponse responseCopy(response);
112
113    // FIXME: This should use CertificateInfo to avoid the platform ifdefs. See https://bugs.webkit.org/show_bug.cgi?id=124724.
114#if PLATFORM(COCOA)
115    responseCopy.setCertificateChain(certificateInfo.certificateChain());
116#elif USE(SOUP)
117    responseCopy.setSoupMessageCertificate(certificateInfo.certificate());
118    responseCopy.setSoupMessageTLSErrors(certificateInfo.tlsErrors());
119#endif
120
121    if (m_coreLoader->documentLoader()->applicationCacheHost()->maybeLoadFallbackForResponse(m_coreLoader.get(), responseCopy))
122        return;
123
124#if USE(QUICK_LOOK)
125    // Refrain from calling didReceiveResponse if QuickLook will convert this response, since the MIME type of the
126    // converted resource isn't yet known. WebResourceLoaderQuickLookDelegate will later call didReceiveResponse upon
127    // receiving the converted data.
128    m_coreLoader->documentLoader()->setQuickLookHandle(QuickLookHandle::create(resourceLoader(), responseCopy.nsURLResponse()));
129    if (!m_coreLoader->documentLoader()->quickLookHandle())
130#endif
131        m_coreLoader->didReceiveResponse(responseCopy);
132
133    // If m_coreLoader becomes null as a result of the didReceiveResponse callback, we can't use the send function().
134    if (!m_coreLoader)
135        return;
136
137    if (needsContinueDidReceiveResponseMessage)
138        send(Messages::NetworkResourceLoader::ContinueDidReceiveResponse());
139}
140
141void WebResourceLoader::didReceiveData(const IPC::DataReference& data, int64_t encodedDataLength)
142{
143    LOG(Network, "(WebProcess) WebResourceLoader::didReceiveData of size %i for '%s'", (int)data.size(), m_coreLoader->url().string().utf8().data());
144
145#if USE(QUICK_LOOK)
146    if (QuickLookHandle* quickLookHandle = m_coreLoader->documentLoader()->quickLookHandle()) {
147        if (quickLookHandle->didReceiveData(adoptCF(CFDataCreate(kCFAllocatorDefault, data.data(), data.size())).get()))
148            return;
149    }
150#endif
151    m_coreLoader->didReceiveData(reinterpret_cast<const char*>(data.data()), data.size(), encodedDataLength, DataPayloadBytes);
152}
153
154void WebResourceLoader::didFinishResourceLoad(double finishTime)
155{
156    LOG(Network, "(WebProcess) WebResourceLoader::didFinishResourceLoad for '%s'", m_coreLoader->url().string().utf8().data());
157
158#if USE(QUICK_LOOK)
159    if (QuickLookHandle* quickLookHandle = m_coreLoader->documentLoader()->quickLookHandle()) {
160        if (quickLookHandle->didFinishLoading())
161            return;
162    }
163#endif
164    m_coreLoader->didFinishLoading(finishTime);
165}
166
167void WebResourceLoader::didFailResourceLoad(const ResourceError& error)
168{
169    LOG(Network, "(WebProcess) WebResourceLoader::didFailResourceLoad for '%s'", m_coreLoader->url().string().utf8().data());
170
171#if USE(QUICK_LOOK)
172    if (QuickLookHandle* quickLookHandle = m_coreLoader->documentLoader()->quickLookHandle())
173        quickLookHandle->didFail();
174#endif
175    if (m_coreLoader->documentLoader()->applicationCacheHost()->maybeLoadFallbackForError(m_coreLoader.get(), error))
176        return;
177    m_coreLoader->didFail(error);
178}
179
180#if ENABLE(SHAREABLE_RESOURCE)
181void WebResourceLoader::didReceiveResource(const ShareableResource::Handle& handle, double finishTime)
182{
183    LOG(Network, "(WebProcess) WebResourceLoader::didReceiveResource for '%s'", m_coreLoader->url().string().utf8().data());
184
185#if USE(QUICK_LOOK)
186    if (QuickLookHandle* quickLookHandle = m_coreLoader->documentLoader()->quickLookHandle()) {
187        RetainPtr<CFDataRef> cfBuffer = handle.tryWrapInCFData();
188        if (cfBuffer) {
189            if (quickLookHandle->didReceiveData(cfBuffer.get())) {
190                quickLookHandle->didFinishLoading();
191                return;
192            }
193        } else
194            quickLookHandle->didFail();
195    }
196#endif
197
198    RefPtr<SharedBuffer> buffer = handle.tryWrapInSharedBuffer();
199    if (!buffer) {
200        LOG_ERROR("Unable to create buffer from ShareableResource sent from the network process.");
201        m_coreLoader->didFail(internalError(m_coreLoader->request().url()));
202        return;
203    }
204
205    Ref<WebResourceLoader> protect(*this);
206
207    // Only send data to the didReceiveData callback if it exists.
208    if (buffer->size())
209        m_coreLoader->didReceiveBuffer(buffer.get(), buffer->size(), DataPayloadWholeResource);
210
211    if (!m_coreLoader)
212        return;
213
214    m_coreLoader->didFinishLoading(finishTime);
215}
216#endif
217
218#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
219void WebResourceLoader::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace)
220{
221    Ref<WebResourceLoader> protect(*this);
222
223    bool result = m_coreLoader->canAuthenticateAgainstProtectionSpace(protectionSpace);
224
225    if (!m_coreLoader)
226        return;
227
228    send(Messages::NetworkResourceLoader::ContinueCanAuthenticateAgainstProtectionSpace(result));
229}
230#endif
231
232} // namespace WebKit
233
234#endif // ENABLE(NETWORK_PROCESS)
235