DocumentLoader::~DocumentLoader() { ASSERT(!m_frame || frameLoader()->activeDocumentLoader() != this || !frameLoader()->isLoading()); }
void MainResourceLoader::continueAfterContentPolicy(PolicyAction contentPolicy, const ResourceResponse& r) { KURL url = request().url(); const String& mimeType = r.mimeType(); switch (contentPolicy) { case PolicyUse: { // Prevent remote web archives from loading because they can claim to be from any domain and thus avoid cross-domain security checks (4120255). bool isRemoteWebArchive = (equalIgnoringCase("application/x-webarchive", mimeType) || equalIgnoringCase("multipart/related", mimeType)) && !m_substituteData.isValid() && !url.isLocalFile(); if (!frameLoader()->client()->canShowMIMEType(mimeType) || isRemoteWebArchive) { frameLoader()->policyChecker()->cannotShowMIMEType(r); // Check reachedTerminalState since the load may have already been cancelled inside of _handleUnimplementablePolicyWithErrorCode::. if (!reachedTerminalState()) stopLoadingForPolicyChange(); return; } break; } case PolicyDownload: // m_handle can be null, e.g. when loading a substitute resource from application cache. if (!m_handle) { receivedError(cannotShowURLError()); return; } frameLoader()->client()->download(m_handle.get(), request(), m_handle.get()->firstRequest(), r); // It might have gone missing if (frameLoader()) receivedError(interruptedForPolicyChangeError()); return; case PolicyIgnore: stopLoadingForPolicyChange(); return; default: ASSERT_NOT_REACHED(); } RefPtr<MainResourceLoader> protect(this); if (r.isHTTP()) { int status = r.httpStatusCode(); if (status < 200 || status >= 300) { bool hostedByObject = frameLoader()->isHostedByObjectElement(); frameLoader()->handleFallbackContent(); // object elements are no longer rendered after we fallback, so don't // keep trying to process data from their load if (hostedByObject) cancel(); } } // we may have cancelled this load as part of switching to fallback content if (!reachedTerminalState()) ResourceLoader::didReceiveResponse(r); if (frameLoader() && !frameLoader()->isStopping()) { if (m_substituteData.isValid()) { if (m_substituteData.content()->size()) didReceiveData(m_substituteData.content()->data(), m_substituteData.content()->size(), m_substituteData.content()->size(), true); if (frameLoader() && !frameLoader()->isStopping()) didFinishLoading(0); } else if (shouldLoadAsEmptyDocument(url) || frameLoader()->client()->representationExistsForURLScheme(url.protocol())) didFinishLoading(0); } }
ResourceError MainResourceLoader::interruptedForPolicyChangeError() const { return frameLoader()->client()->interruptedForPolicyChangeError(request()); }
void MainResourceLoader::continueAfterContentPolicy(PolicyAction contentPolicy, const ResourceResponse& r) { KURL url = request().url(); const String& mimeType = r.mimeType(); switch (contentPolicy) { case PolicyUse: { // Prevent remote web archives from loading because they can claim to be from any domain and thus avoid cross-domain security checks (4120255). bool isRemoteWebArchive = (equalIgnoringCase("application/x-webarchive", mimeType) #if PLATFORM(GTK) || equalIgnoringCase("message/rfc822", mimeType) #endif || equalIgnoringCase("multipart/related", mimeType)) && !m_substituteData.isValid() && !SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol()); if (!frameLoader()->client()->canShowMIMEType(mimeType) || isRemoteWebArchive) { frameLoader()->policyChecker()->cannotShowMIMEType(r); // Check reachedTerminalState since the load may have already been canceled inside of _handleUnimplementablePolicyWithErrorCode::. stopLoadingForPolicyChange(); return; } break; } case PolicyDownload: { // m_resource can be null, e.g. when loading a substitute resource from application cache. if (!m_resource) { receivedError(frameLoader()->client()->cannotShowURLError(request())); return; } InspectorInstrumentation::continueWithPolicyDownload(m_documentLoader->frame(), documentLoader(), identifier(), r); // When starting the request, we didn't know that it would result in download and not navigation. Now we know that main document URL didn't change. // Download may use this knowledge for purposes unrelated to cookies, notably for setting file quarantine data. ResourceRequest request = this->request(); frameLoader()->setOriginalURLForDownloadRequest(request); frameLoader()->client()->convertMainResourceLoadToDownload(this, request, r); // It might have gone missing if (loader()) loader()->didFail(interruptedForPolicyChangeError()); return; } case PolicyIgnore: InspectorInstrumentation::continueWithPolicyIgnore(m_documentLoader->frame(), documentLoader(), identifier(), r); stopLoadingForPolicyChange(); return; default: ASSERT_NOT_REACHED(); } RefPtr<MainResourceLoader> protect(this); if (r.isHTTP()) { int status = r.httpStatusCode(); if (status < 200 || status >= 300) { bool hostedByObject = frameLoader()->isHostedByObjectElement(); frameLoader()->handleFallbackContent(); // object elements are no longer rendered after we fallback, so don't // keep trying to process data from their load if (hostedByObject) cancel(); } } if (!m_documentLoader->isStopping() && m_substituteData.isValid()) { if (m_substituteData.content()->size()) dataReceived(0, m_substituteData.content()->data(), m_substituteData.content()->size()); if (!m_documentLoader->isStopping()) didFinishLoading(0); } }
void MainResourceLoader::addData(const char* data, int length, bool allAtOnce) { ResourceLoader::addData(data, length, allAtOnce); frameLoader()->receivedData(data, length); }
ResourceError ResourceLoader::cancelledError() { return frameLoader()->cancelledError(m_request); }
ResourceError ResourceLoader::cannotShowURLError() { return frameLoader()->client()->cannotShowURLError(m_request); }
bool ResourceLoader::isAlwaysOnLoggingAllowed() const { return frameLoader() && frameLoader()->isAlwaysOnLoggingAllowed(); }
void ResourceLoader::willSendRequestInternal(ResourceRequest& request, const ResourceResponse& redirectResponse) { // Protect this in this delegate method since the additional processing can do // anything including possibly derefing this; one example of this is Radar 3266216. Ref<ResourceLoader> protect(*this); ASSERT(!m_reachedTerminalState); #if ENABLE(CONTENT_EXTENSIONS) ASSERT(m_resourceType != ResourceType::Invalid); #endif // We need a resource identifier for all requests, even if FrameLoader is never going to see it (such as with CORS preflight requests). bool createdResourceIdentifier = false; if (!m_identifier) { m_identifier = m_frame->page()->progress().createUniqueIdentifier(); createdResourceIdentifier = true; } #if ENABLE(CONTENT_EXTENSIONS) if (frameLoader()) { Page* page = frameLoader()->frame().page(); if (page && m_documentLoader) { auto* userContentController = page->userContentController(); if (userContentController) userContentController->processContentExtensionRulesForLoad(*page, request, m_resourceType, *m_documentLoader); } } #endif if (request.isNull()) { didFail(cannotShowURLError()); return; } if (m_options.sendLoadCallbacks() == SendCallbacks) { if (createdResourceIdentifier) frameLoader()->notifier().assignIdentifierToInitialRequest(m_identifier, documentLoader(), request); #if PLATFORM(IOS) // If this ResourceLoader was stopped as a result of assignIdentifierToInitialRequest, bail out if (m_reachedTerminalState) return; #endif frameLoader()->notifier().willSendRequest(this, request, redirectResponse); } else InspectorInstrumentation::willSendRequest(m_frame.get(), m_identifier, m_frame->loader().documentLoader(), request, redirectResponse); bool isRedirect = !redirectResponse.isNull(); if (isRedirect) platformStrategies()->loaderStrategy()->resourceLoadScheduler()->crossOriginRedirectReceived(this, request.url()); m_request = request; if (isRedirect) { auto& redirectURL = request.url(); if (!m_documentLoader->isCommitted()) frameLoader()->client().dispatchDidReceiveServerRedirectForProvisionalLoad(); if (redirectURL.protocolIsData()) { // Handle data URL decoding locally. finishNetworkLoad(); loadDataURL(); } } }
void DocumentLoader::responseReceived( Resource* resource, const ResourceResponse& response, std::unique_ptr<WebDataConsumerHandle> handle) { DCHECK_EQ(m_mainResource, resource); DCHECK(!handle); DCHECK(frame()); m_applicationCacheHost->didReceiveResponseForMainResource(response); // The memory cache doesn't understand the application cache or its caching // rules. So if a main resource is served from the application cache, ensure // we don't save the result for future use. All responses loaded from appcache // will have a non-zero appCacheID(). if (response.appCacheID()) memoryCache()->remove(m_mainResource.get()); m_contentSecurityPolicy = ContentSecurityPolicy::create(); m_contentSecurityPolicy->setOverrideURLForSelf(response.url()); m_contentSecurityPolicy->didReceiveHeaders( ContentSecurityPolicyResponseHeaders(response)); if (!m_contentSecurityPolicy->allowAncestors(m_frame, response.url())) { cancelLoadAfterXFrameOptionsOrCSPDenied(response); return; } // 'frame-ancestors' obviates 'x-frame-options': // https://w3c.github.io/webappsec/specs/content-security-policy/#frame-ancestors-and-frame-options if (!m_contentSecurityPolicy->isFrameAncestorsEnforced()) { HTTPHeaderMap::const_iterator it = response.httpHeaderFields().find(HTTPNames::X_Frame_Options); if (it != response.httpHeaderFields().end()) { String content = it->value; if (frameLoader()->shouldInterruptLoadForXFrameOptions( content, response.url(), mainResourceIdentifier())) { String message = "Refused to display '" + response.url().elidedString() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'."; ConsoleMessage* consoleMessage = ConsoleMessage::createForRequest( SecurityMessageSource, ErrorMessageLevel, message, response.url(), mainResourceIdentifier()); frame()->document()->addConsoleMessage(consoleMessage); cancelLoadAfterXFrameOptionsOrCSPDenied(response); return; } } } if (RuntimeEnabledFeatures::embedderCSPEnforcementEnabled() && !frameLoader()->requiredCSP().isEmpty()) { SecurityOrigin* parentSecurityOrigin = frame()->tree().parent()->securityContext()->getSecurityOrigin(); if (ContentSecurityPolicy::shouldEnforceEmbeddersPolicy( response, parentSecurityOrigin)) { m_contentSecurityPolicy->addPolicyFromHeaderValue( frameLoader()->requiredCSP(), ContentSecurityPolicyHeaderTypeEnforce, ContentSecurityPolicyHeaderSourceHTTP); } else { String message = "Refused to display '" + response.url().elidedString() + "' because it has not opted-into the following policy " "required by its embedder: '" + frameLoader()->requiredCSP() + "'."; ConsoleMessage* consoleMessage = ConsoleMessage::createForRequest( SecurityMessageSource, ErrorMessageLevel, message, response.url(), mainResourceIdentifier()); frame()->document()->addConsoleMessage(consoleMessage); cancelLoadAfterXFrameOptionsOrCSPDenied(response); return; } } DCHECK(!m_frame->page()->defersLoading()); m_response = response; if (isArchiveMIMEType(m_response.mimeType()) && m_mainResource->getDataBufferingPolicy() != BufferData) m_mainResource->setDataBufferingPolicy(BufferData); if (!shouldContinueForResponse()) { InspectorInstrumentation::continueWithPolicyIgnore( m_frame, this, m_mainResource->identifier(), m_response, m_mainResource.get()); m_fetcher->stopFetching(); return; } if (m_response.isHTTP()) { int status = m_response.httpStatusCode(); if ((status < 200 || status >= 300) && m_frame->owner()) m_frame->owner()->renderFallbackContent(); } }
ResourceError ResourceLoader::blockedByContentBlockerError() { return frameLoader()->client().blockedByContentBlockerError(m_request); }
void DocumentLoader::commitIfReady() { if (m_state < Committed) { m_state = Committed; frameLoader()->commitProvisionalLoad(); } }
void DocumentLoader::didChangePerformanceTiming() { if (frame() && frame()->isMainFrame() && m_state >= Committed) { frameLoader()->client()->didChangePerformanceTiming(); } }
void DocumentLoader::updateLoading() { ASSERT(this == frameLoader()->activeDocumentLoader()); setLoading(frameLoader()->isLoading()); }
bool DocumentLoader::doesProgressiveLoad(const String& MIMEType) const { return !frameLoader()->isReplacing() || MIMEType == "text/html"; }
RetainPtr<CFDictionaryRef> ResourceLoader::connectionProperties(ResourceHandle*) { return frameLoader()->connectionProperties(this); }
void DocumentLoader::iconLoadDecisionAvailable() { if (m_frame) m_frame->loader()->icon()->loadDecisionReceived(iconDatabase().synchronousLoadDecisionForIconURL(frameLoader()->icon()->url(), this)); }
void ResourceLoader::didCreateQuickLookHandle(QuickLookHandle& handle) { frameLoader()->client().didCreateQuickLookHandle(handle); }
ResourceError ResourceLoader::blockedError() { return frameLoader()->client()->blockedError(m_request); }
void SubresourceLoader::didReceiveResponse(const ResourceResponse& response) { ASSERT(!response.isNull()); ASSERT(m_state == Initialized); // Reference the object in this method since the additional processing can do // anything including removing the last reference to this object; one example of this is 3266216. Ref<SubresourceLoader> protectedThis(*this); if (shouldIncludeCertificateInfo()) response.includeCertificateInfo(); if (response.isHttpVersion0_9()) { if (m_frame) { String message = "Sandboxing '" + response.url().string() + "' because it is using HTTP/0.9."; m_frame->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, message, identifier()); frameLoader()->forceSandboxFlags(SandboxScripts | SandboxPlugins); } } if (m_resource->resourceToRevalidate()) { if (response.httpStatusCode() == 304) { // 304 Not modified / Use local copy // Existing resource is ok, just use it updating the expiration time. m_resource->setResponse(response); MemoryCache::singleton().revalidationSucceeded(*m_resource, response); if (m_frame && m_frame->page()) m_frame->page()->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultPass, ShouldSample::Yes); if (!reachedTerminalState()) ResourceLoader::didReceiveResponse(response); return; } // Did not get 304 response, continue as a regular resource load. MemoryCache::singleton().revalidationFailed(*m_resource); if (m_frame && m_frame->page()) m_frame->page()->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultFail, ShouldSample::Yes); } m_resource->responseReceived(response); if (reachedTerminalState()) return; ResourceLoader::didReceiveResponse(response); if (reachedTerminalState()) return; // FIXME: Main resources have a different set of rules for multipart than images do. // Hopefully we can merge those 2 paths. if (response.isMultipart() && m_resource->type() != CachedResource::MainResource) { m_loadingMultipartContent = true; // We don't count multiParts in a CachedResourceLoader's request count m_requestCountTracker = Nullopt; if (!m_resource->isImage()) { cancel(); return; } } auto* buffer = resourceData(); if (m_loadingMultipartContent && buffer && buffer->size()) { // The resource data will change as the next part is loaded, so we need to make a copy. m_resource->finishLoading(buffer->copy().ptr()); clearResourceData(); // Since a subresource loader does not load multipart sections progressively, data was delivered to the loader all at once. // After the first multipart section is complete, signal to delegates that this load is "finished" m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this); didFinishLoadingOnePart(0); } checkForHTTPStatusCodeError(); }
bool ResourceLoader::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace) { RefPtr<ResourceLoader> protector(this); return frameLoader()->client()->canAuthenticateAgainstProtectionSpace(documentLoader(), identifier(), protectionSpace); }
bool ResourceLoader::shouldUseCredentialStorage() { RefPtr<ResourceLoader> protector(this); return frameLoader()->shouldUseCredentialStorage(this); }
void MainResourceLoader::responseReceived(CachedResource* resource, const ResourceResponse& r) { ASSERT_UNUSED(resource, m_resource == resource); bool willLoadFallback = documentLoader()->applicationCacheHost()->maybeLoadFallbackForMainResponse(request(), r); // The memory cache doesn't understand the application cache or its caching rules. So if a main resource is served // from the application cache, ensure we don't save the result for future use. bool shouldRemoveResourceFromCache = willLoadFallback; #if PLATFORM(CHROMIUM) // chromium's ApplicationCacheHost implementation always returns true for maybeLoadFallbackForMainResponse(). However, all responses loaded // from appcache will have a non-zero appCacheID(). if (r.appCacheID()) shouldRemoveResourceFromCache = true; #endif if (shouldRemoveResourceFromCache) memoryCache()->remove(m_resource.get()); if (willLoadFallback) return; DEFINE_STATIC_LOCAL(AtomicString, xFrameOptionHeader, ("x-frame-options", AtomicString::ConstructFromLiteral)); HTTPHeaderMap::const_iterator it = r.httpHeaderFields().find(xFrameOptionHeader); if (it != r.httpHeaderFields().end()) { String content = it->value; if (frameLoader()->shouldInterruptLoadForXFrameOptions(content, r.url(), identifier())) { InspectorInstrumentation::continueAfterXFrameOptionsDenied(m_documentLoader->frame(), documentLoader(), identifier(), r); String message = "Refused to display '" + r.url().string() + "' in a frame because it set 'X-Frame-Options' to '" + content + "'."; m_documentLoader->frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, message, identifier()); cancel(); return; } } // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred. // See <rdar://problem/6304600> for more details. #if !USE(CF) ASSERT(!defersLoading()); #endif if (m_loadingMultipartContent) { m_documentLoader->setupForReplace(); m_resource->clear(); } if (r.isMultipart()) m_loadingMultipartContent = true; // The additional processing can do anything including possibly removing the last // reference to this object; one example of this is 3266216. RefPtr<MainResourceLoader> protect(this); m_documentLoader->setResponse(r); m_response = r; if (!loader()) frameLoader()->notifier()->dispatchDidReceiveResponse(documentLoader(), identifier(), m_response, 0); ASSERT(!m_waitingForContentPolicy); m_waitingForContentPolicy = true; ref(); // balanced by deref in continueAfterContentPolicy and cancel // Always show content with valid substitute data. if (m_documentLoader->substituteData().isValid()) { callContinueAfterContentPolicy(this, PolicyUse); return; } #if ENABLE(FTPDIR) // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it Settings* settings = m_documentLoader->frame()->settings(); if (settings && settings->forceFTPDirectoryListings() && m_response.mimeType() == "application/x-ftp-directory") { callContinueAfterContentPolicy(this, PolicyUse); return; } #endif #if USE(CONTENT_FILTERING) if (r.url().protocolIs("https") && ContentFilter::isEnabled()) m_contentFilter = ContentFilter::create(r); #endif frameLoader()->policyChecker()->checkContentPolicy(m_response, callContinueAfterContentPolicy, this); }
bool ResourceLoader::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace) { RefPtr<ResourceLoader> protector(this); return frameLoader()->canAuthenticateAgainstProtectionSpace(this, protectionSpace); }
void MainResourceLoader::didCancel(const ResourceError& error) { // We should notify the frame loader after fully canceling the load, because it can do complicated work // like calling DOMWindow::print(), during which a half-canceled load could try to finish. frameLoader()->receivedMainResourceError(error, true); }
void DocumentLoader::setMainDocumentError(const ResourceError& error) { m_mainDocumentError = error; frameLoader()->client()->setMainDocumentError(this, error); }
void MainResourceLoader::didReceiveResponse(const ResourceResponse& r) { #if ENABLE(OFFLINE_WEB_APPLICATIONS) if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForMainResponse(request(), r)) return; #endif HTTPHeaderMap::const_iterator it = r.httpHeaderFields().find(AtomicString("x-frame-options")); if (it != r.httpHeaderFields().end()) { String content = it->second; if (m_frame->loader()->shouldInterruptLoadForXFrameOptions(content, r.url())) { DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to display document because display forbidden by X-Frame-Options.\n")); m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); cancel(); return; } } // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred. // See <rdar://problem/6304600> for more details. #if !USE(CF) ASSERT(shouldLoadAsEmptyDocument(r.url()) || !defersLoading()); #endif #if PLATFORM(QT) if (r.mimeType() == "application/octet-stream") substituteMIMETypeFromPluginDatabase(r); #endif if (m_loadingMultipartContent) { frameLoader()->setupForReplaceByMIMEType(r.mimeType()); clearResourceData(); } if (r.isMultipart()) m_loadingMultipartContent = true; // The additional processing can do anything including possibly removing the last // reference to this object; one example of this is 3266216. RefPtr<MainResourceLoader> protect(this); m_documentLoader->setResponse(r); m_response = r; ASSERT(!m_waitingForContentPolicy); m_waitingForContentPolicy = true; ref(); // balanced by deref in continueAfterContentPolicy and didCancel ASSERT(frameLoader()->activeDocumentLoader()); // Always show content with valid substitute data. if (frameLoader()->activeDocumentLoader()->substituteData().isValid()) { callContinueAfterContentPolicy(this, PolicyUse); return; } #if ENABLE(FTPDIR) // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it Settings* settings = m_frame->settings(); if (settings && settings->forceFTPDirectoryListings() && m_response.mimeType() == "application/x-ftp-directory") { callContinueAfterContentPolicy(this, PolicyUse); return; } #endif frameLoader()->policyChecker()->checkContentPolicy(m_response, callContinueAfterContentPolicy, this); }
void DocumentLoader::setupForReplace() { frameLoader()->setupForReplace(); m_committed = false; }
void MainResourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse) { // Note that there are no asserts here as there are for the other callbacks. This is due to the // fact that this "callback" is sent when starting every load, and the state of callback // deferrals plays less of a part in this function in preventing the bad behavior deferring // callbacks is meant to prevent. ASSERT(!newRequest.isNull()); // The additional processing can do anything including possibly removing the last // reference to this object; one example of this is 3266216. RefPtr<MainResourceLoader> protect(this); if (!frameLoader()->checkIfFormActionAllowedByCSP(newRequest.url())) { cancel(); return; } ASSERT(documentLoader()->timing()->fetchStart()); if (!redirectResponse.isNull()) { // If the redirecting url is not allowed to display content from the target origin, // then block the redirect. RefPtr<SecurityOrigin> redirectingOrigin = SecurityOrigin::create(redirectResponse.url()); if (!redirectingOrigin->canDisplay(newRequest.url())) { FrameLoader::reportLocalLoadFailed(m_documentLoader->frame(), newRequest.url().string()); cancel(); return; } documentLoader()->timing()->addRedirect(redirectResponse.url(), newRequest.url()); } // Update cookie policy base URL as URL changes, except for subframes, which use the // URL of the main frame which doesn't change when we redirect. if (frameLoader()->isLoadingMainFrame()) newRequest.setFirstPartyForCookies(newRequest.url()); // If we're fielding a redirect in response to a POST, force a load from origin, since // this is a common site technique to return to a page viewing some data that the POST // just modified. // Also, POST requests always load from origin, but this does not affect subresources. if (newRequest.cachePolicy() == UseProtocolCachePolicy && isPostOrRedirectAfterPost(newRequest, redirectResponse)) newRequest.setCachePolicy(ReloadIgnoringCacheData); Frame* top = m_documentLoader->frame()->tree()->top(); if (top != m_documentLoader->frame()) { if (!frameLoader()->mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), newRequest.url())) { cancel(); return; } } ResourceLoader::willSendRequest(newRequest, redirectResponse); // Don't set this on the first request. It is set when the main load was started. m_documentLoader->setRequest(newRequest); if (!redirectResponse.isNull()) { // We checked application cache for initial URL, now we need to check it for redirected one. ASSERT(!m_substituteData.isValid()); documentLoader()->applicationCacheHost()->maybeLoadMainResourceForRedirect(newRequest, m_substituteData); } // FIXME: Ideally we'd stop the I/O until we hear back from the navigation policy delegate // listener. But there's no way to do that in practice. So instead we cancel later if the // listener tells us to. In practice that means the navigation policy needs to be decided // synchronously for these redirect cases. if (!redirectResponse.isNull()) { ref(); // balanced by deref in continueAfterNavigationPolicy frameLoader()->policyChecker()->checkNavigationPolicy(newRequest, callContinueAfterNavigationPolicy, this); } }
void MainResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce) { ASSERT(data); ASSERT(length != 0); ASSERT(!m_response.isNull()); #if USE(CFNETWORK) || PLATFORM(MAC) // Workaround for <rdar://problem/6060782> if (m_response.isNull()) { m_response = ResourceResponse(KURL(), "text/html", 0, String(), String()); if (DocumentLoader* documentLoader = frameLoader()->activeDocumentLoader()) documentLoader->setResponse(m_response); } #endif // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred. // See <rdar://problem/6304600> for more details. #if !USE(CF) ASSERT(!defersLoading()); #endif #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 if (m_filter) { ASSERT(!wkFilterWasBlocked(m_filter)); const char* blockedData = wkFilterAddData(m_filter, data, &length); // If we don't have blockedData, that means we're still accumulating data if (!blockedData) { // Transition to committed state. ResourceLoader::didReceiveData("", 0, 0, false); return; } data = blockedData; encodedDataLength = -1; } #endif documentLoader()->applicationCacheHost()->mainResourceDataReceived(data, length, encodedDataLength, allAtOnce); // The additional processing can do anything including possibly removing the last // reference to this object; one example of this is 3266216. RefPtr<MainResourceLoader> protect(this); m_timeOfLastDataReceived = monotonicallyIncreasingTime(); ResourceLoader::didReceiveData(data, length, encodedDataLength, allAtOnce); #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 if (WebFilterEvaluator *filter = m_filter) { // If we got here, it means we know if we were blocked or not. If we were blocked, we're // done loading the page altogether. Either way, we don't need the filter anymore. // Remove this->m_filter early so didFinishLoading doesn't see it. m_filter = 0; if (wkFilterWasBlocked(filter)) cancel(); wkFilterRelease(filter); } #endif }