588568e89b331b8f867be2826f157416db1dc61a
[WebKit-https.git] / Source / WebKit / NetworkProcess / PingLoad.cpp
1 /*
2  * Copyright (C) 2016-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 "PingLoad.h"
28
29 #if USE(NETWORK_SESSION)
30
31 #include "AuthenticationManager.h"
32 #include "Logging.h"
33 #include "NetworkCORSPreflightChecker.h"
34 #include "SessionTracker.h"
35 #include <WebCore/ContentSecurityPolicy.h>
36 #include <WebCore/CrossOriginAccessControl.h>
37
38 #define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(m_parameters.sessionID.isAlwaysOnLoggingAllowed(), Network, "%p - PingLoad::" fmt, this, ##__VA_ARGS__)
39
40 namespace WebKit {
41
42 using namespace WebCore;
43
44 PingLoad::PingLoad(NetworkResourceLoadParameters&& parameters)
45     : m_parameters(WTFMove(parameters))
46     , m_timeoutTimer(*this, &PingLoad::timeoutTimerFired)
47     , m_isSameOriginRequest(securityOrigin().canRequest(m_parameters.request.url()))
48 {
49     // If the server never responds, this object will hang around forever.
50     // Set a very generous timeout, just in case.
51     m_timeoutTimer.startOneShot(60000_s);
52
53     if (needsCORSPreflight(m_parameters.request))
54         doCORSPreflight(m_parameters.request);
55     else
56         loadRequest(m_parameters.request);
57 }
58
59 PingLoad::~PingLoad()
60 {
61     if (m_redirectHandler)
62         m_redirectHandler({ });
63
64     if (m_task) {
65         ASSERT(m_task->client() == this);
66         m_task->clearClient();
67         m_task->cancel();
68     }
69 }
70
71 void PingLoad::loadRequest(const ResourceRequest& request)
72 {
73     RELEASE_LOG_IF_ALLOWED("startNetworkLoad");
74     if (auto* networkSession = SessionTracker::networkSession(m_parameters.sessionID)) {
75         auto loadParameters = m_parameters;
76         loadParameters.request = request;
77         m_task = NetworkDataTask::create(*networkSession, *this, WTFMove(loadParameters));
78         m_task->resume();
79     } else
80         ASSERT_NOT_REACHED();
81 }
82
83 SecurityOrigin& PingLoad::securityOrigin() const
84 {
85     return m_origin ? *m_origin : *m_parameters.sourceOrigin;
86 }
87
88 void PingLoad::willPerformHTTPRedirection(ResourceResponse&& redirectResponse, ResourceRequest&& request, RedirectCompletionHandler&& completionHandler)
89 {
90     RELEASE_LOG_IF_ALLOWED("willPerformHTTPRedirection - shouldFollowRedirects? %d", m_parameters.shouldFollowRedirects);
91     if (!m_parameters.shouldFollowRedirects) {
92         completionHandler({ });
93         return;
94     }
95
96     if (auto* contentSecurityPolicy = this->contentSecurityPolicy()) {
97         if (!contentSecurityPolicy->allowConnectToSource(request.url(), redirectResponse.isNull() ? ContentSecurityPolicy::RedirectResponseReceived::No : ContentSecurityPolicy::RedirectResponseReceived::Yes)) {
98             RELEASE_LOG_IF_ALLOWED("willPerformHTTPRedirection - Redirect was blocked by CSP");
99             completionHandler({ });
100             return;
101         }
102     }
103
104     // FIXME: We should ensure the number of redirects does not exceed 20.
105
106     if (!needsCORSPreflight(request)) {
107         completionHandler(request);
108         return;
109     }
110     RELEASE_LOG_IF_ALLOWED("willPerformHTTPRedirection - Redirect requires a CORS preflight");
111
112     // Use a unique origin for subsequent loads if needed.
113     // https://fetch.spec.whatwg.org/#concept-http-redirect-fetch (Step 10).
114     ASSERT(m_parameters.mode == FetchOptions::Mode::Cors);
115     if (!securityOrigin().canRequest(redirectResponse.url()) && !protocolHostAndPortAreEqual(redirectResponse.url(), request.url())) {
116         if (!m_origin || !m_origin->isUnique())
117             m_origin = SecurityOrigin::createUnique();
118     }
119
120     m_isSameOriginRequest = false;
121     m_redirectHandler = WTFMove(completionHandler);
122
123     // Let's fetch the request with the original headers (equivalent to request cloning specified by fetch algorithm).
124     request.setHTTPHeaderFields(m_parameters.request.httpHeaderFields());
125
126     doCORSPreflight(request);
127 }
128
129 void PingLoad::didReceiveChallenge(const AuthenticationChallenge&, ChallengeCompletionHandler&& completionHandler)
130 {
131     RELEASE_LOG_IF_ALLOWED("didReceiveChallenge");
132     completionHandler(AuthenticationChallengeDisposition::Cancel, { });
133     delete this;
134 }
135
136 void PingLoad::didReceiveResponseNetworkSession(ResourceResponse&& response, ResponseCompletionHandler&& completionHandler)
137 {
138     RELEASE_LOG_IF_ALLOWED("didReceiveResponseNetworkSession - httpStatusCode: %d", response.httpStatusCode());
139     completionHandler(PolicyAction::PolicyIgnore);
140     delete this;
141 }
142
143 void PingLoad::didReceiveData(Ref<SharedBuffer>&&)
144 {
145     RELEASE_LOG_IF_ALLOWED("didReceiveData");
146     ASSERT_NOT_REACHED();
147 }
148
149 void PingLoad::didCompleteWithError(const ResourceError& error, const NetworkLoadMetrics&)
150 {
151     if (error.isNull())
152         RELEASE_LOG_IF_ALLOWED("didComplete");
153     else
154         RELEASE_LOG_IF_ALLOWED("didCompleteWithError, error_code: %d", error.errorCode());
155     delete this;
156 }
157
158 void PingLoad::didSendData(uint64_t totalBytesSent, uint64_t totalBytesExpectedToSend)
159 {
160 }
161
162 void PingLoad::wasBlocked()
163 {
164     RELEASE_LOG_IF_ALLOWED("wasBlocked");
165     delete this;
166 }
167
168 void PingLoad::cannotShowURL()
169 {
170     RELEASE_LOG_IF_ALLOWED("cannotShowURL");
171     delete this;
172 }
173
174 void PingLoad::timeoutTimerFired()
175 {
176     RELEASE_LOG_IF_ALLOWED("timeoutTimerFired");
177     delete this;
178 }
179
180 bool PingLoad::needsCORSPreflight(const ResourceRequest& request) const
181 {
182     if (m_parameters.mode == FetchOptions::Mode::NoCors)
183         return false;
184
185     return !m_isSameOriginRequest || !securityOrigin().canRequest(request.url());
186 }
187
188 ContentSecurityPolicy* PingLoad::contentSecurityPolicy() const
189 {
190     if (!m_contentSecurityPolicy && m_parameters.cspResponseHeaders) {
191         m_contentSecurityPolicy = std::make_unique<ContentSecurityPolicy>(*m_parameters.sourceOrigin);
192         m_contentSecurityPolicy->didReceiveHeaders(*m_parameters.cspResponseHeaders, ContentSecurityPolicy::ReportParsingErrors::No);
193     }
194     return m_contentSecurityPolicy.get();
195 }
196
197 void PingLoad::doCORSPreflight(const ResourceRequest& request)
198 {
199     RELEASE_LOG_IF_ALLOWED("doCORSPreflight");
200     ASSERT(!m_corsPreflightChecker);
201
202     NetworkCORSPreflightChecker::Parameters parameters = {
203         request,
204         securityOrigin(),
205         m_parameters.sessionID,
206         m_parameters.allowStoredCredentials
207     };
208     m_corsPreflightChecker = std::make_unique<NetworkCORSPreflightChecker>(WTFMove(parameters), [this](NetworkCORSPreflightChecker::Result result) {
209         RELEASE_LOG_IF_ALLOWED("doCORSPreflight complete, success: %d forRedirect? %d", result == NetworkCORSPreflightChecker::Result::Success, !!m_redirectHandler);
210         auto corsPreflightChecker = WTFMove(m_corsPreflightChecker);
211         if (result == NetworkCORSPreflightChecker::Result::Success) {
212             ResourceRequest actualRequest = corsPreflightChecker->originalRequest();
213             updateRequestForAccessControl(actualRequest, securityOrigin(), m_parameters.allowStoredCredentials);
214             if (auto redirectHandler = std::exchange(m_redirectHandler, nullptr))
215                 redirectHandler(actualRequest);
216             else
217                 loadRequest(actualRequest);
218         } else
219             delete this;
220     });
221     m_corsPreflightChecker->startPreflight();
222 }
223
224 } // namespace WebKit
225
226 #endif // USE(NETWORK_SESSION)