Load may get committed before receiving policy for the resource response
[WebKit-https.git] / Source / WebKit / WebProcess / Network / WebResourceLoader.cpp
1 /*
2  * Copyright (C) 2012-2017 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 #include "DataReference.h"
30 #include "Logging.h"
31 #include "NetworkProcessConnection.h"
32 #include "NetworkResourceLoaderMessages.h"
33 #include "WebCoreArgumentCoders.h"
34 #include "WebErrors.h"
35 #include "WebProcess.h"
36 #include <WebCore/ApplicationCacheHost.h>
37 #include <WebCore/CertificateInfo.h>
38 #include <WebCore/DiagnosticLoggingClient.h>
39 #include <WebCore/DiagnosticLoggingKeys.h>
40 #include <WebCore/DocumentLoader.h>
41 #include <WebCore/Frame.h>
42 #include <WebCore/Page.h>
43 #include <WebCore/ResourceError.h>
44 #include <WebCore/ResourceLoader.h>
45 #include <WebCore/SubresourceLoader.h>
46 #include <wtf/CompletionHandler.h>
47
48 using namespace WebCore;
49
50 #define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Network, "%p - WebResourceLoader::" fmt, this, ##__VA_ARGS__)
51
52 namespace WebKit {
53
54 Ref<WebResourceLoader> WebResourceLoader::create(Ref<ResourceLoader>&& coreLoader, const TrackingParameters& trackingParameters)
55 {
56     return adoptRef(*new WebResourceLoader(WTFMove(coreLoader), trackingParameters));
57 }
58
59 WebResourceLoader::WebResourceLoader(Ref<WebCore::ResourceLoader>&& coreLoader, const TrackingParameters& trackingParameters)
60     : m_coreLoader(WTFMove(coreLoader))
61     , m_trackingParameters(trackingParameters)
62 {
63 }
64
65 WebResourceLoader::~WebResourceLoader()
66 {
67 }
68
69 IPC::Connection* WebResourceLoader::messageSenderConnection()
70 {
71     return &WebProcess::singleton().ensureNetworkProcessConnection().connection();
72 }
73
74 uint64_t WebResourceLoader::messageSenderDestinationID()
75 {
76     return m_coreLoader->identifier();
77 }
78
79 void WebResourceLoader::detachFromCoreLoader()
80 {
81     m_coreLoader = nullptr;
82 }
83
84 void WebResourceLoader::willSendRequest(ResourceRequest&& proposedRequest, ResourceResponse&& redirectResponse)
85 {
86     LOG(Network, "(WebProcess) WebResourceLoader::willSendRequest to '%s'", proposedRequest.url().string().latin1().data());
87     RELEASE_LOG_IF_ALLOWED("willSendRequest: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_trackingParameters.pageID, m_trackingParameters.frameID, m_trackingParameters.resourceID);
88
89     if (m_coreLoader->documentLoader()->applicationCacheHost().maybeLoadFallbackForRedirect(m_coreLoader.get(), proposedRequest, redirectResponse))
90         return;
91
92     m_coreLoader->willSendRequest(WTFMove(proposedRequest), redirectResponse, [protectedThis = makeRef(*this)](ResourceRequest&& request) {
93         if (!protectedThis->m_coreLoader)
94             return;
95
96         protectedThis->send(Messages::NetworkResourceLoader::ContinueWillSendRequest(request, protectedThis->m_coreLoader->isAllowedToAskUserForCredentials()));
97     });
98 }
99
100 void WebResourceLoader::didSendData(uint64_t bytesSent, uint64_t totalBytesToBeSent)
101 {
102     m_coreLoader->didSendData(bytesSent, totalBytesToBeSent);
103 }
104
105 void WebResourceLoader::didReceiveResponse(const ResourceResponse& response, bool needsContinueDidReceiveResponseMessage)
106 {
107     LOG(Network, "(WebProcess) WebResourceLoader::didReceiveResponse for '%s'. Status %d.", m_coreLoader->url().string().latin1().data(), response.httpStatusCode());
108     RELEASE_LOG_IF_ALLOWED("didReceiveResponse: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", status = %d)", m_trackingParameters.pageID, m_trackingParameters.frameID, m_trackingParameters.resourceID, response.httpStatusCode());
109
110     Ref<WebResourceLoader> protectedThis(*this);
111
112     if (m_coreLoader->documentLoader()->applicationCacheHost().maybeLoadFallbackForResponse(m_coreLoader.get(), response))
113         return;
114
115     CompletionHandler<void()> policyDecisionCompletionHandler;
116     if (needsContinueDidReceiveResponseMessage) {
117 #if !ASSERT_DISABLED
118         m_isProcessingNetworkResponse = true;
119 #endif
120         policyDecisionCompletionHandler = [this, protectedThis = WTFMove(protectedThis)] {
121 #if !ASSERT_DISABLED
122             m_isProcessingNetworkResponse = false;
123 #endif
124             // If m_coreLoader becomes null as a result of the didReceiveResponse callback, we can't use the send function().
125             if (m_coreLoader)
126                 send(Messages::NetworkResourceLoader::ContinueDidReceiveResponse());
127         };
128     }
129
130     m_coreLoader->didReceiveResponse(response, WTFMove(policyDecisionCompletionHandler));
131 }
132
133 void WebResourceLoader::didReceiveData(const IPC::DataReference& data, int64_t encodedDataLength)
134 {
135     LOG(Network, "(WebProcess) WebResourceLoader::didReceiveData of size %lu for '%s'", data.size(), m_coreLoader->url().string().latin1().data());
136     ASSERT_WITH_MESSAGE(!m_isProcessingNetworkResponse, "Network process should not send data until we've validated the response");
137
138     if (!m_numBytesReceived) {
139         RELEASE_LOG_IF_ALLOWED("didReceiveData: Started receiving data (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_trackingParameters.pageID, m_trackingParameters.frameID, m_trackingParameters.resourceID);
140     }
141     m_numBytesReceived += data.size();
142
143     m_coreLoader->didReceiveData(reinterpret_cast<const char*>(data.data()), data.size(), encodedDataLength, DataPayloadBytes);
144 }
145
146 void WebResourceLoader::didRetrieveDerivedData(const String& type, const IPC::DataReference& data)
147 {
148     LOG(Network, "(WebProcess) WebResourceLoader::didRetrieveDerivedData of size %lu for '%s'", data.size(), m_coreLoader->url().string().latin1().data());
149
150     auto buffer = SharedBuffer::create(data.data(), data.size());
151     m_coreLoader->didRetrieveDerivedDataFromCache(type, buffer.get());
152 }
153
154 void WebResourceLoader::didFinishResourceLoad(const NetworkLoadMetrics& networkLoadMetrics)
155 {
156     LOG(Network, "(WebProcess) WebResourceLoader::didFinishResourceLoad for '%s'", m_coreLoader->url().string().latin1().data());
157     RELEASE_LOG_IF_ALLOWED("didFinishResourceLoad: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", length = %zd)", m_trackingParameters.pageID, m_trackingParameters.frameID, m_trackingParameters.resourceID, m_numBytesReceived);
158
159     ASSERT_WITH_MESSAGE(!m_isProcessingNetworkResponse, "Load should not be able to finish before we've validated the response");
160     m_coreLoader->didFinishLoading(networkLoadMetrics);
161 }
162
163 void WebResourceLoader::didFailResourceLoad(const ResourceError& error)
164 {
165     LOG(Network, "(WebProcess) WebResourceLoader::didFailResourceLoad for '%s'", m_coreLoader->url().string().latin1().data());
166     RELEASE_LOG_IF_ALLOWED("didFailResourceLoad: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_trackingParameters.pageID, m_trackingParameters.frameID, m_trackingParameters.resourceID);
167
168     ASSERT_WITH_MESSAGE(!m_isProcessingNetworkResponse, "Load should not be able to finish before we've validated the response");
169
170     if (m_coreLoader->documentLoader()->applicationCacheHost().maybeLoadFallbackForError(m_coreLoader.get(), error))
171         return;
172     m_coreLoader->didFail(error);
173 }
174
175 void WebResourceLoader::didBlockAuthenticationChallenge()
176 {
177     LOG(Network, "(WebProcess) WebResourceLoader::didBlockAuthenticationChallenge for '%s'", m_coreLoader->url().string().latin1().data());
178     RELEASE_LOG_IF_ALLOWED("didBlockAuthenticationChallenge: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_trackingParameters.pageID, m_trackingParameters.frameID, m_trackingParameters.resourceID);
179
180     m_coreLoader->didBlockAuthenticationChallenge();
181 }
182
183 #if ENABLE(SHAREABLE_RESOURCE)
184 void WebResourceLoader::didReceiveResource(const ShareableResource::Handle& handle)
185 {
186     LOG(Network, "(WebProcess) WebResourceLoader::didReceiveResource for '%s'", m_coreLoader->url().string().latin1().data());
187     RELEASE_LOG_IF_ALLOWED("didReceiveResource: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_trackingParameters.pageID, m_trackingParameters.frameID, m_trackingParameters.resourceID);
188
189     RefPtr<SharedBuffer> buffer = handle.tryWrapInSharedBuffer();
190
191     if (!buffer) {
192         LOG_ERROR("Unable to create buffer from ShareableResource sent from the network process.");
193         RELEASE_LOG_IF_ALLOWED("didReceiveResource: Unable to create SharedBuffer (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ")", m_trackingParameters.pageID, m_trackingParameters.frameID, m_trackingParameters.resourceID);
194         if (auto* frame = m_coreLoader->frame()) {
195             if (auto* page = frame->page())
196                 page->diagnosticLoggingClient().logDiagnosticMessage(WebCore::DiagnosticLoggingKeys::internalErrorKey(), WebCore::DiagnosticLoggingKeys::createSharedBufferFailedKey(), WebCore::ShouldSample::No);
197         }
198         m_coreLoader->didFail(internalError(m_coreLoader->request().url()));
199         return;
200     }
201
202     Ref<WebResourceLoader> protect(*this);
203
204     // Only send data to the didReceiveData callback if it exists.
205     if (unsigned bufferSize = buffer->size())
206         m_coreLoader->didReceiveBuffer(buffer.releaseNonNull(), bufferSize, DataPayloadWholeResource);
207
208     if (!m_coreLoader)
209         return;
210
211     NetworkLoadMetrics emptyMetrics;
212     m_coreLoader->didFinishLoading(emptyMetrics);
213 }
214 #endif
215
216 bool WebResourceLoader::isAlwaysOnLoggingAllowed() const
217 {
218     return resourceLoader() && resourceLoader()->isAlwaysOnLoggingAllowed();
219 }
220
221 } // namespace WebKit