void ResourceLoader::didReceiveResponse(const ResourceResponse& r) { if (!fastMallocSize(documentLoader()->applicationCacheHost())) CRASH(); if (!fastMallocSize(documentLoader()->frame())) CRASH(); ASSERT(!m_reachedTerminalState); // Protect this in this delegate method since the additional processing can do // anything including possibly derefing this; one example of this is Radar 3266216. RefPtr<ResourceLoader> protector(this); m_response = r; if (FormData* data = m_request.httpBody()) data->removeGeneratedFilesIfNeeded(); if (m_options.sendLoadCallbacks == SendCallbacks) frameLoader()->notifier()->didReceiveResponse(this, m_response); }
void MainResourceLoader::receivedError(const ResourceError& error) { // Calling receivedMainResourceError will likely result in the last reference to this object to go away. RefPtr<MainResourceLoader> protect(this); RefPtr<Frame> protectFrame(m_documentLoader->frame()); // It is important that we call DocumentLoader::mainReceivedError before calling // ResourceLoadNotifier::didFailToLoad because mainReceivedError clears out the relevant // document loaders. Also, mainReceivedError ends up calling a FrameLoadDelegate method // and didFailToLoad calls a ResourceLoadDelegate method and they need to be in the correct order. documentLoader()->mainReceivedError(error); }
void MainResourceLoader::continueAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue) { if (!shouldContinue) stopLoadingForPolicyChange(); else if (m_substituteData.isValid()) { // A redirect resulted in loading substitute data. ASSERT(documentLoader()->timing()->redirectCount()); handle()->cancel(); handleSubstituteDataLoadSoon(request); } deref(); // balances ref in willSendRequest }
void MainResourceLoader::didFinishLoading(double finishTime) { // 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(frameLoader()->activeDocumentLoader()->url()) || !defersLoading()); #endif // The additional processing can do anything including possibly removing the last // reference to this object. RefPtr<MainResourceLoader> protect(this); RefPtr<DocumentLoader> dl = documentLoader(); if (m_loadingMultipartContent) dl->maybeFinishLoadingMultipartContent(); documentLoader()->timing()->setResponseEnd(finishTime ? finishTime : (m_timeOfLastDataReceived ? m_timeOfLastDataReceived : monotonicallyIncreasingTime())); frameLoader()->finishedLoading(); ResourceLoader::didFinishLoading(finishTime); dl->applicationCacheHost()->finishedLoadingMainResource(); }
bool ApplicationCacheHost::maybeLoadFallbackForMainError(const ResourceRequest& request, const ResourceError& error) { if (!error.isCancellation()) { ASSERT(!m_mainResourceApplicationCache); if (isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request)) { m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, m_documentLoader); if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader(), m_mainResourceApplicationCache.get())) return true; } } return false; }
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. documentLoader()->mainReceivedError(error); #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 if (m_filter) { wkFilterRelease(m_filter); m_filter = 0; } #endif }
void MainResourceLoader::didFail(const ResourceError& error) { if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForMainError(request(), error)) 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 receivedError(error); }
unsigned long long PerformanceTiming::secureConnectionStart() const { DocumentLoader* loader = documentLoader(); if (!loader) return 0; const ResourceLoadTiming& timing = loader->response().resourceLoadTiming(); if (timing.secureConnectionStart < 0) return 0; return resourceLoadTimeRelativeToAbsolute(timing.secureConnectionStart); }
bool ApplicationCacheHost::maybeLoadFallbackForMainResponse(const ResourceRequest& request, const ResourceResponse& r) { if (r.httpStatusCode() / 100 == 4 || r.httpStatusCode() / 100 == 5) { ASSERT(!m_mainResourceApplicationCache); if (isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request)) { m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, documentLoader()); if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader(), m_mainResourceApplicationCache.get())) return true; } } return false; }
void MainResourceLoader::didFinishLoading(double finishTime) { // 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() || InspectorInstrumentation::isDebuggerPaused(m_documentLoader->frame())); #endif // The additional processing can do anything including possibly removing the last // reference to this object. RefPtr<MainResourceLoader> protect(this); RefPtr<DocumentLoader> dl = documentLoader(); if (!loader()) { frameLoader()->notifier()->dispatchDidFinishLoading(documentLoader(), identifier(), finishTime); m_substituteDataLoadIdentifier = 0; } #if USE(CONTENT_FILTERING) if (m_filter) { int length; const char* data = wkFilterDataComplete(m_filter, &length); WebFilterEvaluator *filter = m_filter; // Remove this->m_filter early so didReceiveData doesn't see it. m_filter = 0; if (data) dataReceived(m_resource.get(), data, length); wkFilterRelease(filter); } #endif if (m_loadingMultipartContent) dl->maybeFinishLoadingMultipartContent(); documentLoader()->timing()->setResponseEnd(finishTime ? finishTime : (m_timeOfLastDataReceived ? m_timeOfLastDataReceived : monotonicallyIncreasingTime())); documentLoader()->finishedLoading(); dl->applicationCacheHost()->finishedLoadingMainResource(); }
bool ResourceLoader::isInclusionRequest() { DocumentLoader* loader = documentLoader(); if (loader->frameLoader()->isLoadingMainFrame() && !loader->isLoadingSubresources()) return false; else return true; // for debug // NF4_DP((" => isLoadingMainResource(): %s", ((loader->isLoadingMainResource())?"true":"false"))); // NF4_DP((" => isLoadingSubresources(): %s", ((loader->isLoadingSubresources())?"true":"false"))); // NF4_DP((" => isLoadingMainFrame(): %s", ((loader->frameLoader()->isLoadingMainFrame())?"true":"false"))); // NF4_DP((" => subframeIsLoading() : %s", ((loader->frameLoader()->subframeIsLoading())?"true":"false"))); }
bool ApplicationCacheHost::maybeLoadSynchronously(ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data) { ApplicationCacheResource* resource; if (shouldLoadResourceFromApplicationCache(request, resource)) { if (resource) { response = resource->response(); data.append(resource->data()->data(), resource->data()->size()); } else { error = documentLoader()->frameLoader()->client().cannotShowURLError(request); } return true; } return false; }
void ResourceLoader::willSendRequest(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); if (frameLoader() && frameLoader()->frame().page() && frameLoader()->frame().page()->userContentController() && m_documentLoader) frameLoader()->frame().page()->userContentController()->processContentExtensionRulesForLoad(request, m_resourceType, *m_documentLoader); if (request.isNull()) { didFail(cannotShowURLError()); return; } #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 (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); if (!redirectResponse.isNull()) platformStrategies()->loaderStrategy()->resourceLoadScheduler()->crossOriginRedirectReceived(this, request.url()); m_request = request; if (!redirectResponse.isNull() && !m_documentLoader->isCommitted()) frameLoader()->client().dispatchDidReceiveServerRedirectForProvisionalLoad(); }
void ResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce) { if (!m_cancelled && !fastMallocSize(documentLoader()->applicationCacheHost())) CRASH(); if (!m_cancelled && !fastMallocSize(documentLoader()->frame())) CRASH(); // The following assertions are not quite valid here, since a subclass // might override didReceiveData in a way that invalidates them. This // happens with the steps listed in 3266216 // ASSERT(con == connection); // ASSERT(!m_reachedTerminalState); // Protect this in this delegate method since the additional processing can do // anything including possibly derefing this; one example of this is Radar 3266216. RefPtr<ResourceLoader> protector(this); addData(data, length, allAtOnce); // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing. // However, with today's computers and networking speeds, this won't happen in practice. // Could be an issue with a giant local file. if (m_options.sendLoadCallbacks == SendCallbacks && m_frame) frameLoader()->notifier()->didReceiveData(this, data, length, static_cast<int>(encodedDataLength)); }
void ApplicationCacheHost::stopDeferringEvents() { RefPtr<DocumentLoader> protect(documentLoader()); for (unsigned i = 0; i < m_deferredEvents.size(); ++i) { EventID id = m_deferredEvents[i]; if (m_domApplicationCache) { ExceptionCode ec = 0; m_domApplicationCache->dispatchEvent(Event::create(DOMApplicationCache::toEventType(id), false, false), ec); ASSERT(!ec); } } m_deferredEvents.clear(); m_defersEvents = false; }
void MainResourceLoader::load(const ResourceRequest& initialRequest, const SubstituteData& substituteData) { // It appears that it is possible for this load to be cancelled and derefenced by the DocumentLoader // in willSendRequest() if loadNow() is called. RefPtr<MainResourceLoader> protect(this); m_substituteData = substituteData; ASSERT(documentLoader()->timing()->navigationStart()); ASSERT(!documentLoader()->timing()->fetchStart()); documentLoader()->timing()->markFetchStart(); ResourceRequest request(initialRequest); // Send this synthetic delegate callback since clients expect it, and // we no longer send the callback from within NSURLConnection for // initial requests. willSendRequest(request, ResourceResponse()); ASSERT(!deletionHasBegun()); // willSendRequest() may lead to our DocumentLoader being detached or cancelling the load via nulling the ResourceRequest. if (!documentLoader()->frame() || request.isNull()) return; documentLoader()->applicationCacheHost()->maybeLoadMainResource(request, m_substituteData); if (m_substituteData.isValid()) { handleSubstituteDataLoadSoon(request); return; } DEFINE_STATIC_LOCAL(ResourceLoaderOptions, mainResourceLoadOptions, (SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, AskClientForCrossOriginCredentials, SkipSecurityCheck)); CachedResourceRequest cachedResourceRequest(request, mainResourceLoadOptions); m_resource = documentLoader()->cachedResourceLoader()->requestMainResource(cachedResourceRequest); if (!m_resource) { documentLoader()->setRequest(ResourceRequest()); return; } m_resource->addClient(this); // We need to wait until after requestMainResource() is called to setRequest(), because there are a bunch of headers set when // the underlying ResourceLoader is created, and DocumentLoader::m_request needs to include those. However, the cache will // strip the fragment identifier (which DocumentLoader::m_request should also include), so add that back in. if (loader()) request = loader()->originalRequest(); documentLoader()->setRequest(request); }
void MainResourceLoader::load(const ResourceRequest& r, const SubstituteData& substituteData) { ASSERT(!m_handle); // It appears that it is possible for this load to be cancelled and derefenced by the DocumentLoader // in willSendRequest() if loadNow() is called. RefPtr<MainResourceLoader> protect(this); m_substituteData = substituteData; ASSERT(documentLoader()->timing()->navigationStart()); ASSERT(!documentLoader()->timing()->fetchStart()); documentLoader()->timing()->markFetchStart(); ResourceRequest request(r); // Send this synthetic delegate callback since clients expect it, and // we no longer send the callback from within NSURLConnection for // initial requests. willSendRequest(request, ResourceResponse()); ASSERT(!deletionHasBegun()); // <rdar://problem/4801066> // willSendRequest() is liable to make the call to frameLoader() return null, so we need to check that here if (!frameLoader() || request.isNull()) { if (!reachedTerminalState()) releaseResources(); return; } documentLoader()->applicationCacheHost()->maybeLoadMainResource(request, m_substituteData); if (defersLoading()) m_initialRequest = request; else loadNow(request); }
unsigned long long PerformanceTiming::secureConnectionStart() const { DocumentLoader* loader = documentLoader(); if (!loader) return 0; ResourceLoadTiming* timing = loader->response().resourceLoadTiming(); if (!timing) return 0; double sslStart = timing->sslStart(); if (sslStart == 0.0) return 0; return monotonicTimeToIntegerMilliseconds(sslStart); }
unsigned long long PerformanceTiming::domainLookupEnd() const { DocumentLoader* loader = documentLoader(); if (!loader) return domainLookupStart(); const ResourceLoadTiming& timing = loader->response().resourceLoadTiming(); // This will be -1 when a DNS request is not performed. // Rather than exposing a special value that indicates no DNS, we "backfill" with domainLookupStart. if (timing.domainLookupEnd < 0) return domainLookupStart(); return resourceLoadTimeRelativeToAbsolute(timing.domainLookupEnd); }
unsigned long long PerformanceTiming::connectEnd() const { DocumentLoader* loader = documentLoader(); if (!loader) return connectStart(); const ResourceLoadTiming& timing = loader->response().resourceLoadTiming(); // connectEnd will be -1 when a network request is not made. // Rather than exposing a special value that indicates no new connection, we "backfill" with connectStart. if (timing.connectEnd < 0) return connectStart(); return resourceLoadTimeRelativeToAbsolute(timing.connectEnd); }
unsigned long long PerformanceTiming::secureConnectionStart() const { DocumentLoader* loader = documentLoader(); if (!loader) return 0; ResourceLoadTiming* timing = loader->response().resourceLoadTiming(); if (!timing) return 0; int sslStart = timing->sslStart; if (sslStart < 0) return 0; return resourceLoadTimeRelativeToAbsolute(sslStart); }
unsigned long long PerformanceTiming::connectEnd() const { DocumentLoader* loader = documentLoader(); if (!loader) return connectStart(); ResourceLoadTiming* timing = loader->response().resourceLoadTiming(); if (!timing) return connectStart(); // connectEnd will be zero when a network request is not made. Rather than // exposing a special value that indicates no new connection, we "backfill" // with connectStart. double connectEnd = timing->connectEnd(); if (connectEnd == 0.0 || loader->response().connectionReused()) return connectStart(); return monotonicTimeToIntegerMilliseconds(connectEnd); }
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())) { 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 !PLATFORM(CF) ASSERT(shouldLoadAsEmptyDocument(r.url()) || !defersLoading()); #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 frameLoader()->checkContentPolicy(m_response.mimeType(), callContinueAfterContentPolicy, this); }
void MainResourceLoader::didFail(const ResourceError& error) { #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 if (m_filter) { wkFilterRelease(m_filter); m_filter = 0; } #endif if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForMainError(request(), error)) 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 receivedError(error); }
unsigned long long PerformanceTiming::connectStart() const { DocumentLoader* loader = documentLoader(); if (!loader) return domainLookupEnd(); const ResourceLoadTiming& timing = loader->response().resourceLoadTiming(); // connectStart will be -1 when a network request is not made. // Rather than exposing a special value that indicates no new connection, we "backfill" with domainLookupEnd. int connectStart = timing.connectStart; if (connectStart < 0) return domainLookupEnd(); // ResourceLoadTiming's connect phase includes DNS, however Navigation Timing's // connect phase should not. So if there is DNS time, trim it from the start. if (timing.domainLookupEnd >= 0 && timing.domainLookupEnd > connectStart) connectStart = timing.domainLookupEnd; return resourceLoadTimeRelativeToAbsolute(connectStart); }
void ResourceLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response) { #if ENABLE(INSPECTOR) if (InspectorTimelineAgent::instanceCount()) { InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0; if (timelineAgent) timelineAgent->willReceiveResourceResponse(identifier(), response); } #endif #if ENABLE(OFFLINE_WEB_APPLICATIONS) if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForResponse(this, response)) return; #endif didReceiveResponse(response); #if ENABLE(INSPECTOR) if (InspectorTimelineAgent::instanceCount()) { InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0; if (timelineAgent) timelineAgent->didReceiveResourceResponse(); } #endif }
unsigned long long PerformanceTiming::connectStart() const { DocumentLoader* loader = documentLoader(); if (!loader) return domainLookupEnd(); ResourceLoadTiming* timing = loader->response().resourceLoadTiming(); if (!timing) return domainLookupEnd(); // connectStart will be zero when a network request is not made. // Rather than exposing a special value that indicates no new connection, we "backfill" with domainLookupEnd. double connectStart = timing->connectStart; if (connectStart == 0.0 || loader->response().connectionReused()) return domainLookupEnd(); // ResourceLoadTiming's connect phase includes DNS, however Navigation Timing's // connect phase should not. So if there is DNS time, trim it from the start. if (timing->dnsEnd > 0.0 && timing->dnsEnd > connectStart) connectStart = timing->dnsEnd; return monotonicTimeToIntegerMilliseconds(connectStart); }
void MainResourceLoader::didFinishLoading() { // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred. // See <rdar://problem/6304600> for more details. #if !PLATFORM(CF) ASSERT(shouldLoadAsEmptyDocument(frameLoader()->activeDocumentLoader()->url()) || !defersLoading()); #endif // The additional processing can do anything including possibly removing the last // reference to this object. RefPtr<MainResourceLoader> protect(this); #if ENABLE(OFFLINE_WEB_APPLICATIONS) RefPtr<DocumentLoader> dl = documentLoader(); #endif frameLoader()->finishedLoading(); ResourceLoader::didFinishLoading(); #if ENABLE(OFFLINE_WEB_APPLICATIONS) dl->applicationCacheHost()->finishedLoadingMainResource(); #endif }
void MainResourceLoader::continueAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue) { if (!shouldContinue) stopLoadingForPolicyChange(); else if (m_substituteData.isValid()) { // A redirect resulted in loading substitute data. ASSERT(documentLoader()->timing()->redirectCount()); // We need to remove our reference to the CachedResource in favor of a SubstituteData load. // This will probably trigger the cancellation of the CachedResource's underlying ResourceLoader, though there is a // small chance that the resource is being loaded by a different Frame, preventing the ResourceLoader from being cancelled. // If the ResourceLoader is indeed cancelled, it would normally send resource load callbacks. // However, from an API perspective, this isn't a cancellation. Therefore, sever our relationship with the network load via clearResource(), // but prevent the ResourceLoader from sending ResourceLoadNotifier callbacks. RefPtr<ResourceLoader> resourceLoader = loader(); ASSERT(resourceLoader->shouldSendResourceLoadCallbacks()); resourceLoader->setSendCallbackPolicy(DoNotSendCallbacks); clearResource(); resourceLoader->setSendCallbackPolicy(SendCallbacks); handleSubstituteDataLoadSoon(request); } deref(); // balances ref in willSendRequest }
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 }