logo

WebKitGTK

Collection of patches on top of WebKitGTK

NetworkResourceLoader.cpp (66106B)


  1. /*
  2. * Copyright (C) 2012-2019 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. #include "config.h"
  26. #include "NetworkResourceLoader.h"
  27. #include "DataReference.h"
  28. #include "FormDataReference.h"
  29. #include "Logging.h"
  30. #include "NetworkCache.h"
  31. #include "NetworkCacheSpeculativeLoadManager.h"
  32. #include "NetworkConnectionToWebProcess.h"
  33. #include "NetworkConnectionToWebProcessMessages.h"
  34. #include "NetworkLoad.h"
  35. #include "NetworkLoadChecker.h"
  36. #include "NetworkProcess.h"
  37. #include "NetworkProcessConnectionMessages.h"
  38. #include "NetworkProcessProxyMessages.h"
  39. #include "NetworkSession.h"
  40. #include "ResourceLoadInfo.h"
  41. #include "ServiceWorkerFetchTask.h"
  42. #include "SharedBufferDataReference.h"
  43. #include "WebCoreArgumentCoders.h"
  44. #include "WebErrors.h"
  45. #include "WebPageMessages.h"
  46. #include "WebResourceLoaderMessages.h"
  47. #include "WebSWServerConnection.h"
  48. #include "WebsiteDataStoreParameters.h"
  49. #include <WebCore/BlobDataFileReference.h>
  50. #include <WebCore/CertificateInfo.h>
  51. #include <WebCore/ContentSecurityPolicy.h>
  52. #include <WebCore/DiagnosticLoggingKeys.h>
  53. #include <WebCore/HTTPParsers.h>
  54. #include <WebCore/NetworkLoadMetrics.h>
  55. #include <WebCore/NetworkStorageSession.h>
  56. #include <WebCore/RegistrableDomain.h>
  57. #include <WebCore/SameSiteInfo.h>
  58. #include <WebCore/SecurityOrigin.h>
  59. #include <WebCore/SharedBuffer.h>
  60. #include <wtf/RunLoop.h>
  61. #if USE(QUICK_LOOK)
  62. #include <WebCore/PreviewConverter.h>
  63. #endif
  64. #define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), Network, "%p - [pageProxyID=%" PRIu64 ", webPageID=%" PRIu64 ", frameID=%" PRIu64 ", resourceID=%" PRIu64 ", isMainResource=%d, destination=%u, isSynchronous=%d] NetworkResourceLoader::" fmt, this, m_parameters.webPageProxyID.toUInt64(), m_parameters.webPageID.toUInt64(), m_parameters.webFrameID.toUInt64(), m_parameters.identifier, isMainResource(), static_cast<unsigned>(m_parameters.options.destination), isSynchronous(), ##__VA_ARGS__)
  65. #define RELEASE_LOG_ERROR_IF_ALLOWED(fmt, ...) RELEASE_LOG_ERROR_IF(isAlwaysOnLoggingAllowed(), Network, "%p - [pageProxyID=%" PRIu64 ", webPageID=%" PRIu64 ", frameID=%" PRIu64 ", resourceID=%" PRIu64 ", isMainResource=%d, destination=%u, isSynchronous=%d] NetworkResourceLoader::" fmt, this, m_parameters.webPageProxyID.toUInt64(), m_parameters.webPageID.toUInt64(), m_parameters.webFrameID.toUInt64(), m_parameters.identifier, isMainResource(), static_cast<unsigned>(m_parameters.options.destination), isSynchronous(), ##__VA_ARGS__)
  66. namespace WebKit {
  67. using namespace WebCore;
  68. struct NetworkResourceLoader::SynchronousLoadData {
  69. WTF_MAKE_STRUCT_FAST_ALLOCATED;
  70. SynchronousLoadData(Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply&& reply)
  71. : delayedReply(WTFMove(reply))
  72. {
  73. ASSERT(delayedReply);
  74. }
  75. ResourceRequest currentRequest;
  76. Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply delayedReply;
  77. ResourceResponse response;
  78. ResourceError error;
  79. };
  80. static void sendReplyToSynchronousRequest(NetworkResourceLoader::SynchronousLoadData& data, const SharedBuffer* buffer)
  81. {
  82. ASSERT(data.delayedReply);
  83. ASSERT(!data.response.isNull() || !data.error.isNull());
  84. Vector<char> responseBuffer;
  85. if (buffer && buffer->size())
  86. responseBuffer.append(buffer->data(), buffer->size());
  87. data.delayedReply(data.error, data.response, responseBuffer);
  88. data.delayedReply = nullptr;
  89. }
  90. NetworkResourceLoader::NetworkResourceLoader(NetworkResourceLoadParameters&& parameters, NetworkConnectionToWebProcess& connection, Messages::NetworkConnectionToWebProcess::PerformSynchronousLoad::DelayedReply&& synchronousReply)
  91. : m_parameters { WTFMove(parameters) }
  92. , m_connection { connection }
  93. , m_fileReferences(connection.resolveBlobReferences(m_parameters))
  94. , m_isAllowedToAskUserForCredentials { m_parameters.clientCredentialPolicy == ClientCredentialPolicy::MayAskClientForCredentials }
  95. , m_bufferingTimer { *this, &NetworkResourceLoader::bufferingTimerFired }
  96. , m_shouldCaptureExtraNetworkLoadMetrics(m_connection->captureExtraNetworkLoadMetricsEnabled())
  97. , m_resourceLoadID { NetworkResourceLoadIdentifier::generate() }
  98. {
  99. ASSERT(RunLoop::isMain());
  100. if (auto* session = connection.networkProcess().networkSession(sessionID()))
  101. m_cache = session->cache();
  102. // FIXME: This is necessary because of the existence of EmptyFrameLoaderClient in WebCore.
  103. // Once bug 116233 is resolved, this ASSERT can just be "m_webPageID && m_webFrameID"
  104. ASSERT((m_parameters.webPageID && m_parameters.webFrameID) || m_parameters.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials);
  105. if (synchronousReply || parameters.shouldRestrictHTTPResponseAccess || parameters.options.keepAlive) {
  106. NetworkLoadChecker::LoadType requestLoadType = isMainFrameLoad() ? NetworkLoadChecker::LoadType::MainFrame : NetworkLoadChecker::LoadType::Other;
  107. m_networkLoadChecker = makeUnique<NetworkLoadChecker>(connection.networkProcess(), &connection.schemeRegistry(), FetchOptions { m_parameters.options }, sessionID(), m_parameters.webPageProxyID, HTTPHeaderMap { m_parameters.originalRequestHeaders }, URL { m_parameters.request.url() }, m_parameters.sourceOrigin.copyRef(), m_parameters.topOrigin.copyRef(), m_parameters.preflightPolicy, originalRequest().httpReferrer(), m_parameters.isHTTPSUpgradeEnabled, shouldCaptureExtraNetworkLoadMetrics(), requestLoadType);
  108. if (m_parameters.cspResponseHeaders)
  109. m_networkLoadChecker->setCSPResponseHeaders(ContentSecurityPolicyResponseHeaders { m_parameters.cspResponseHeaders.value() });
  110. #if ENABLE(CONTENT_EXTENSIONS)
  111. m_networkLoadChecker->setContentExtensionController(URL { m_parameters.mainDocumentURL }, m_parameters.userContentControllerIdentifier);
  112. #endif
  113. }
  114. if (synchronousReply)
  115. m_synchronousLoadData = makeUnique<SynchronousLoadData>(WTFMove(synchronousReply));
  116. }
  117. NetworkResourceLoader::~NetworkResourceLoader()
  118. {
  119. ASSERT(RunLoop::isMain());
  120. ASSERT(!m_networkLoad);
  121. ASSERT(!isSynchronous() || !m_synchronousLoadData->delayedReply);
  122. ASSERT(m_fileReferences.isEmpty());
  123. if (m_responseCompletionHandler)
  124. m_responseCompletionHandler(PolicyAction::Ignore);
  125. }
  126. bool NetworkResourceLoader::canUseCache(const ResourceRequest& request) const
  127. {
  128. if (!m_cache)
  129. return false;
  130. ASSERT(!sessionID().isEphemeral());
  131. if (!request.url().protocolIsInHTTPFamily())
  132. return false;
  133. if (originalRequest().cachePolicy() == WebCore::ResourceRequestCachePolicy::DoNotUseAnyCache)
  134. return false;
  135. return true;
  136. }
  137. bool NetworkResourceLoader::canUseCachedRedirect(const ResourceRequest& request) const
  138. {
  139. if (!canUseCache(request) || m_cacheEntryForMaxAgeCapValidation)
  140. return false;
  141. // Limit cached redirects to avoid cycles and other trouble.
  142. // Networking layer follows over 30 redirects but caching that many seems unnecessary.
  143. static const unsigned maximumCachedRedirectCount { 5 };
  144. if (m_redirectCount > maximumCachedRedirectCount)
  145. return false;
  146. return true;
  147. }
  148. bool NetworkResourceLoader::isSynchronous() const
  149. {
  150. return !!m_synchronousLoadData;
  151. }
  152. void NetworkResourceLoader::start()
  153. {
  154. ASSERT(RunLoop::isMain());
  155. RELEASE_LOG_IF_ALLOWED("start: parentPID=%d, hasNetworkLoadChecker=%d", m_parameters.parentPID, !!m_networkLoadChecker);
  156. m_networkActivityTracker = m_connection->startTrackingResourceLoad(m_parameters.webPageID, m_parameters.identifier, isMainFrameLoad());
  157. ASSERT(!m_wasStarted);
  158. m_wasStarted = true;
  159. if (m_networkLoadChecker) {
  160. m_networkLoadChecker->check(ResourceRequest { originalRequest() }, this, [this, weakThis = makeWeakPtr(*this)] (auto&& result) {
  161. if (!weakThis)
  162. return;
  163. WTF::switchOn(result,
  164. [this] (ResourceError& error) {
  165. RELEASE_LOG_IF_ALLOWED("start: NetworkLoadChecker::check returned an error (error.domain=%{public}s, error.code=%d, isCancellation=%d)", error.domain().utf8().data(), error.errorCode(), error.isCancellation());
  166. if (!error.isCancellation())
  167. this->didFailLoading(error);
  168. },
  169. [this] (NetworkLoadChecker::RedirectionTriplet& triplet) {
  170. RELEASE_LOG_IF_ALLOWED("start: NetworkLoadChecker::check returned a synthetic redirect");
  171. this->m_isWaitingContinueWillSendRequestForCachedRedirect = true;
  172. this->willSendRedirectedRequest(WTFMove(triplet.request), WTFMove(triplet.redirectRequest), WTFMove(triplet.redirectResponse));
  173. },
  174. [this] (ResourceRequest& request) {
  175. RELEASE_LOG_IF_ALLOWED("start: NetworkLoadChecker::check is done");
  176. if (this->canUseCache(request)) {
  177. this->retrieveCacheEntry(request);
  178. return;
  179. }
  180. this->startNetworkLoad(WTFMove(request), FirstLoad::Yes);
  181. }
  182. );
  183. });
  184. return;
  185. }
  186. // FIXME: Remove that code path once m_networkLoadChecker is used for all network loads.
  187. if (canUseCache(originalRequest())) {
  188. retrieveCacheEntry(originalRequest());
  189. return;
  190. }
  191. startNetworkLoad(ResourceRequest { originalRequest() }, FirstLoad::Yes);
  192. }
  193. void NetworkResourceLoader::retrieveCacheEntry(const ResourceRequest& request)
  194. {
  195. RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: isMainFrameLoad=%d", isMainFrameLoad());
  196. ASSERT(canUseCache(request));
  197. auto protectedThis = makeRef(*this);
  198. if (isMainFrameLoad()) {
  199. ASSERT(m_parameters.options.mode == FetchOptions::Mode::Navigate);
  200. if (auto* session = m_connection->networkProcess().networkSession(sessionID())) {
  201. if (auto entry = session->prefetchCache().take(request.url())) {
  202. RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: retrieved an entry from the prefetch cache (isRedirect=%d)", !entry->redirectRequest.isNull());
  203. // FIXME: Deal with credentials (https://bugs.webkit.org/show_bug.cgi?id=200000)
  204. if (!entry->redirectRequest.isNull()) {
  205. auto cacheEntry = m_cache->makeRedirectEntry(request, entry->response, entry->redirectRequest);
  206. retrieveCacheEntryInternal(WTFMove(cacheEntry), ResourceRequest { request });
  207. auto maxAgeCap = validateCacheEntryForMaxAgeCapValidation(request, entry->redirectRequest, entry->response);
  208. m_cache->storeRedirect(request, entry->response, entry->redirectRequest, maxAgeCap);
  209. return;
  210. }
  211. auto buffer = entry->releaseBuffer();
  212. auto cacheEntry = m_cache->makeEntry(request, entry->response, buffer.copyRef());
  213. retrieveCacheEntryInternal(WTFMove(cacheEntry), ResourceRequest { request });
  214. m_cache->store(request, entry->response, WTFMove(buffer));
  215. return;
  216. }
  217. }
  218. }
  219. RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Checking the HTTP disk cache");
  220. m_cache->retrieve(request, globalFrameID(), [this, weakThis = makeWeakPtr(*this), request = ResourceRequest { request }](auto entry, auto info) mutable {
  221. if (!weakThis)
  222. return;
  223. RELEASE_LOG_IF_ALLOWED("retrieveCacheEntry: Done checking the HTTP disk cache (foundCachedEntry=%d)", !!entry);
  224. logSlowCacheRetrieveIfNeeded(info);
  225. if (!entry) {
  226. startNetworkLoad(WTFMove(request), FirstLoad::Yes);
  227. return;
  228. }
  229. retrieveCacheEntryInternal(WTFMove(entry), WTFMove(request));
  230. });
  231. }
  232. void NetworkResourceLoader::retrieveCacheEntryInternal(std::unique_ptr<NetworkCache::Entry>&& entry, WebCore::ResourceRequest&& request)
  233. {
  234. RELEASE_LOG_IF_ALLOWED("retrieveCacheEntryInternal:");
  235. #if ENABLE(RESOURCE_LOAD_STATISTICS)
  236. if (entry->hasReachedPrevalentResourceAgeCap()) {
  237. RELEASE_LOG_IF_ALLOWED("retrieveCacheEntryInternal: Revalidating cached entry because it reached the prevalent resource age cap");
  238. m_cacheEntryForMaxAgeCapValidation = WTFMove(entry);
  239. ResourceRequest revalidationRequest = originalRequest();
  240. startNetworkLoad(WTFMove(revalidationRequest), FirstLoad::Yes);
  241. return;
  242. }
  243. #endif
  244. if (entry->redirectRequest()) {
  245. RELEASE_LOG_IF_ALLOWED("retrieveCacheEntryInternal: Cached entry is a redirect");
  246. dispatchWillSendRequestForCacheEntry(WTFMove(request), WTFMove(entry));
  247. return;
  248. }
  249. if (m_parameters.needsCertificateInfo && !entry->response().certificateInfo()) {
  250. RELEASE_LOG_IF_ALLOWED("retrieveCacheEntryInternal: Cached entry is missing certificate information so we are not using it");
  251. startNetworkLoad(WTFMove(request), FirstLoad::Yes);
  252. return;
  253. }
  254. if (entry->needsValidation() || request.cachePolicy() == WebCore::ResourceRequestCachePolicy::RefreshAnyCacheData) {
  255. RELEASE_LOG_IF_ALLOWED("retrieveCacheEntryInternal: Cached entry needs revalidation");
  256. validateCacheEntry(WTFMove(entry));
  257. return;
  258. }
  259. RELEASE_LOG_IF_ALLOWED("retrieveCacheEntryInternal: Cached entry is directly usable");
  260. didRetrieveCacheEntry(WTFMove(entry));
  261. }
  262. void NetworkResourceLoader::startNetworkLoad(ResourceRequest&& request, FirstLoad load)
  263. {
  264. RELEASE_LOG_IF_ALLOWED("startNetworkLoad: (isFirstLoad=%d, timeout=%f)", load == FirstLoad::Yes, request.timeoutInterval());
  265. if (load == FirstLoad::Yes) {
  266. consumeSandboxExtensions();
  267. if (isSynchronous() || m_parameters.maximumBufferingTime > 0_s)
  268. m_bufferedData = SharedBuffer::create();
  269. if (canUseCache(request))
  270. m_bufferedDataForCache = SharedBuffer::create();
  271. }
  272. NetworkLoadParameters parameters = m_parameters;
  273. parameters.networkActivityTracker = m_networkActivityTracker;
  274. if (parameters.storedCredentialsPolicy == WebCore::StoredCredentialsPolicy::Use && m_networkLoadChecker)
  275. parameters.storedCredentialsPolicy = m_networkLoadChecker->storedCredentialsPolicy();
  276. auto* networkSession = m_connection->networkSession();
  277. if (!networkSession) {
  278. WTFLogAlways("Attempted to create a NetworkLoad with a session (id=%" PRIu64 ") that does not exist.", sessionID().toUInt64());
  279. RELEASE_LOG_ERROR_IF_ALLOWED("startNetworkLoad: Attempted to create a NetworkLoad for a session that does not exist (sessionID=%" PRIu64 ")", sessionID().toUInt64());
  280. m_connection->networkProcess().logDiagnosticMessage(m_parameters.webPageProxyID, WebCore::DiagnosticLoggingKeys::internalErrorKey(), WebCore::DiagnosticLoggingKeys::invalidSessionIDKey(), WebCore::ShouldSample::No);
  281. didFailLoading(internalError(request.url()));
  282. return;
  283. }
  284. if (request.url().protocolIsBlob())
  285. parameters.blobFileReferences = networkSession->blobRegistry().filesInBlob(originalRequest().url());
  286. if (m_parameters.pageHasResourceLoadClient)
  287. m_connection->networkProcess().parentProcessConnection()->send(Messages::NetworkProcessProxy::ResourceLoadDidSendRequest(m_parameters.webPageProxyID, resourceLoadInfo(), request), 0);
  288. parameters.request = WTFMove(request);
  289. m_networkLoad = makeUnique<NetworkLoad>(*this, &networkSession->blobRegistry(), WTFMove(parameters), *networkSession);
  290. RELEASE_LOG_IF_ALLOWED("startNetworkLoad: Going to the network (description=%{public}s)", m_networkLoad->description().utf8().data());
  291. }
  292. ResourceLoadInfo NetworkResourceLoader::resourceLoadInfo()
  293. {
  294. return {
  295. m_resourceLoadID,
  296. m_parameters.webFrameID,
  297. m_parameters.parentFrameID,
  298. };
  299. }
  300. void NetworkResourceLoader::cleanup(LoadResult result)
  301. {
  302. ASSERT(RunLoop::isMain());
  303. RELEASE_LOG_IF_ALLOWED("cleanup: (result=%u)", static_cast<unsigned>(result));
  304. NetworkActivityTracker::CompletionCode code { };
  305. switch (result) {
  306. case LoadResult::Unknown:
  307. code = NetworkActivityTracker::CompletionCode::Undefined;
  308. break;
  309. case LoadResult::Success:
  310. code = NetworkActivityTracker::CompletionCode::Success;
  311. break;
  312. case LoadResult::Failure:
  313. code = NetworkActivityTracker::CompletionCode::Failure;
  314. break;
  315. case LoadResult::Cancel:
  316. code = NetworkActivityTracker::CompletionCode::Cancel;
  317. break;
  318. }
  319. m_connection->stopTrackingResourceLoad(m_parameters.identifier, code);
  320. m_bufferingTimer.stop();
  321. invalidateSandboxExtensions();
  322. m_networkLoad = nullptr;
  323. // This will cause NetworkResourceLoader to be destroyed and therefore we do it last.
  324. m_connection->didCleanupResourceLoader(*this);
  325. }
  326. void NetworkResourceLoader::convertToDownload(DownloadID downloadID, const ResourceRequest& request, const ResourceResponse& response)
  327. {
  328. RELEASE_LOG_IF_ALLOWED("convertToDownload: (downloadID=%" PRIu64 ", hasNetworkLoad=%d, hasResponseCompletionHandler=%d)", downloadID.downloadID(), !!m_networkLoad, !!m_responseCompletionHandler);
  329. // This can happen if the resource came from the disk cache.
  330. if (!m_networkLoad) {
  331. m_connection->networkProcess().downloadManager().startDownload(sessionID(), downloadID, request);
  332. abort();
  333. return;
  334. }
  335. if (m_responseCompletionHandler)
  336. m_connection->networkProcess().downloadManager().convertNetworkLoadToDownload(downloadID, std::exchange(m_networkLoad, nullptr), WTFMove(m_responseCompletionHandler), WTFMove(m_fileReferences), request, response);
  337. }
  338. void NetworkResourceLoader::abort()
  339. {
  340. RELEASE_LOG_IF_ALLOWED("abort: (hasNetworkLoad=%d)", !!m_networkLoad);
  341. ASSERT(RunLoop::isMain());
  342. if (m_parameters.options.keepAlive && m_response.isNull() && !m_isKeptAlive) {
  343. m_isKeptAlive = true;
  344. RELEASE_LOG_IF_ALLOWED("abort: Keeping network load alive due to keepalive option");
  345. m_connection->transferKeptAliveLoad(*this);
  346. return;
  347. }
  348. #if ENABLE(SERVICE_WORKER)
  349. if (auto task = WTFMove(m_serviceWorkerFetchTask)) {
  350. RELEASE_LOG_IF_ALLOWED("abort: Cancelling pending service worker fetch task (fetchIdentifier=%" PRIu64 ")", task->fetchIdentifier().toUInt64());
  351. task->cancelFromClient();
  352. }
  353. #endif
  354. if (m_networkLoad) {
  355. if (canUseCache(m_networkLoad->currentRequest())) {
  356. // We might already have used data from this incomplete load. Ensure older versions don't remain in the cache after cancel.
  357. if (!m_response.isNull())
  358. m_cache->remove(m_networkLoad->currentRequest());
  359. }
  360. RELEASE_LOG_IF_ALLOWED("abort: Cancelling network load");
  361. m_networkLoad->cancel();
  362. }
  363. cleanup(LoadResult::Cancel);
  364. }
  365. bool NetworkResourceLoader::shouldInterruptLoadForXFrameOptions(const String& xFrameOptions, const URL& url)
  366. {
  367. if (isMainFrameLoad())
  368. return false;
  369. switch (parseXFrameOptionsHeader(xFrameOptions)) {
  370. case XFrameOptionsNone:
  371. case XFrameOptionsAllowAll:
  372. return false;
  373. case XFrameOptionsDeny:
  374. return true;
  375. case XFrameOptionsSameOrigin: {
  376. auto origin = SecurityOrigin::create(url);
  377. auto topFrameOrigin = m_parameters.frameAncestorOrigins.last();
  378. if (!origin->isSameSchemeHostPort(*topFrameOrigin))
  379. return true;
  380. for (auto& ancestorOrigin : m_parameters.frameAncestorOrigins) {
  381. if (!origin->isSameSchemeHostPort(*ancestorOrigin))
  382. return true;
  383. }
  384. return false;
  385. }
  386. case XFrameOptionsConflict: {
  387. String errorMessage = "Multiple 'X-Frame-Options' headers with conflicting values ('" + xFrameOptions + "') encountered when loading '" + url.stringCenterEllipsizedToLength() + "'. Falling back to 'DENY'.";
  388. send(Messages::WebPage::AddConsoleMessage { m_parameters.webFrameID, MessageSource::JS, MessageLevel::Error, errorMessage, identifier() }, m_parameters.webPageID);
  389. return true;
  390. }
  391. case XFrameOptionsInvalid: {
  392. String errorMessage = "Invalid 'X-Frame-Options' header encountered when loading '" + url.stringCenterEllipsizedToLength() + "': '" + xFrameOptions + "' is not a recognized directive. The header will be ignored.";
  393. send(Messages::WebPage::AddConsoleMessage { m_parameters.webFrameID, MessageSource::JS, MessageLevel::Error, errorMessage, identifier() }, m_parameters.webPageID);
  394. return false;
  395. }
  396. }
  397. ASSERT_NOT_REACHED();
  398. return false;
  399. }
  400. bool NetworkResourceLoader::shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions(const ResourceResponse& response)
  401. {
  402. ASSERT(isMainResource());
  403. #if USE(QUICK_LOOK)
  404. if (PreviewConverter::supportsMIMEType(response.mimeType()))
  405. return false;
  406. #endif
  407. auto url = response.url();
  408. ContentSecurityPolicy contentSecurityPolicy { URL { url }, this };
  409. contentSecurityPolicy.didReceiveHeaders(ContentSecurityPolicyResponseHeaders { response }, originalRequest().httpReferrer());
  410. if (!contentSecurityPolicy.allowFrameAncestors(m_parameters.frameAncestorOrigins, url))
  411. return true;
  412. if (!contentSecurityPolicy.overridesXFrameOptions()) {
  413. String xFrameOptions = m_response.httpHeaderField(HTTPHeaderName::XFrameOptions);
  414. if (!xFrameOptions.isNull() && shouldInterruptLoadForXFrameOptions(xFrameOptions, response.url())) {
  415. String errorMessage = "Refused to display '" + response.url().stringCenterEllipsizedToLength() + "' in a frame because it set 'X-Frame-Options' to '" + xFrameOptions + "'.";
  416. send(Messages::WebPage::AddConsoleMessage { m_parameters.webFrameID, MessageSource::Security, MessageLevel::Error, errorMessage, identifier() }, m_parameters.webPageID);
  417. return true;
  418. }
  419. }
  420. return false;
  421. }
  422. void NetworkResourceLoader::didReceiveResponse(ResourceResponse&& receivedResponse, ResponseCompletionHandler&& completionHandler)
  423. {
  424. RELEASE_LOG_IF_ALLOWED("didReceiveResponse: (httpStatusCode=%d, MIMEType=%{public}s, expectedContentLength=%" PRId64 ", hasCachedEntryForValidation=%d, hasNetworkLoadChecker=%d)", receivedResponse.httpStatusCode(), receivedResponse.mimeType().utf8().data(), receivedResponse.expectedContentLength(), !!m_cacheEntryForValidation, !!m_networkLoadChecker);
  425. if (isMainResource())
  426. didReceiveMainResourceResponse(receivedResponse);
  427. m_response = WTFMove(receivedResponse);
  428. if (shouldCaptureExtraNetworkLoadMetrics() && m_networkLoadChecker) {
  429. auto information = m_networkLoadChecker->takeNetworkLoadInformation();
  430. information.response = m_response;
  431. m_connection->addNetworkLoadInformation(identifier(), WTFMove(information));
  432. }
  433. // For multipart/x-mixed-replace didReceiveResponseAsync gets called multiple times and buffering would require special handling.
  434. if (!isSynchronous() && m_response.isMultipart())
  435. m_bufferedData = nullptr;
  436. if (m_response.isMultipart())
  437. m_bufferedDataForCache = nullptr;
  438. if (m_cacheEntryForValidation) {
  439. m_cacheEntryForValidation = nullptr;
  440. }
  441. if (m_cacheEntryForValidation)
  442. return completionHandler(PolicyAction::Use);
  443. if (isMainResource() && shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions(m_response)) {
  444. RELEASE_LOG_ERROR_IF_ALLOWED("didReceiveResponse: Interrupting main resource load due to CSP frame-ancestors or X-Frame-Options");
  445. auto response = sanitizeResponseIfPossible(ResourceResponse { m_response }, ResourceResponse::SanitizationType::CrossOriginSafe);
  446. send(Messages::WebResourceLoader::StopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied { response });
  447. return completionHandler(PolicyAction::Ignore);
  448. }
  449. if (m_networkLoadChecker) {
  450. auto error = m_networkLoadChecker->validateResponse(m_networkLoad ? m_networkLoad->currentRequest() : originalRequest(), m_response);
  451. if (!error.isNull()) {
  452. RELEASE_LOG_ERROR_IF_ALLOWED("didReceiveResponse: NetworkLoadChecker::validateResponse returned an error (error.domain=%{public}s, error.code=%d)", error.domain().utf8().data(), error.errorCode());
  453. RunLoop::main().dispatch([protectedThis = makeRef(*this), error = WTFMove(error)] {
  454. if (protectedThis->m_networkLoad)
  455. protectedThis->didFailLoading(error);
  456. });
  457. return completionHandler(PolicyAction::Ignore);
  458. }
  459. }
  460. auto response = sanitizeResponseIfPossible(ResourceResponse { m_response }, ResourceResponse::SanitizationType::CrossOriginSafe);
  461. if (isSynchronous()) {
  462. RELEASE_LOG_IF_ALLOWED("didReceiveResponse: Using response for synchronous load");
  463. m_synchronousLoadData->response = WTFMove(response);
  464. return completionHandler(PolicyAction::Use);
  465. }
  466. if (isCrossOriginPrefetch()) {
  467. RELEASE_LOG_IF_ALLOWED("didReceiveResponse: Using response for cross-origin prefetch");
  468. return completionHandler(PolicyAction::Use);
  469. }
  470. // We wait to receive message NetworkResourceLoader::ContinueDidReceiveResponse before continuing a load for
  471. // a main resource because the embedding client must decide whether to allow the load.
  472. bool willWaitForContinueDidReceiveResponse = isMainResource();
  473. RELEASE_LOG_IF_ALLOWED("didReceiveResponse: Sending WebResourceLoader::DidReceiveResponse IPC (willWaitForContinueDidReceiveResponse=%d)", willWaitForContinueDidReceiveResponse);
  474. send(Messages::WebResourceLoader::DidReceiveResponse { response, willWaitForContinueDidReceiveResponse });
  475. if (m_parameters.pageHasResourceLoadClient)
  476. m_connection->networkProcess().parentProcessConnection()->send(Messages::NetworkProcessProxy::ResourceLoadDidReceiveResponse(m_parameters.webPageProxyID, resourceLoadInfo(), response), 0);
  477. if (willWaitForContinueDidReceiveResponse) {
  478. m_responseCompletionHandler = WTFMove(completionHandler);
  479. return;
  480. }
  481. if (m_isKeptAlive) {
  482. RELEASE_LOG_IF_ALLOWED("didReceiveResponse: Ignoring response because of keepalive option");
  483. return completionHandler(PolicyAction::Ignore);
  484. }
  485. RELEASE_LOG_IF_ALLOWED("didReceiveResponse: Using response");
  486. completionHandler(PolicyAction::Use);
  487. }
  488. void NetworkResourceLoader::didReceiveBuffer(Ref<SharedBuffer>&& buffer, int reportedEncodedDataLength)
  489. {
  490. if (!m_numBytesReceived)
  491. RELEASE_LOG_IF_ALLOWED("didReceiveBuffer: Started receiving data (reportedEncodedDataLength=%d)", reportedEncodedDataLength);
  492. m_numBytesReceived += buffer->size();
  493. ASSERT(!m_cacheEntryForValidation);
  494. if (m_bufferedDataForCache) {
  495. // Prevent memory growth in case of streaming data.
  496. const size_t maximumCacheBufferSize = 10 * 1024 * 1024;
  497. if (m_bufferedDataForCache->size() + buffer->size() <= maximumCacheBufferSize)
  498. m_bufferedDataForCache->append(buffer.get());
  499. else
  500. m_bufferedDataForCache = nullptr;
  501. }
  502. if (isCrossOriginPrefetch())
  503. return;
  504. // FIXME: At least on OS X Yosemite we always get -1 from the resource handle.
  505. unsigned encodedDataLength = reportedEncodedDataLength >= 0 ? reportedEncodedDataLength : buffer->size();
  506. if (m_bufferedData) {
  507. m_bufferedData->append(buffer.get());
  508. m_bufferedDataEncodedDataLength += encodedDataLength;
  509. startBufferingTimerIfNeeded();
  510. return;
  511. }
  512. sendBuffer(buffer, encodedDataLength);
  513. }
  514. void NetworkResourceLoader::didFinishLoading(const NetworkLoadMetrics& networkLoadMetrics)
  515. {
  516. RELEASE_LOG_IF_ALLOWED("didFinishLoading: (numBytesReceived=%zd, hasCacheEntryForValidation=%d)", m_numBytesReceived, !!m_cacheEntryForValidation);
  517. if (shouldCaptureExtraNetworkLoadMetrics())
  518. m_connection->addNetworkLoadInformationMetrics(identifier(), networkLoadMetrics);
  519. #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED
  520. if (shouldLogCookieInformation(m_connection, sessionID()))
  521. logCookieInformation();
  522. #endif
  523. if (isSynchronous())
  524. sendReplyToSynchronousRequest(*m_synchronousLoadData, m_bufferedData.get());
  525. else {
  526. if (m_bufferedData && !m_bufferedData->isEmpty()) {
  527. // FIXME: Pass a real value or remove the encoded data size feature.
  528. sendBuffer(*m_bufferedData, -1);
  529. }
  530. send(Messages::WebResourceLoader::DidFinishResourceLoad(networkLoadMetrics));
  531. }
  532. tryStoreAsCacheEntry();
  533. if (m_parameters.pageHasResourceLoadClient)
  534. m_connection->networkProcess().parentProcessConnection()->send(Messages::NetworkProcessProxy::ResourceLoadDidCompleteWithError(m_parameters.webPageProxyID, resourceLoadInfo(), { }), 0);
  535. cleanup(LoadResult::Success);
  536. }
  537. void NetworkResourceLoader::didFailLoading(const ResourceError& error)
  538. {
  539. bool wasServiceWorkerLoad = false;
  540. #if ENABLE(SERVICE_WORKER)
  541. wasServiceWorkerLoad = !!m_serviceWorkerFetchTask;
  542. #endif
  543. RELEASE_LOG_ERROR_IF_ALLOWED("didFailLoading: (wasServiceWorkerLoad=%d, isTimeout=%d, isCancellation=%d, isAccessControl=%d, errorCode=%d)", wasServiceWorkerLoad, error.isTimeout(), error.isCancellation(), error.isAccessControl(), error.errorCode());
  544. UNUSED_VARIABLE(wasServiceWorkerLoad);
  545. if (shouldCaptureExtraNetworkLoadMetrics())
  546. m_connection->removeNetworkLoadInformation(identifier());
  547. ASSERT(!error.isNull());
  548. m_cacheEntryForValidation = nullptr;
  549. if (isSynchronous()) {
  550. m_synchronousLoadData->error = error;
  551. sendReplyToSynchronousRequest(*m_synchronousLoadData, nullptr);
  552. } else if (auto* connection = messageSenderConnection()) {
  553. #if ENABLE(SERVICE_WORKER)
  554. if (m_serviceWorkerFetchTask)
  555. connection->send(Messages::WebResourceLoader::DidFailServiceWorkerLoad(error), messageSenderDestinationID());
  556. else
  557. connection->send(Messages::WebResourceLoader::DidFailResourceLoad(error), messageSenderDestinationID());
  558. #else
  559. connection->send(Messages::WebResourceLoader::DidFailResourceLoad(error), messageSenderDestinationID());
  560. #endif
  561. }
  562. if (m_parameters.pageHasResourceLoadClient)
  563. m_connection->networkProcess().parentProcessConnection()->send(Messages::NetworkProcessProxy::ResourceLoadDidCompleteWithError(m_parameters.webPageProxyID, resourceLoadInfo(), error), 0);
  564. cleanup(LoadResult::Failure);
  565. }
  566. void NetworkResourceLoader::didBlockAuthenticationChallenge()
  567. {
  568. RELEASE_LOG_IF_ALLOWED("didBlockAuthenticationChallenge:");
  569. send(Messages::WebResourceLoader::DidBlockAuthenticationChallenge());
  570. }
  571. void NetworkResourceLoader::didReceiveChallenge(const AuthenticationChallenge& challenge)
  572. {
  573. if (m_parameters.pageHasResourceLoadClient)
  574. m_connection->networkProcess().parentProcessConnection()->send(Messages::NetworkProcessProxy::ResourceLoadDidReceiveChallenge(m_parameters.webPageProxyID, resourceLoadInfo(), challenge), 0);
  575. }
  576. Optional<Seconds> NetworkResourceLoader::validateCacheEntryForMaxAgeCapValidation(const ResourceRequest& request, const ResourceRequest& redirectRequest, const ResourceResponse& redirectResponse)
  577. {
  578. #if ENABLE(RESOURCE_LOAD_STATISTICS)
  579. bool existingCacheEntryMatchesNewResponse = false;
  580. if (m_cacheEntryForMaxAgeCapValidation) {
  581. ASSERT(redirectResponse.source() == ResourceResponse::Source::Network);
  582. ASSERT(redirectResponse.isRedirection());
  583. if (redirectResponse.httpHeaderField(WebCore::HTTPHeaderName::Location) == m_cacheEntryForMaxAgeCapValidation->response().httpHeaderField(WebCore::HTTPHeaderName::Location))
  584. existingCacheEntryMatchesNewResponse = true;
  585. m_cache->remove(m_cacheEntryForMaxAgeCapValidation->key());
  586. m_cacheEntryForMaxAgeCapValidation = nullptr;
  587. }
  588. if (!existingCacheEntryMatchesNewResponse) {
  589. if (auto* networkStorageSession = m_connection->networkProcess().storageSession(sessionID()))
  590. return networkStorageSession->maxAgeCacheCap(request);
  591. }
  592. #endif
  593. return WTF::nullopt;
  594. }
  595. void NetworkResourceLoader::willSendRedirectedRequest(ResourceRequest&& request, ResourceRequest&& redirectRequest, ResourceResponse&& redirectResponse)
  596. {
  597. RELEASE_LOG_IF_ALLOWED("willSendRedirectedRequest:");
  598. ++m_redirectCount;
  599. m_redirectResponse = redirectResponse;
  600. Optional<AdClickAttribution::Conversion> adClickConversion;
  601. if (!sessionID().isEphemeral())
  602. adClickConversion = AdClickAttribution::parseConversionRequest(redirectRequest.url());
  603. auto maxAgeCap = validateCacheEntryForMaxAgeCapValidation(request, redirectRequest, redirectResponse);
  604. if (redirectResponse.source() == ResourceResponse::Source::Network && canUseCachedRedirect(request))
  605. m_cache->storeRedirect(request, redirectResponse, redirectRequest, maxAgeCap);
  606. if (m_networkLoadChecker) {
  607. if (adClickConversion)
  608. m_networkLoadChecker->enableContentExtensionsCheck();
  609. m_networkLoadChecker->storeRedirectionIfNeeded(request, redirectResponse);
  610. RELEASE_LOG_IF_ALLOWED("willSendRedirectedRequest: Checking redirect using NetworkLoadChecker");
  611. m_networkLoadChecker->checkRedirection(WTFMove(request), WTFMove(redirectRequest), WTFMove(redirectResponse), this, [protectedThis = makeRef(*this), this, storedCredentialsPolicy = m_networkLoadChecker->storedCredentialsPolicy(), adClickConversion = WTFMove(adClickConversion)](auto&& result) mutable {
  612. if (!result.has_value()) {
  613. if (result.error().isCancellation()) {
  614. RELEASE_LOG_IF_ALLOWED("willSendRedirectedRequest: NetworkLoadChecker::checkRedirection returned with a cancellation");
  615. return;
  616. }
  617. RELEASE_LOG_ERROR_IF_ALLOWED("willSendRedirectedRequest: NetworkLoadChecker::checkRedirection returned an error");
  618. this->didFailLoading(result.error());
  619. return;
  620. }
  621. RELEASE_LOG_IF_ALLOWED("willSendRedirectedRequest: NetworkLoadChecker::checkRedirection is done");
  622. if (m_parameters.options.redirect == FetchOptions::Redirect::Manual) {
  623. this->didFinishWithRedirectResponse(WTFMove(result->request), WTFMove(result->redirectRequest), WTFMove(result->redirectResponse));
  624. return;
  625. }
  626. if (this->isSynchronous()) {
  627. if (storedCredentialsPolicy != m_networkLoadChecker->storedCredentialsPolicy()) {
  628. // We need to restart the load to update the session according the new credential policy.
  629. RELEASE_LOG_IF_ALLOWED("willSendRedirectedRequest: Restarting network load due to credential policy change for synchronous load");
  630. this->restartNetworkLoad(WTFMove(result->redirectRequest));
  631. return;
  632. }
  633. // We do not support prompting for credentials for synchronous loads. If we ever change this policy then
  634. // we need to take care to prompt if and only if request and redirectRequest are not mixed content.
  635. this->continueWillSendRequest(WTFMove(result->redirectRequest), false);
  636. return;
  637. }
  638. m_shouldRestartLoad = storedCredentialsPolicy != m_networkLoadChecker->storedCredentialsPolicy();
  639. this->continueWillSendRedirectedRequest(WTFMove(result->request), WTFMove(result->redirectRequest), WTFMove(result->redirectResponse), WTFMove(adClickConversion));
  640. });
  641. return;
  642. }
  643. continueWillSendRedirectedRequest(WTFMove(request), WTFMove(redirectRequest), WTFMove(redirectResponse), WTFMove(adClickConversion));
  644. }
  645. void NetworkResourceLoader::continueWillSendRedirectedRequest(ResourceRequest&& request, ResourceRequest&& redirectRequest, ResourceResponse&& redirectResponse, Optional<AdClickAttribution::Conversion>&& adClickConversion)
  646. {
  647. RELEASE_LOG_IF_ALLOWED("continueWillSendRedirectedRequest: (m_isKeptAlive=%d, hasAdClickConversion=%d)", m_isKeptAlive, !!adClickConversion);
  648. ASSERT(!isSynchronous());
  649. if (m_isKeptAlive) {
  650. continueWillSendRequest(WTFMove(redirectRequest), false);
  651. return;
  652. }
  653. NetworkSession* networkSession = nullptr;
  654. if (adClickConversion && (networkSession = m_connection->networkProcess().networkSession(sessionID())))
  655. networkSession->handleAdClickAttributionConversion(WTFMove(*adClickConversion), request.url(), redirectRequest);
  656. // We send the request body separately because the ResourceRequest body normally does not get encoded when sent over IPC, as an optimization.
  657. // However, we really need the body here because a redirect cross-site may cause a process-swap and the request to start again in a new WebContent process.
  658. send(Messages::WebResourceLoader::WillSendRequest(redirectRequest, IPC::FormDataReference { redirectRequest.httpBody() }, sanitizeResponseIfPossible(WTFMove(redirectResponse), ResourceResponse::SanitizationType::Redirection)));
  659. }
  660. void NetworkResourceLoader::didFinishWithRedirectResponse(WebCore::ResourceRequest&& request, WebCore::ResourceRequest&& redirectRequest, ResourceResponse&& redirectResponse)
  661. {
  662. RELEASE_LOG_IF_ALLOWED("didFinishWithRedirectResponse:");
  663. redirectResponse.setType(ResourceResponse::Type::Opaqueredirect);
  664. if (!isCrossOriginPrefetch())
  665. didReceiveResponse(WTFMove(redirectResponse), [] (auto) { });
  666. else if (auto* session = m_connection->networkProcess().networkSession(sessionID()))
  667. session->prefetchCache().storeRedirect(request.url(), WTFMove(redirectResponse), WTFMove(redirectRequest));
  668. WebCore::NetworkLoadMetrics networkLoadMetrics;
  669. networkLoadMetrics.markComplete();
  670. networkLoadMetrics.responseBodyBytesReceived = 0;
  671. networkLoadMetrics.responseBodyDecodedSize = 0;
  672. send(Messages::WebResourceLoader::DidFinishResourceLoad { networkLoadMetrics });
  673. cleanup(LoadResult::Success);
  674. }
  675. ResourceResponse NetworkResourceLoader::sanitizeResponseIfPossible(ResourceResponse&& response, ResourceResponse::SanitizationType type)
  676. {
  677. if (m_parameters.shouldRestrictHTTPResponseAccess)
  678. response.sanitizeHTTPHeaderFields(type);
  679. return WTFMove(response);
  680. }
  681. void NetworkResourceLoader::restartNetworkLoad(WebCore::ResourceRequest&& newRequest)
  682. {
  683. RELEASE_LOG_IF_ALLOWED("restartNetworkLoad: (hasNetworkLoad=%d)", !!m_networkLoad);
  684. if (m_networkLoad)
  685. m_networkLoad->cancel();
  686. startNetworkLoad(WTFMove(newRequest), FirstLoad::No);
  687. }
  688. void NetworkResourceLoader::continueWillSendRequest(ResourceRequest&& newRequest, bool isAllowedToAskUserForCredentials)
  689. {
  690. RELEASE_LOG_IF_ALLOWED("continueWillSendRequest: (isAllowedToAskUserForCredentials=%d)", isAllowedToAskUserForCredentials);
  691. #if ENABLE(SERVICE_WORKER)
  692. if (parameters().options.mode == FetchOptions::Mode::Navigate) {
  693. if (auto serviceWorkerFetchTask = m_connection->swConnection().createFetchTask(*this, newRequest)) {
  694. RELEASE_LOG_IF_ALLOWED("continueWillSendRequest: Created a ServiceWorkerFetchTask to handle the redirect (fetchIdentifier=%" PRIu64 ")", serviceWorkerFetchTask->fetchIdentifier().toUInt64());
  695. m_networkLoad = nullptr;
  696. m_serviceWorkerFetchTask = WTFMove(serviceWorkerFetchTask);
  697. return;
  698. }
  699. RELEASE_LOG_IF_ALLOWED("continueWillSendRequest: Navigation is not using service workers");
  700. m_shouldRestartLoad = !!m_serviceWorkerFetchTask;
  701. m_serviceWorkerFetchTask = nullptr;
  702. }
  703. if (m_serviceWorkerFetchTask) {
  704. RELEASE_LOG_IF_ALLOWED("continueWillSendRequest: Continuing fetch task with redirect (fetchIdentifier=%" PRIu64 ")", m_serviceWorkerFetchTask->fetchIdentifier().toUInt64());
  705. m_serviceWorkerFetchTask->continueFetchTaskWith(WTFMove(newRequest));
  706. return;
  707. }
  708. #endif
  709. if (m_shouldRestartLoad) {
  710. m_shouldRestartLoad = false;
  711. if (m_networkLoad)
  712. m_networkLoad->updateRequestAfterRedirection(newRequest);
  713. RELEASE_LOG_IF_ALLOWED("continueWillSendRequest: Restarting network load");
  714. restartNetworkLoad(WTFMove(newRequest));
  715. return;
  716. }
  717. if (m_networkLoadChecker) {
  718. // FIXME: We should be doing this check when receiving the redirection and not allow about protocol as per fetch spec.
  719. if (!newRequest.url().protocolIsInHTTPFamily() && !newRequest.url().protocolIsAbout() && m_redirectCount) {
  720. RELEASE_LOG_ERROR_IF_ALLOWED("continueWillSendRequest: Failing load because it redirected to a scheme that is not HTTP(S)");
  721. didFailLoading(ResourceError { String { }, 0, newRequest.url(), "Redirection to URL with a scheme that is not HTTP(S)"_s, ResourceError::Type::AccessControl });
  722. return;
  723. }
  724. }
  725. m_isAllowedToAskUserForCredentials = isAllowedToAskUserForCredentials;
  726. // If there is a match in the network cache, we need to reuse the original cache policy and partition.
  727. newRequest.setCachePolicy(originalRequest().cachePolicy());
  728. newRequest.setCachePartition(originalRequest().cachePartition());
  729. if (m_isWaitingContinueWillSendRequestForCachedRedirect) {
  730. m_isWaitingContinueWillSendRequestForCachedRedirect = false;
  731. LOG(NetworkCache, "(NetworkProcess) Retrieving cached redirect");
  732. RELEASE_LOG_IF_ALLOWED("continueWillSendRequest: m_isWaitingContinueWillSendRequestForCachedRedirect was set");
  733. if (canUseCachedRedirect(newRequest))
  734. retrieveCacheEntry(newRequest);
  735. else
  736. startNetworkLoad(WTFMove(newRequest), FirstLoad::Yes);
  737. return;
  738. }
  739. if (m_networkLoad) {
  740. RELEASE_LOG_IF_ALLOWED("continueWillSendRequest: Telling NetworkLoad to proceed with the redirect");
  741. if (m_parameters.pageHasResourceLoadClient && !newRequest.isNull())
  742. m_connection->networkProcess().parentProcessConnection()->send(Messages::NetworkProcessProxy::ResourceLoadDidPerformHTTPRedirection(m_parameters.webPageProxyID, resourceLoadInfo(), m_redirectResponse, newRequest), 0);
  743. m_networkLoad->continueWillSendRequest(WTFMove(newRequest));
  744. }
  745. }
  746. void NetworkResourceLoader::continueDidReceiveResponse()
  747. {
  748. RELEASE_LOG_IF_ALLOWED("continueDidReceiveResponse: (hasCacheEntryWaitingForContinueDidReceiveResponse=%d, hasResponseCompletionHandler=%d)", !!m_cacheEntryWaitingForContinueDidReceiveResponse, !!m_responseCompletionHandler);
  749. #if ENABLE(SERVICE_WORKER)
  750. if (m_serviceWorkerFetchTask) {
  751. RELEASE_LOG_IF_ALLOWED("continueDidReceiveResponse: continuing with ServiceWorkerFetchTask (fetchIdentifier=%" PRIu64 ")", m_serviceWorkerFetchTask->fetchIdentifier().toUInt64());
  752. m_serviceWorkerFetchTask->continueDidReceiveFetchResponse();
  753. return;
  754. }
  755. #endif
  756. if (m_cacheEntryWaitingForContinueDidReceiveResponse) {
  757. sendResultForCacheEntry(WTFMove(m_cacheEntryWaitingForContinueDidReceiveResponse));
  758. cleanup(LoadResult::Success);
  759. return;
  760. }
  761. if (m_responseCompletionHandler)
  762. m_responseCompletionHandler(PolicyAction::Use);
  763. }
  764. void NetworkResourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
  765. {
  766. if (!isSynchronous())
  767. send(Messages::WebResourceLoader::DidSendData(bytesSent, totalBytesToBeSent));
  768. }
  769. void NetworkResourceLoader::startBufferingTimerIfNeeded()
  770. {
  771. if (isSynchronous())
  772. return;
  773. if (m_bufferingTimer.isActive())
  774. return;
  775. m_bufferingTimer.startOneShot(m_parameters.maximumBufferingTime);
  776. }
  777. void NetworkResourceLoader::bufferingTimerFired()
  778. {
  779. ASSERT(m_bufferedData);
  780. ASSERT(m_networkLoad);
  781. if (m_bufferedData->isEmpty())
  782. return;
  783. send(Messages::WebResourceLoader::DidReceiveData({ *m_bufferedData }, m_bufferedDataEncodedDataLength));
  784. m_bufferedData = SharedBuffer::create();
  785. m_bufferedDataEncodedDataLength = 0;
  786. }
  787. void NetworkResourceLoader::sendBuffer(SharedBuffer& buffer, size_t encodedDataLength)
  788. {
  789. ASSERT(!isSynchronous());
  790. send(Messages::WebResourceLoader::DidReceiveData({ buffer }, encodedDataLength));
  791. }
  792. void NetworkResourceLoader::tryStoreAsCacheEntry()
  793. {
  794. if (!canUseCache(m_networkLoad->currentRequest())) {
  795. RELEASE_LOG_IF_ALLOWED("tryStoreAsCacheEntry: Not storing cache entry because request is not eligible");
  796. return;
  797. }
  798. if (!m_bufferedDataForCache) {
  799. RELEASE_LOG_IF_ALLOWED("tryStoreAsCacheEntry: Not storing cache entry because m_bufferedDataForCache is null");
  800. return;
  801. }
  802. if (isCrossOriginPrefetch()) {
  803. if (auto* session = m_connection->networkProcess().networkSession(sessionID())) {
  804. RELEASE_LOG_IF_ALLOWED("tryStoreAsCacheEntry: Storing entry in prefetch cache");
  805. session->prefetchCache().store(m_networkLoad->currentRequest().url(), WTFMove(m_response), WTFMove(m_bufferedDataForCache));
  806. }
  807. return;
  808. }
  809. RELEASE_LOG_IF_ALLOWED("tryStoreAsCacheEntry: Storing entry in HTTP disk cache");
  810. m_cache->store(m_networkLoad->currentRequest(), m_response, WTFMove(m_bufferedDataForCache), [loader = makeRef(*this)](auto& mappedBody) mutable {
  811. #if ENABLE(SHAREABLE_RESOURCE)
  812. if (mappedBody.shareableResourceHandle.isNull())
  813. return;
  814. LOG(NetworkCache, "(NetworkProcess) sending DidCacheResource");
  815. loader->send(Messages::NetworkProcessConnection::DidCacheResource(loader->originalRequest(), mappedBody.shareableResourceHandle));
  816. #endif
  817. });
  818. }
  819. void NetworkResourceLoader::didReceiveMainResourceResponse(const WebCore::ResourceResponse& response)
  820. {
  821. RELEASE_LOG_IF_ALLOWED("didReceiveMainResourceResponse:");
  822. #if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
  823. if (auto* speculativeLoadManager = m_cache ? m_cache->speculativeLoadManager() : nullptr)
  824. speculativeLoadManager->registerMainResourceLoadResponse(globalFrameID(), originalRequest(), response);
  825. #endif
  826. }
  827. void NetworkResourceLoader::didRetrieveCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
  828. {
  829. RELEASE_LOG_IF_ALLOWED("didRetrieveCacheEntry:");
  830. auto response = entry->response();
  831. if (isMainResource())
  832. didReceiveMainResourceResponse(response);
  833. if (isMainResource() && shouldInterruptLoadForCSPFrameAncestorsOrXFrameOptions(response)) {
  834. RELEASE_LOG_ERROR_IF_ALLOWED("didRetrieveCacheEntry: Stopping load due to CSP Frame-Ancestors or X-Frame-Options");
  835. response = sanitizeResponseIfPossible(WTFMove(response), ResourceResponse::SanitizationType::CrossOriginSafe);
  836. send(Messages::WebResourceLoader::StopLoadingAfterXFrameOptionsOrContentSecurityPolicyDenied { response });
  837. return;
  838. }
  839. if (m_networkLoadChecker) {
  840. auto error = m_networkLoadChecker->validateResponse(originalRequest(), response);
  841. if (!error.isNull()) {
  842. RELEASE_LOG_ERROR_IF_ALLOWED("didRetrieveCacheEntry: Failing load due to NetworkLoadChecker::validateResponse");
  843. didFailLoading(error);
  844. return;
  845. }
  846. }
  847. response = sanitizeResponseIfPossible(WTFMove(response), ResourceResponse::SanitizationType::CrossOriginSafe);
  848. if (isSynchronous()) {
  849. m_synchronousLoadData->response = WTFMove(response);
  850. sendReplyToSynchronousRequest(*m_synchronousLoadData, entry->buffer());
  851. cleanup(LoadResult::Success);
  852. return;
  853. }
  854. bool needsContinueDidReceiveResponseMessage = isMainResource();
  855. RELEASE_LOG_IF_ALLOWED("didRetrieveCacheEntry: Sending WebResourceLoader::DidReceiveResponse IPC (needsContinueDidReceiveResponseMessage=%d)", needsContinueDidReceiveResponseMessage);
  856. send(Messages::WebResourceLoader::DidReceiveResponse { response, needsContinueDidReceiveResponseMessage });
  857. if (needsContinueDidReceiveResponseMessage)
  858. m_cacheEntryWaitingForContinueDidReceiveResponse = WTFMove(entry);
  859. else {
  860. sendResultForCacheEntry(WTFMove(entry));
  861. cleanup(LoadResult::Success);
  862. }
  863. }
  864. void NetworkResourceLoader::sendResultForCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
  865. {
  866. RELEASE_LOG_IF_ALLOWED("sendResultForCacheEntry:");
  867. #if ENABLE(SHAREABLE_RESOURCE)
  868. if (!entry->shareableResourceHandle().isNull()) {
  869. send(Messages::WebResourceLoader::DidReceiveResource(entry->shareableResourceHandle()));
  870. return;
  871. }
  872. #endif
  873. #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED
  874. if (shouldLogCookieInformation(m_connection, sessionID()))
  875. logCookieInformation();
  876. #endif
  877. WebCore::NetworkLoadMetrics networkLoadMetrics;
  878. networkLoadMetrics.markComplete();
  879. networkLoadMetrics.requestHeaderBytesSent = 0;
  880. networkLoadMetrics.requestBodyBytesSent = 0;
  881. networkLoadMetrics.responseHeaderBytesReceived = 0;
  882. networkLoadMetrics.responseBodyBytesReceived = 0;
  883. networkLoadMetrics.responseBodyDecodedSize = 0;
  884. sendBuffer(*entry->buffer(), entry->buffer()->size());
  885. send(Messages::WebResourceLoader::DidFinishResourceLoad(networkLoadMetrics));
  886. }
  887. void NetworkResourceLoader::validateCacheEntry(std::unique_ptr<NetworkCache::Entry> entry)
  888. {
  889. RELEASE_LOG_IF_ALLOWED("validateCacheEntry:");
  890. ASSERT(!m_networkLoad);
  891. // If the request is already conditional then the revalidation was not triggered by the disk cache
  892. // and we should not overwrite the existing conditional headers.
  893. ResourceRequest revalidationRequest = originalRequest();
  894. m_cacheEntryForValidation = WTFMove(entry);
  895. startNetworkLoad(WTFMove(revalidationRequest), FirstLoad::Yes);
  896. }
  897. void NetworkResourceLoader::dispatchWillSendRequestForCacheEntry(ResourceRequest&& request, std::unique_ptr<NetworkCache::Entry>&& entry)
  898. {
  899. RELEASE_LOG_IF_ALLOWED("dispatchWillSendRequestForCacheEntry:");
  900. ASSERT(entry->redirectRequest());
  901. ASSERT(!m_isWaitingContinueWillSendRequestForCachedRedirect);
  902. LOG(NetworkCache, "(NetworkProcess) Executing cached redirect");
  903. m_isWaitingContinueWillSendRequestForCachedRedirect = true;
  904. willSendRedirectedRequest(WTFMove(request), ResourceRequest { *entry->redirectRequest() }, ResourceResponse { entry->response() });
  905. }
  906. IPC::Connection* NetworkResourceLoader::messageSenderConnection() const
  907. {
  908. return &connectionToWebProcess().connection();
  909. }
  910. void NetworkResourceLoader::consumeSandboxExtensionsIfNeeded()
  911. {
  912. if (!m_didConsumeSandboxExtensions)
  913. consumeSandboxExtensions();
  914. }
  915. void NetworkResourceLoader::consumeSandboxExtensions()
  916. {
  917. ASSERT(!m_didConsumeSandboxExtensions);
  918. for (auto& extension : m_parameters.requestBodySandboxExtensions)
  919. extension->consume();
  920. if (auto& extension = m_parameters.resourceSandboxExtension)
  921. extension->consume();
  922. for (auto& fileReference : m_fileReferences)
  923. fileReference->prepareForFileAccess();
  924. m_didConsumeSandboxExtensions = true;
  925. }
  926. void NetworkResourceLoader::invalidateSandboxExtensions()
  927. {
  928. if (m_didConsumeSandboxExtensions) {
  929. for (auto& extension : m_parameters.requestBodySandboxExtensions)
  930. extension->revoke();
  931. if (auto& extension = m_parameters.resourceSandboxExtension)
  932. extension->revoke();
  933. for (auto& fileReference : m_fileReferences)
  934. fileReference->revokeFileAccess();
  935. m_didConsumeSandboxExtensions = false;
  936. }
  937. m_fileReferences.clear();
  938. }
  939. bool NetworkResourceLoader::isAlwaysOnLoggingAllowed() const
  940. {
  941. if (m_connection->networkProcess().sessionIsControlledByAutomation(sessionID()))
  942. return true;
  943. return sessionID().isAlwaysOnLoggingAllowed();
  944. }
  945. bool NetworkResourceLoader::shouldCaptureExtraNetworkLoadMetrics() const
  946. {
  947. return m_shouldCaptureExtraNetworkLoadMetrics;
  948. }
  949. #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED
  950. bool NetworkResourceLoader::shouldLogCookieInformation(NetworkConnectionToWebProcess& connection, const PAL::SessionID& sessionID)
  951. {
  952. if (auto* session = connection.networkProcess().networkSession(sessionID))
  953. return session->shouldLogCookieInformation();
  954. return false;
  955. }
  956. static String escapeForJSON(String s)
  957. {
  958. return s.replace('\\', "\\\\").replace('"', "\\\"");
  959. }
  960. static String escapeIDForJSON(const Optional<uint64_t>& value)
  961. {
  962. return value ? String::number(value.value()) : String("None"_s);
  963. }
  964. static String escapeIDForJSON(const Optional<FrameIdentifier>& value)
  965. {
  966. return value ? String::number(value->toUInt64()) : String("None"_s);
  967. }
  968. static String escapeIDForJSON(const Optional<PageIdentifier>& value)
  969. {
  970. return value ? String::number(value->toUInt64()) : String("None"_s);
  971. }
  972. void NetworkResourceLoader::logCookieInformation() const
  973. {
  974. ASSERT(shouldLogCookieInformation(m_connection, sessionID()));
  975. auto* networkStorageSession = m_connection->networkProcess().storageSession(sessionID());
  976. ASSERT(networkStorageSession);
  977. logCookieInformation(m_connection, "NetworkResourceLoader", reinterpret_cast<const void*>(this), *networkStorageSession, originalRequest().firstPartyForCookies(), SameSiteInfo::create(originalRequest()), originalRequest().url(), originalRequest().httpReferrer(), frameID(), pageID(), identifier());
  978. }
  979. static void logBlockedCookieInformation(NetworkConnectionToWebProcess& connection, const String& label, const void* loggedObject, const WebCore::NetworkStorageSession& networkStorageSession, const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, const String& referrer, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, Optional<uint64_t> identifier)
  980. {
  981. ASSERT(NetworkResourceLoader::shouldLogCookieInformation(connection, networkStorageSession.sessionID()));
  982. auto escapedURL = escapeForJSON(url.string());
  983. auto escapedFirstParty = escapeForJSON(firstParty.string());
  984. auto escapedFrameID = escapeIDForJSON(frameID);
  985. auto escapedPageID = escapeIDForJSON(pageID);
  986. auto escapedIdentifier = escapeIDForJSON(identifier);
  987. auto escapedReferrer = escapeForJSON(referrer);
  988. #define LOCAL_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(networkStorageSession.sessionID().isAlwaysOnLoggingAllowed(), Network, "%p - %s::" fmt, loggedObject, label.utf8().data(), ##__VA_ARGS__)
  989. #define LOCAL_LOG(str, ...) \
  990. LOCAL_LOG_IF_ALLOWED("logCookieInformation: BLOCKED cookie access for webPageID=%s, frameID=%s, resourceID=%s, firstParty=%s: " str, escapedPageID.utf8().data(), escapedFrameID.utf8().data(), escapedIdentifier.utf8().data(), escapedFirstParty.utf8().data(), ##__VA_ARGS__)
  991. LOCAL_LOG(R"({ "url": "%{public}s",)", escapedURL.utf8().data());
  992. LOCAL_LOG(R"( "partition": "%{public}s",)", "BLOCKED");
  993. LOCAL_LOG(R"( "hasStorageAccess": %{public}s,)", "false");
  994. LOCAL_LOG(R"( "referer": "%{public}s",)", escapedReferrer.utf8().data());
  995. LOCAL_LOG(R"( "isSameSite": "%{public}s",)", sameSiteInfo.isSameSite ? "true" : "false");
  996. LOCAL_LOG(R"( "isTopSite": "%{public}s",)", sameSiteInfo.isTopSite ? "true" : "false");
  997. LOCAL_LOG(R"( "cookies": [])");
  998. LOCAL_LOG(R"( })");
  999. #undef LOCAL_LOG
  1000. #undef LOCAL_LOG_IF_ALLOWED
  1001. }
  1002. static void logCookieInformationInternal(NetworkConnectionToWebProcess& connection, const String& label, const void* loggedObject, const WebCore::NetworkStorageSession& networkStorageSession, const URL& firstParty, const WebCore::SameSiteInfo& sameSiteInfo, const URL& url, const String& referrer, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, Optional<uint64_t> identifier)
  1003. {
  1004. ASSERT(NetworkResourceLoader::shouldLogCookieInformation(connection, networkStorageSession.sessionID()));
  1005. Vector<WebCore::Cookie> cookies;
  1006. if (!networkStorageSession.getRawCookies(firstParty, sameSiteInfo, url, frameID, pageID, ShouldAskITP::Yes, cookies))
  1007. return;
  1008. auto escapedURL = escapeForJSON(url.string());
  1009. auto escapedPartition = escapeForJSON(emptyString());
  1010. auto escapedReferrer = escapeForJSON(referrer);
  1011. auto escapedFrameID = escapeIDForJSON(frameID);
  1012. auto escapedPageID = escapeIDForJSON(pageID);
  1013. auto escapedIdentifier = escapeIDForJSON(identifier);
  1014. bool hasStorageAccess = (frameID && pageID) ? networkStorageSession.hasStorageAccess(WebCore::RegistrableDomain { url }, WebCore::RegistrableDomain { firstParty }, frameID.value(), pageID.value()) : false;
  1015. #define LOCAL_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(networkStorageSession.sessionID().isAlwaysOnLoggingAllowed(), Network, "%p - %s::" fmt, loggedObject, label.utf8().data(), ##__VA_ARGS__)
  1016. #define LOCAL_LOG(str, ...) \
  1017. LOCAL_LOG_IF_ALLOWED("logCookieInformation: webPageID=%s, frameID=%s, resourceID=%s: " str, escapedPageID.utf8().data(), escapedFrameID.utf8().data(), escapedIdentifier.utf8().data(), ##__VA_ARGS__)
  1018. LOCAL_LOG(R"({ "url": "%{public}s",)", escapedURL.utf8().data());
  1019. LOCAL_LOG(R"( "partition": "%{public}s",)", escapedPartition.utf8().data());
  1020. LOCAL_LOG(R"( "hasStorageAccess": %{public}s,)", hasStorageAccess ? "true" : "false");
  1021. LOCAL_LOG(R"( "referer": "%{public}s",)", escapedReferrer.utf8().data());
  1022. LOCAL_LOG(R"( "isSameSite": "%{public}s",)", sameSiteInfo.isSameSite ? "true" : "false");
  1023. LOCAL_LOG(R"( "isTopSite": "%{public}s",)", sameSiteInfo.isTopSite ? "true" : "false");
  1024. LOCAL_LOG(R"( "cookies": [)");
  1025. auto size = cookies.size();
  1026. decltype(size) count = 0;
  1027. for (const auto& cookie : cookies) {
  1028. const char* trailingComma = ",";
  1029. if (++count == size)
  1030. trailingComma = "";
  1031. auto escapedName = escapeForJSON(cookie.name);
  1032. auto escapedValue = escapeForJSON(cookie.value);
  1033. auto escapedDomain = escapeForJSON(cookie.domain);
  1034. auto escapedPath = escapeForJSON(cookie.path);
  1035. auto escapedComment = escapeForJSON(cookie.comment);
  1036. auto escapedCommentURL = escapeForJSON(cookie.commentURL.string());
  1037. // FIXME: Log Same-Site policy for each cookie. See <https://bugs.webkit.org/show_bug.cgi?id=184894>.
  1038. LOCAL_LOG(R"( { "name": "%{public}s",)", escapedName.utf8().data());
  1039. LOCAL_LOG(R"( "value": "%{public}s",)", escapedValue.utf8().data());
  1040. LOCAL_LOG(R"( "domain": "%{public}s",)", escapedDomain.utf8().data());
  1041. LOCAL_LOG(R"( "path": "%{public}s",)", escapedPath.utf8().data());
  1042. LOCAL_LOG(R"( "created": %f,)", cookie.created);
  1043. LOCAL_LOG(R"( "expires": %f,)", cookie.expires);
  1044. LOCAL_LOG(R"( "httpOnly": %{public}s,)", cookie.httpOnly ? "true" : "false");
  1045. LOCAL_LOG(R"( "secure": %{public}s,)", cookie.secure ? "true" : "false");
  1046. LOCAL_LOG(R"( "session": %{public}s,)", cookie.session ? "true" : "false");
  1047. LOCAL_LOG(R"( "comment": "%{public}s",)", escapedComment.utf8().data());
  1048. LOCAL_LOG(R"( "commentURL": "%{public}s")", escapedCommentURL.utf8().data());
  1049. LOCAL_LOG(R"( }%{public}s)", trailingComma);
  1050. }
  1051. LOCAL_LOG(R"(]})");
  1052. #undef LOCAL_LOG
  1053. #undef LOCAL_LOG_IF_ALLOWED
  1054. }
  1055. void NetworkResourceLoader::logCookieInformation(NetworkConnectionToWebProcess& connection, const String& label, const void* loggedObject, const NetworkStorageSession& networkStorageSession, const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, const String& referrer, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, Optional<uint64_t> identifier)
  1056. {
  1057. ASSERT(shouldLogCookieInformation(connection, networkStorageSession.sessionID()));
  1058. if (networkStorageSession.shouldBlockCookies(firstParty, url, frameID, pageID))
  1059. logBlockedCookieInformation(connection, label, loggedObject, networkStorageSession, firstParty, sameSiteInfo, url, referrer, frameID, pageID, identifier);
  1060. else
  1061. logCookieInformationInternal(connection, label, loggedObject, networkStorageSession, firstParty, sameSiteInfo, url, referrer, frameID, pageID, identifier);
  1062. }
  1063. #endif
  1064. void NetworkResourceLoader::addConsoleMessage(MessageSource messageSource, MessageLevel messageLevel, const String& message, unsigned long)
  1065. {
  1066. send(Messages::WebPage::AddConsoleMessage { m_parameters.webFrameID, messageSource, messageLevel, message, identifier() }, m_parameters.webPageID);
  1067. }
  1068. void NetworkResourceLoader::sendCSPViolationReport(URL&& reportURL, Ref<FormData>&& report)
  1069. {
  1070. send(Messages::WebPage::SendCSPViolationReport { m_parameters.webFrameID, WTFMove(reportURL), IPC::FormDataReference { WTFMove(report) } }, m_parameters.webPageID);
  1071. }
  1072. void NetworkResourceLoader::enqueueSecurityPolicyViolationEvent(WebCore::SecurityPolicyViolationEvent::Init&& eventInit)
  1073. {
  1074. send(Messages::WebPage::EnqueueSecurityPolicyViolationEvent { m_parameters.webFrameID, WTFMove(eventInit) }, m_parameters.webPageID);
  1075. }
  1076. void NetworkResourceLoader::logSlowCacheRetrieveIfNeeded(const NetworkCache::Cache::RetrieveInfo& info)
  1077. {
  1078. #if RELEASE_LOG_DISABLED
  1079. UNUSED_PARAM(info);
  1080. #else
  1081. if (!isAlwaysOnLoggingAllowed())
  1082. return;
  1083. auto duration = info.completionTime - info.startTime;
  1084. if (duration < 1_s)
  1085. return;
  1086. RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Took %.0fms, priority %d", duration.milliseconds(), info.priority);
  1087. if (info.wasSpeculativeLoad)
  1088. RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Was speculative load");
  1089. if (!info.storageTimings.startTime)
  1090. return;
  1091. RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Storage retrieve time %.0fms", (info.storageTimings.completionTime - info.storageTimings.startTime).milliseconds());
  1092. if (info.storageTimings.dispatchTime) {
  1093. auto time = (info.storageTimings.dispatchTime - info.storageTimings.startTime).milliseconds();
  1094. auto count = info.storageTimings.dispatchCountAtDispatch - info.storageTimings.dispatchCountAtStart;
  1095. RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Dispatch delay %.0fms, dispatched %lu resources first", time, count);
  1096. }
  1097. if (info.storageTimings.recordIOStartTime)
  1098. RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Record I/O time %.0fms", (info.storageTimings.recordIOEndTime - info.storageTimings.recordIOStartTime).milliseconds());
  1099. if (info.storageTimings.blobIOStartTime)
  1100. RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Blob I/O time %.0fms", (info.storageTimings.blobIOEndTime - info.storageTimings.blobIOStartTime).milliseconds());
  1101. if (info.storageTimings.synchronizationInProgressAtDispatch)
  1102. RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Synchronization was in progress");
  1103. if (info.storageTimings.shrinkInProgressAtDispatch)
  1104. RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Shrink was in progress");
  1105. if (info.storageTimings.wasCanceled)
  1106. RELEASE_LOG_IF_ALLOWED("logSlowCacheRetrieveIfNeeded: Retrieve was canceled");
  1107. #endif
  1108. }
  1109. bool NetworkResourceLoader::isCrossOriginPrefetch() const
  1110. {
  1111. auto& request = originalRequest();
  1112. return request.httpHeaderField(HTTPHeaderName::Purpose) == "prefetch" && !m_parameters.sourceOrigin->canRequest(request.url());
  1113. }
  1114. #if ENABLE(SERVICE_WORKER)
  1115. void NetworkResourceLoader::startWithServiceWorker()
  1116. {
  1117. RELEASE_LOG_IF_ALLOWED("startWithServiceWorker:");
  1118. ASSERT(!m_serviceWorkerFetchTask);
  1119. m_serviceWorkerFetchTask = m_connection->swConnection().createFetchTask(*this, originalRequest());
  1120. if (m_serviceWorkerFetchTask) {
  1121. RELEASE_LOG_IF_ALLOWED("startWithServiceWorker: Created a ServiceWorkerFetchTask (fetchIdentifier=%" PRIu64 ")", m_serviceWorkerFetchTask->fetchIdentifier().toUInt64());
  1122. return;
  1123. }
  1124. serviceWorkerDidNotHandle(nullptr);
  1125. }
  1126. void NetworkResourceLoader::serviceWorkerDidNotHandle(ServiceWorkerFetchTask* fetchTask)
  1127. {
  1128. RELEASE_LOG_IF_ALLOWED("serviceWorkerDidNotHandle: (fetchIdentifier=%" PRIu64 ")", fetchTask ? fetchTask->fetchIdentifier().toUInt64() : 0);
  1129. RELEASE_ASSERT(m_serviceWorkerFetchTask.get() == fetchTask);
  1130. if (m_parameters.serviceWorkersMode == ServiceWorkersMode::Only) {
  1131. RELEASE_LOG_ERROR_IF_ALLOWED("serviceWorkerDidNotHandle: Aborting load because the service worker did not handle the load and serviceWorkerMode only allows service workers");
  1132. send(Messages::WebResourceLoader::ServiceWorkerDidNotHandle { }, identifier());
  1133. abort();
  1134. return;
  1135. }
  1136. if (m_serviceWorkerFetchTask) {
  1137. auto newRequest = m_serviceWorkerFetchTask->takeRequest();
  1138. m_serviceWorkerFetchTask = nullptr;
  1139. if (m_networkLoad)
  1140. m_networkLoad->updateRequestAfterRedirection(newRequest);
  1141. RELEASE_LOG_IF_ALLOWED("serviceWorkerDidNotHandle: Restarting network load for redirect");
  1142. restartNetworkLoad(WTFMove(newRequest));
  1143. return;
  1144. }
  1145. start();
  1146. }
  1147. #endif
  1148. } // namespace WebKit
  1149. #undef RELEASE_LOG_IF_ALLOWED
  1150. #undef RELEASE_LOG_ERROR_IF_ALLOWED