Upstream version 7.35.139.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / fetch / ResourceFetcher.cpp
index 651050f..cce718c 100644 (file)
@@ -31,9 +31,9 @@
 #include "bindings/v8/ScriptController.h"
 #include "core/dom/Document.h"
 #include "core/fetch/CSSStyleSheetResource.h"
+#include "core/fetch/CrossOriginAccessControl.h"
 #include "core/fetch/DocumentResource.h"
 #include "core/fetch/FetchContext.h"
-#include "core/fetch/FetchRequest.h"
 #include "core/fetch/FontResource.h"
 #include "core/fetch/ImageResource.h"
 #include "core/fetch/MemoryCache.h"
 #include "core/fetch/XSLStyleSheetResource.h"
 #include "core/html/HTMLElement.h"
 #include "core/html/HTMLFrameOwnerElement.h"
-#include "core/html/HTMLImport.h"
+#include "core/html/imports/HTMLImport.h"
 #include "core/inspector/InspectorInstrumentation.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/loader/FrameLoader.h"
 #include "core/loader/FrameLoaderClient.h"
 #include "core/loader/PingLoader.h"
+#include "core/loader/SubstituteData.h"
 #include "core/loader/UniqueIdentifier.h"
 #include "core/loader/appcache/ApplicationCacheHost.h"
-#include "core/frame/ContentSecurityPolicy.h"
 #include "core/frame/DOMWindow.h"
-#include "core/frame/Frame.h"
+#include "core/frame/LocalFrame.h"
+#include "core/frame/csp/ContentSecurityPolicy.h"
 #include "core/timing/Performance.h"
 #include "core/timing/ResourceTimingInfo.h"
-#include "core/page/Settings.h"
+#include "core/frame/Settings.h"
 #include "platform/Logging.h"
 #include "platform/TraceEvent.h"
+#include "platform/weborigin/SecurityOrigin.h"
+#include "platform/weborigin/SecurityPolicy.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebURL.h"
-#include "weborigin/SecurityOrigin.h"
-#include "weborigin/SecurityPolicy.h"
 #include "wtf/text/CString.h"
 #include "wtf/text/WTFString.h"
 
@@ -122,7 +123,9 @@ static ResourceLoadPriority loadPriority(Resource::Type type, const FetchRequest
     case Resource::ImportResource:
         return ResourceLoadPriorityMedium;
     case Resource::Image:
-        return request.forPreload() ? ResourceLoadPriorityVeryLow : ResourceLoadPriorityLow;
+        // We'll default images to VeryLow, and promote whatever is visible. This improves
+        // speed-index by ~5% on average, ~14% at the 99th percentile.
+        return ResourceLoadPriorityVeryLow;
     case Resource::XSLStyleSheet:
         ASSERT(RuntimeEnabledFeatures::xsltEnabled());
         return ResourceLoadPriorityHigh;
@@ -146,9 +149,9 @@ static Resource* resourceFromDataURIRequest(const ResourceRequest& request, cons
     const KURL& url = request.url();
     ASSERT(url.protocolIsData());
 
-    WebKit::WebString mimetype;
-    WebKit::WebString charset;
-    RefPtr<SharedBuffer> data = PassRefPtr<SharedBuffer>(WebKit::Platform::current()->parseDataURL(url, mimetype, charset));
+    blink::WebString mimetype;
+    blink::WebString charset;
+    RefPtr<SharedBuffer> data = PassRefPtr<SharedBuffer>(blink::Platform::current()->parseDataURL(url, mimetype, charset));
     if (!data)
         return 0;
     ResourceResponse response(url, mimetype, data->size(), charset, String());
@@ -156,29 +159,34 @@ static Resource* resourceFromDataURIRequest(const ResourceRequest& request, cons
     Resource* resource = createResource(Resource::Image, request, charset);
     resource->setOptions(resourceOptions);
     resource->responseReceived(response);
-    // FIXME: AppendData causes an unnecessary memcpy.
     if (data->size())
-        resource->appendData(data->data(), data->size());
+        resource->setResourceBuffer(data);
     resource->finish();
     return resource;
 }
 
-static void reportResourceTiming(ResourceTimingInfo* info, Resource* resource, double finishTime, Document* initiatorDocument, bool clearLoadTimings)
+static void populateResourceTiming(ResourceTimingInfo* info, Resource* resource, bool clearLoadTimings)
 {
-    if (resource->type() == Resource::MainResource)
-        initiatorDocument = initiatorDocument->parentDocument();
-    ASSERT(initiatorDocument);
     info->setInitialRequest(resource->resourceRequest());
     info->setFinalResponse(resource->response());
-    if (clearLoadTimings)
+    if (clearLoadTimings) {
         info->clearLoadTimings();
-    info->setLoadFinishTime(finishTime);
-    if (DOMWindow* initiatorWindow = initiatorDocument->domWindow()) {
-        if (Performance* performance = initiatorWindow->performance())
-            performance->addResourceTiming(*info, initiatorDocument);
+        info->setLoadFinishTime(info->initialTime());
+    } else {
+        info->setLoadFinishTime(resource->loadFinishTime());
     }
 }
 
+static void reportResourceTiming(ResourceTimingInfo* info, Document* initiatorDocument, bool isMainResource)
+{
+    if (initiatorDocument && isMainResource)
+        initiatorDocument = initiatorDocument->parentDocument();
+    if (!initiatorDocument || !initiatorDocument->loader())
+        return;
+    if (DOMWindow* initiatorWindow = initiatorDocument->domWindow())
+        initiatorWindow->performance().addResourceTiming(*info, initiatorDocument);
+}
+
 static ResourceRequest::TargetType requestTargetType(const ResourceFetcher* fetcher, const ResourceRequest& request, Resource::Type type)
 {
     switch (type) {
@@ -218,6 +226,7 @@ ResourceFetcher::ResourceFetcher(DocumentLoader* documentLoader)
     , m_documentLoader(documentLoader)
     , m_requestCount(0)
     , m_garbageCollectDocumentResourcesTimer(this, &ResourceFetcher::garbageCollectDocumentResourcesTimerFired)
+    , m_resourceTimingReportTimer(this, &ResourceFetcher::resourceTimingReportTimerFired)
     , m_autoLoadImages(true)
     , m_imagesEnabled(true)
     , m_allowStaleResources(false)
@@ -235,19 +244,13 @@ ResourceFetcher::~ResourceFetcher()
     ASSERT(!m_requestCount);
 }
 
-Resource* ResourceFetcher::cachedResource(const String& resourceURL) const
-{
-    KURL url = m_document->completeURL(resourceURL);
-    return cachedResource(url);
-}
-
 Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const
 {
     KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL);
     return m_documentResources.get(url).get();
 }
 
-Frame* ResourceFetcher::frame() const
+LocalFrame* ResourceFetcher::frame() const
 {
     if (m_documentLoader)
         return m_documentLoader->frame();
@@ -258,7 +261,7 @@ Frame* ResourceFetcher::frame() const
 
 FetchContext& ResourceFetcher::context() const
 {
-    if (Frame* frame = this->frame())
+    if (LocalFrame* frame = this->frame())
         return frame->fetchContext();
     return FetchContext::nullInstance();
 }
@@ -275,10 +278,10 @@ ResourcePtr<Resource> ResourceFetcher::fetchSynchronously(FetchRequest& request)
 
 ResourcePtr<ImageResource> ResourceFetcher::fetchImage(FetchRequest& request)
 {
-    if (Frame* f = frame()) {
+    if (LocalFrame* f = frame()) {
         if (f->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal) {
             KURL requestURL = request.resourceRequest().url();
-            if (requestURL.isValid() && canRequest(Resource::Image, requestURL, request.options(), request.forPreload()))
+            if (requestURL.isValid() && canRequest(Resource::Image, requestURL, request.options(), request.forPreload(), request.originRestriction()))
                 PingLoader::loadImage(f, requestURL);
             return 0;
         }
@@ -288,7 +291,7 @@ ResourcePtr<ImageResource> ResourceFetcher::fetchImage(FetchRequest& request)
         preCacheDataURIImage(request);
 
     request.setDefer(clientDefersImage(request.resourceRequest().url()) ? FetchRequest::DeferredByClient : FetchRequest::NoDefer);
-    return static_cast<ImageResource*>(requestResource(Resource::Image, request).get());
+    return toImageResource(requestResource(Resource::Image, request));
 }
 
 void ResourceFetcher::preCacheDataURIImage(const FetchRequest& request)
@@ -299,28 +302,30 @@ void ResourceFetcher::preCacheDataURIImage(const FetchRequest& request)
     if (memoryCache()->resourceForURL(url))
         return;
 
-    if (Resource* resource = resourceFromDataURIRequest(request.resourceRequest(), request.options()))
+    if (Resource* resource = resourceFromDataURIRequest(request.resourceRequest(), request.options())) {
         memoryCache()->add(resource);
+        scheduleDocumentResourcesGC();
+    }
 }
 
 ResourcePtr<FontResource> ResourceFetcher::fetchFont(FetchRequest& request)
 {
-    return static_cast<FontResource*>(requestResource(Resource::Font, request).get());
+    return toFontResource(requestResource(Resource::Font, request));
 }
 
 ResourcePtr<ShaderResource> ResourceFetcher::fetchShader(FetchRequest& request)
 {
-    return static_cast<ShaderResource*>(requestResource(Resource::Shader, request).get());
+    return toShaderResource(requestResource(Resource::Shader, request));
 }
 
 ResourcePtr<RawResource> ResourceFetcher::fetchImport(FetchRequest& request)
 {
-    return static_cast<RawResource*>(requestResource(Resource::ImportResource, request).get());
+    return toRawResource(requestResource(Resource::ImportResource, request));
 }
 
 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchCSSStyleSheet(FetchRequest& request)
 {
-    return static_cast<CSSStyleSheetResource*>(requestResource(Resource::CSSStyleSheet, request).get());
+    return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
 }
 
 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchUserCSSStyleSheet(FetchRequest& request)
@@ -329,28 +334,28 @@ ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchUserCSSStyleSheet(Fetch
 
     if (Resource* existing = memoryCache()->resourceForURL(url)) {
         if (existing->type() == Resource::CSSStyleSheet)
-            return static_cast<CSSStyleSheetResource*>(existing);
+            return toCSSStyleSheetResource(existing);
         memoryCache()->remove(existing);
     }
 
-    request.setOptions(ResourceLoaderOptions(DoNotSendCallbacks, SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, AskClientForCrossOriginCredentials, SkipSecurityCheck, CheckContentSecurityPolicy, UseDefaultOriginRestrictionsForType, DocumentContext));
-    return static_cast<CSSStyleSheetResource*>(requestResource(Resource::CSSStyleSheet, request).get());
+    request.setOptions(ResourceLoaderOptions(SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
+    return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
 }
 
 ResourcePtr<ScriptResource> ResourceFetcher::fetchScript(FetchRequest& request)
 {
-    return static_cast<ScriptResource*>(requestResource(Resource::Script, request).get());
+    return toScriptResource(requestResource(Resource::Script, request));
 }
 
 ResourcePtr<XSLStyleSheetResource> ResourceFetcher::fetchXSLStyleSheet(FetchRequest& request)
 {
     ASSERT(RuntimeEnabledFeatures::xsltEnabled());
-    return static_cast<XSLStyleSheetResource*>(requestResource(Resource::XSLStyleSheet, request).get());
+    return toXSLStyleSheetResource(requestResource(Resource::XSLStyleSheet, request));
 }
 
 ResourcePtr<DocumentResource> ResourceFetcher::fetchSVGDocument(FetchRequest& request)
 {
-    return static_cast<DocumentResource*>(requestResource(Resource::SVGDocument, request).get());
+    return toDocumentResource(requestResource(Resource::SVGDocument, request));
 }
 
 ResourcePtr<Resource> ResourceFetcher::fetchLinkResource(Resource::Type type, FetchRequest& request)
@@ -362,12 +367,32 @@ ResourcePtr<Resource> ResourceFetcher::fetchLinkResource(Resource::Type type, Fe
 
 ResourcePtr<RawResource> ResourceFetcher::fetchRawResource(FetchRequest& request)
 {
-    return static_cast<RawResource*>(requestResource(Resource::Raw, request).get());
+    return toRawResource(requestResource(Resource::Raw, request));
 }
 
-ResourcePtr<RawResource> ResourceFetcher::fetchMainResource(FetchRequest& request)
+ResourcePtr<RawResource> ResourceFetcher::fetchMainResource(FetchRequest& request, const SubstituteData& substituteData)
 {
-    return static_cast<RawResource*>(requestResource(Resource::MainResource, request).get());
+    if (substituteData.isValid())
+        preCacheSubstituteDataForMainResource(request, substituteData);
+    return toRawResource(requestResource(Resource::MainResource, request));
+}
+
+void ResourceFetcher::preCacheSubstituteDataForMainResource(const FetchRequest& request, const SubstituteData& substituteData)
+{
+    const KURL& url = request.url();
+    if (Resource* oldResource = memoryCache()->resourceForURL(url))
+        memoryCache()->remove(oldResource);
+
+    ResourceResponse response(url, substituteData.mimeType(), substituteData.content()->size(), substituteData.textEncoding(), emptyString());
+    ResourcePtr<Resource> resource = createResource(Resource::MainResource, request.resourceRequest(), substituteData.textEncoding());
+    resource->setNeedsSynchronousCacheHit(substituteData.forceSynchronousLoad());
+    resource->setOptions(request.options());
+    resource->setDataBufferingPolicy(BufferData);
+    resource->responseReceived(response);
+    if (substituteData.content()->size())
+        resource->setResourceBuffer(substituteData.content());
+    resource->finish();
+    memoryCache()->add(resource.get());
 }
 
 bool ResourceFetcher::checkInsecureContent(Resource::Type type, const KURL& url, MixedContentBlockingTreatment treatment) const
@@ -403,16 +428,16 @@ bool ResourceFetcher::checkInsecureContent(Resource::Type type, const KURL& url,
         }
     }
     if (treatment == TreatAsActiveContent) {
-        if (Frame* f = frame()) {
+        if (LocalFrame* f = frame()) {
             if (!f->loader().mixedContentChecker()->canRunInsecureContent(m_document->securityOrigin(), url))
                 return false;
-            Frame* top = f->tree().top();
+            LocalFrame* top = f->tree().top();
             if (top != f && !top->loader().mixedContentChecker()->canRunInsecureContent(top->document()->securityOrigin(), url))
                 return false;
         }
     } else if (treatment == TreatAsPassiveContent) {
-        if (Frame* f = frame()) {
-            Frame* top = f->tree().top();
+        if (LocalFrame* f = frame()) {
+            LocalFrame* top = f->tree().top();
             if (!top->loader().mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), url))
                 return false;
         }
@@ -422,12 +447,16 @@ bool ResourceFetcher::checkInsecureContent(Resource::Type type, const KURL& url,
     return true;
 }
 
-bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const ResourceLoaderOptions& options, bool forPreload)
+bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const ResourceLoaderOptions& options, bool forPreload, FetchRequest::OriginRestriction originRestriction) const
 {
-    if (document() && !document()->securityOrigin()->canDisplay(url)) {
+    SecurityOrigin* securityOrigin = options.securityOrigin.get();
+    if (!securityOrigin && document())
+        securityOrigin = document()->securityOrigin();
+
+    if (securityOrigin && !securityOrigin->canDisplay(url)) {
         if (!forPreload)
             context().reportLocalLoadFailed(url);
-        LOG(ResourceLoading, "ResourceFetcher::requestResource URL was not allowed by SecurityOrigin::canDisplay");
+        WTF_LOG(ResourceLoading, "ResourceFetcher::requestResource URL was not allowed by SecurityOrigin::canDisplay");
         return 0;
     }
 
@@ -451,7 +480,7 @@ bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const Res
     case Resource::ImportResource:
         // By default these types of resources can be loaded from any origin.
         // FIXME: Are we sure about Resource::Font?
-        if (options.requestOriginPolicy == RestrictToSameOrigin && !m_document->securityOrigin()->canRequest(url)) {
+        if (originRestriction == FetchRequest::RestrictToSameOrigin && !securityOrigin->canRequest(url)) {
             printAccessDeniedMessage(url);
             return false;
         }
@@ -459,7 +488,7 @@ bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const Res
     case Resource::XSLStyleSheet:
         ASSERT(RuntimeEnabledFeatures::xsltEnabled());
     case Resource::SVGDocument:
-        if (!m_document->securityOrigin()->canRequest(url)) {
+        if (!securityOrigin->canRequest(url)) {
             printAccessDeniedMessage(url);
             return false;
         }
@@ -479,7 +508,7 @@ bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const Res
 
         if (frame()) {
             Settings* settings = frame()->settings();
-            if (!frame()->loader().client()->allowScriptFromSource(!settings || settings->isScriptEnabled(), url)) {
+            if (!frame()->loader().client()->allowScriptFromSource(!settings || settings->scriptEnabled(), url)) {
                 frame()->loader().client()->didNotAllowScript();
                 return false;
             }
@@ -523,40 +552,38 @@ bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const Res
     return true;
 }
 
-bool ResourceFetcher::canAccess(Resource* resource)
+bool ResourceFetcher::canAccessResource(Resource* resource, SecurityOrigin* sourceOrigin, const KURL& url) const
 {
     // Redirects can change the response URL different from one of request.
-    if (!canRequest(resource->type(), resource->response().url(), resource->options(), false))
+    if (!canRequest(resource->type(), url, resource->options(), false, FetchRequest::UseDefaultOriginRestrictionForType))
         return false;
 
-    String error;
-    switch (resource->type()) {
-    case Resource::Script:
-    case Resource::ImportResource:
-        if (resource->options().requestOriginPolicy == PotentiallyCrossOriginEnabled
-            && !m_document->securityOrigin()->canRequest(resource->response().url())
-            && !resource->passesAccessControlCheck(m_document->securityOrigin(), error)) {
-            if (frame() && frame()->document())
-                frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Script from origin '" + SecurityOrigin::create(resource->response().url())->toString() + "' has been blocked from loading by Cross-Origin Resource Sharing policy: " + error);
-            return false;
-        }
+    if (!sourceOrigin && document())
+        sourceOrigin = document()->securityOrigin();
 
-        break;
-    default:
-        ASSERT_NOT_REACHED(); // FIXME: generalize to non-script resources
+    if (sourceOrigin->canRequest(url))
+        return true;
+
+    String errorDescription;
+    if (!resource->passesAccessControlCheck(sourceOrigin, errorDescription)) {
+        if (frame() && frame()->document()) {
+            String resourceType = Resource::resourceTypeToString(resource->type(), resource->options().initiatorInfo);
+            frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, resourceType + " from origin '" + SecurityOrigin::create(url)->toString() + "' has been blocked from loading by Cross-Origin Resource Sharing policy: " + errorDescription);
+        }
         return false;
     }
-
     return true;
 }
 
-bool ResourceFetcher::shouldLoadNewResource() const
+bool ResourceFetcher::shouldLoadNewResource(Resource::Type type) const
 {
     if (!frame())
         return false;
     if (!m_documentLoader)
         return true;
-    return m_documentLoader == frame()->loader().activeDocumentLoader();
+    if (type == Resource::MainResource)
+        return m_documentLoader == frame()->loader().provisionalDocumentLoader();
+    return m_documentLoader == frame()->loader().documentLoader();
 }
 
 bool ResourceFetcher::resourceNeedsLoad(Resource* resource, const FetchRequest& request, RevalidationPolicy policy)
@@ -576,7 +603,7 @@ ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, Fetc
 
     KURL url = request.resourceRequest().url();
 
-    LOG(ResourceLoading, "ResourceFetcher::requestResource '%s', charset '%s', priority=%d, forPreload=%u, type=%s", url.elidedString().latin1().data(), request.charset().latin1().data(), request.priority(), request.forPreload(), ResourceTypeName(type));
+    WTF_LOG(ResourceLoading, "ResourceFetcher::requestResource '%s', charset '%s', priority=%d, forPreload=%u, type=%s", url.elidedString().latin1().data(), request.charset().latin1().data(), request.priority(), request.forPreload(), ResourceTypeName(type));
 
     // If only the fragment identifiers differ, it is the same resource.
     url = MemoryCache::removeFragmentIdentifierIfNeeded(url);
@@ -584,16 +611,16 @@ ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, Fetc
     if (!url.isValid())
         return 0;
 
-    if (!canRequest(type, url, request.options(), request.forPreload()))
+    if (!canRequest(type, url, request.options(), request.forPreload(), request.originRestriction()))
         return 0;
 
-    if (Frame* f = frame())
+    if (LocalFrame* f = frame())
         f->loader().client()->dispatchWillRequestResource(&request);
 
     // See if we can use an existing resource from the cache.
     ResourcePtr<Resource> resource = memoryCache()->resourceForURL(url);
 
-    const RevalidationPolicy policy = determineRevalidationPolicy(type, request.mutableResourceRequest(), request.forPreload(), resource.get(), request.defer());
+    const RevalidationPolicy policy = determineRevalidationPolicy(type, request.mutableResourceRequest(), request.forPreload(), resource.get(), request.defer(), request.options());
     switch (policy) {
     case Reload:
         memoryCache()->remove(resource.get());
@@ -605,7 +632,7 @@ ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, Fetc
         resource = revalidateResource(request, resource.get());
         break;
     case Use:
-        resource->updateForAccess();
+        memoryCache()->updateForAccess(resource.get());
         notifyLoadedFromMemoryCache(resource.get());
         break;
     }
@@ -613,6 +640,9 @@ ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, Fetc
     if (!resource)
         return 0;
 
+    if (!resource->hasClients())
+        m_deadStatsRecorder.update(policy);
+
     if (policy != Use)
         resource->setIdentifier(createUniqueIdentifier());
 
@@ -620,13 +650,13 @@ ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, Fetc
         ResourceLoadPriority priority = loadPriority(type, request);
         if (priority != resource->resourceRequest().priority()) {
             resource->resourceRequest().setPriority(priority);
-            resource->didChangePriority(priority);
+            resource->didChangePriority(priority, 0);
         }
     }
 
     if (resourceNeedsLoad(resource.get(), request, policy)) {
-        if (!shouldLoadNewResource()) {
-            if (resource->inCache())
+        if (!shouldLoadNewResource(type)) {
+            if (memoryCache()->contains(resource.get()))
                 memoryCache()->remove(resource.get());
             return 0;
         }
@@ -641,7 +671,7 @@ ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, Fetc
         // In that case, the requester should have access to the relevant ResourceError, so
         // we need to return a non-null Resource.
         if (resource->errorOccurred()) {
-            if (resource->inCache())
+            if (memoryCache()->contains(resource.get()))
                 memoryCache()->remove(resource.get());
             return request.options().synchronousPolicy == RequestSynchronously ? resource : 0;
         }
@@ -655,18 +685,21 @@ ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, Fetc
     // Ensure main resources aren't preloaded, and other main resource loads
     // are removed from cache to prevent reuse.
     if (type == Resource::MainResource) {
-        ASSERT(policy != Use);
+        ASSERT(policy != Use || m_documentLoader->substituteData().isValid());
         ASSERT(policy != Revalidate);
         memoryCache()->remove(resource.get());
         if (request.forPreload())
             return 0;
     }
 
-    if (!request.resourceRequest().url().protocolIsData()) {
+    if (!request.resourceRequest().url().protocolIsData() && (!m_documentLoader || !m_documentLoader->substituteData().isValid())) {
         if (policy == Use && !m_validatedURLs.contains(request.resourceRequest().url())) {
             // Resources loaded from memory cache should be reported the first time they're used.
             RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime());
-            reportResourceTiming(info.get(), resource.get(), monotonicallyIncreasingTime(), document(), true);
+            populateResourceTiming(info.get(), resource.get(), true);
+            m_scheduledResourceTimingReports.add(info, resource->type() == Resource::MainResource);
+            if (!m_resourceTimingReportTimer.isActive())
+                m_resourceTimingReportTimer.startOneShot(0, FROM_HERE);
         }
 
         m_validatedURLs.add(request.resourceRequest().url());
@@ -677,6 +710,19 @@ ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, Fetc
     return resource;
 }
 
+void ResourceFetcher::resourceTimingReportTimerFired(Timer<ResourceFetcher>* timer)
+{
+    ASSERT_UNUSED(timer, timer == &m_resourceTimingReportTimer);
+    HashMap<RefPtr<ResourceTimingInfo>, bool> timingReports;
+    timingReports.swap(m_scheduledResourceTimingReports);
+    HashMap<RefPtr<ResourceTimingInfo>, bool>::iterator end = timingReports.end();
+    for (HashMap<RefPtr<ResourceTimingInfo>, bool>::iterator it = timingReports.begin(); it != end; ++it) {
+        RefPtr<ResourceTimingInfo> info = it->key;
+        bool isMainResource = it->value;
+        reportResourceTiming(info.get(), document(), isMainResource);
+    }
+}
+
 void ResourceFetcher::determineTargetType(ResourceRequest& request, Resource::Type type)
 {
     ResourceRequest::TargetType targetType = requestTargetType(this, request, type);
@@ -694,7 +740,7 @@ ResourceRequestCachePolicy ResourceFetcher::resourceRequestCachePolicy(const Res
             return ReturnCacheDataElseLoad;
         if (isReload || frameLoadType == FrameLoadTypeSame || request.isConditional() || request.httpMethod() == "POST")
             return ReloadIgnoringCacheData;
-        if (Frame* parent = frame()->tree().parent())
+        if (LocalFrame* parent = frame()->tree().parent())
             return parent->document()->fetcher()->resourceRequestCachePolicy(request, type);
         return UseProtocolCachePolicy;
     }
@@ -702,7 +748,7 @@ ResourceRequestCachePolicy ResourceFetcher::resourceRequestCachePolicy(const Res
     if (request.isConditional())
         return ReloadIgnoringCacheData;
 
-    if (m_documentLoader && m_documentLoader->isLoadingInAPISense()) {
+    if (m_documentLoader && m_document && !m_document->loadEventFinished()) {
         // For POST requests, we mutate the main resource's cache policy to avoid form resubmission.
         // This policy should not be inherited by subresources.
         ResourceRequestCachePolicy mainResourceCachePolicy = m_documentLoader->request().cachePolicy();
@@ -725,25 +771,26 @@ void ResourceFetcher::addAdditionalRequestHeaders(ResourceRequest& request, Reso
     if (type == Resource::LinkPrefetch || type == Resource::LinkSubresource)
         request.setHTTPHeaderField("Purpose", "prefetch");
 
-    context().addAdditionalRequestHeaders(*document(), request, type);
+    context().addAdditionalRequestHeaders(document(), request, (type == Resource::MainResource) ? FetchMainResource : FetchSubresource);
 }
 
 ResourcePtr<Resource> ResourceFetcher::revalidateResource(const FetchRequest& request, Resource* resource)
 {
     ASSERT(resource);
-    ASSERT(resource->inCache());
+    ASSERT(memoryCache()->contains(resource));
     ASSERT(resource->isLoaded());
     ASSERT(resource->canUseCacheValidator());
     ASSERT(!resource->resourceToRevalidate());
 
     ResourceRequest revalidatingRequest(resource->resourceRequest());
+    revalidatingRequest.clearHTTPReferrer();
     addAdditionalRequestHeaders(revalidatingRequest, resource->type());
 
-    const String& lastModified = resource->response().httpHeaderField("Last-Modified");
-    const String& eTag = resource->response().httpHeaderField("ETag");
+    const AtomicString& lastModified = resource->response().httpHeaderField("Last-Modified");
+    const AtomicString& eTag = resource->response().httpHeaderField("ETag");
     if (!lastModified.isEmpty() || !eTag.isEmpty()) {
-        ASSERT(context().cachePolicy(resource->type()) != CachePolicyReload);
-        if (context().cachePolicy(resource->type()) == CachePolicyRevalidate)
+        ASSERT(context().cachePolicy(document()) != CachePolicyReload);
+        if (context().cachePolicy(document()) == CachePolicyRevalidate)
             revalidatingRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
         if (!lastModified.isEmpty())
             revalidatingRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
@@ -753,7 +800,7 @@ ResourcePtr<Resource> ResourceFetcher::revalidateResource(const FetchRequest& re
 
     ResourcePtr<Resource> newResource = createResource(resource->type(), revalidatingRequest, resource->encoding());
 
-    LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), resource);
+    WTF_LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), resource);
     newResource->setResourceToRevalidate(resource);
 
     memoryCache()->remove(resource);
@@ -767,7 +814,7 @@ ResourcePtr<Resource> ResourceFetcher::loadResource(Resource::Type type, FetchRe
 {
     ASSERT(!memoryCache()->resourceForURL(request.resourceRequest().url()));
 
-    LOG(ResourceLoading, "Loading Resource for '%s'.", request.resourceRequest().url().elidedString().latin1().data());
+    WTF_LOG(ResourceLoading, "Loading Resource for '%s'.", request.resourceRequest().url().elidedString().latin1().data());
 
     addAdditionalRequestHeaders(request.mutableResourceRequest(), type);
     ResourcePtr<Resource> resource = createResource(type, request.mutableResourceRequest(), charset);
@@ -797,7 +844,7 @@ void ResourceFetcher::storeResourceTimingInitiatorInformation(const ResourcePtr<
     }
 }
 
-ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy(Resource::Type type, ResourceRequest& request, bool forPreload, Resource* existingResource, FetchRequest::DeferOption defer) const
+ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy(Resource::Type type, ResourceRequest& request, bool forPreload, Resource* existingResource, FetchRequest::DeferOption defer, const ResourceLoaderOptions& options) const
 {
     if (!existingResource)
         return Load;
@@ -808,7 +855,7 @@ ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy
 
     // If the same URL has been loaded as a different type, we need to reload.
     if (existingResource->type() != type) {
-        LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to type mismatch.");
+        WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to type mismatch.");
         return Reload;
     }
 
@@ -822,9 +869,17 @@ ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy
     if (type == Resource::Image && request.url().protocolIsData())
         return Use;
 
+    // If a main resource was populated from a SubstituteData load, use it.
+    if (type == Resource::MainResource && m_documentLoader->substituteData().isValid())
+        return Use;
+
     if (!existingResource->canReuse(request))
         return Reload;
 
+    // Never use cache entries for downloadToFile requests. The caller expects the resource in a file.
+    if (request.downloadToFile())
+        return Reload;
+
     // Certain requests (e.g., XHRs) might have manually set headers that require revalidation.
     // FIXME: In theory, this should be a Revalidate case. In practice, the MemoryCache revalidation path assumes a whole bunch
     // of things about how revalidation works that manual headers violate, so punt to Reload instead.
@@ -835,44 +890,50 @@ ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy
     if (m_allowStaleResources)
         return Use;
 
-    // Alwaus use preloads.
+    // Always use preloads.
     if (existingResource->isPreloaded())
         return Use;
 
     // CachePolicyHistoryBuffer uses the cache no matter what.
-    if (context().cachePolicy(type) == CachePolicyHistoryBuffer)
+    CachePolicy cachePolicy = context().cachePolicy(document());
+    if (cachePolicy == CachePolicyHistoryBuffer)
         return Use;
 
     // Don't reuse resources with Cache-control: no-store.
     if (existingResource->response().cacheControlContainsNoStore()) {
-        LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to Cache-control: no-store.");
+        WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to Cache-control: no-store.");
         return Reload;
     }
 
+    // If fetching a resource with a different 'CORS enabled' flag, reload.
+    if (type != Resource::MainResource && options.corsEnabled != existingResource->options().corsEnabled)
+        return Reload;
+
     // If credentials were sent with the previous request and won't be
     // with this one, or vice versa, re-fetch the resource.
     //
     // This helps with the case where the server sends back
     // "Access-Control-Allow-Origin: *" all the time, but some of the
     // client's requests are made without CORS and some with.
-    if (existingResource->resourceRequest().allowCookies() != request.allowCookies()) {
-        LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to difference in credentials settings.");
+    if (existingResource->resourceRequest().allowStoredCredentials() != request.allowStoredCredentials()) {
+        WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to difference in credentials settings.");
         return Reload;
     }
 
-    // During the initial load, avoid loading the same resource multiple times for a single document, even if the cache policies would tell us to.
-    if (document() && !document()->loadEventFinished() && m_validatedURLs.contains(existingResource->url()))
+    // During the initial load, avoid loading the same resource multiple times for a single document,
+    // even if the cache policies would tell us to. Raw resources are exempted.
+    if (type != Resource::Raw && document() && !document()->loadEventFinished() && m_validatedURLs.contains(existingResource->url()))
         return Use;
 
     // CachePolicyReload always reloads
-    if (context().cachePolicy(type) == CachePolicyReload) {
-        LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to CachePolicyReload.");
+    if (cachePolicy == CachePolicyReload) {
+        WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to CachePolicyReload.");
         return Reload;
     }
 
     // We'll try to reload the resource if it failed last time.
     if (existingResource->errorOccurred()) {
-        LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicye reloading due to resource being in the error state");
+        WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicye reloading due to resource being in the error state");
         return Reload;
     }
 
@@ -880,14 +941,20 @@ ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy
     if (existingResource->isLoading())
         return Use;
 
+    // If any of the redirects in the chain to loading the resource were not cacheable, we cannot reuse our cached resource.
+    if (!existingResource->canReuseRedirectChain()) {
+        WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to an uncacheable redirect");
+        return Reload;
+    }
+
     // Check if the cache headers requires us to revalidate (cache expiration for example).
-    if (existingResource->mustRevalidateDueToCacheHeaders(context().cachePolicy(type))) {
+    if (cachePolicy == CachePolicyRevalidate || existingResource->mustRevalidateDueToCacheHeaders()) {
         // See if the resource has usable ETag or Last-modified headers.
         if (existingResource->canUseCacheValidator())
             return Revalidate;
 
         // No, must reload.
-        LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to missing cache validators.");
+        WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to missing cache validators.");
         return Reload;
     }
 
@@ -974,16 +1041,20 @@ void ResourceFetcher::didLoadResource(Resource* resource)
         if (it != m_resourceTimingInfoMap.end()) {
             RefPtr<ResourceTimingInfo> info = it->value;
             m_resourceTimingInfoMap.remove(it);
-            reportResourceTiming(info.get(), resource, resource->loadFinishTime(), document(), false);
+            populateResourceTiming(info.get(), resource, false);
+            reportResourceTiming(info.get(), document(), resource->type() == Resource::MainResource);
         }
     }
 
     if (frame())
         frame()->loader().loadDone();
-    performPostLoadActions();
+    scheduleDocumentResourcesGC();
+}
 
+void ResourceFetcher::scheduleDocumentResourcesGC()
+{
     if (!m_garbageCollectDocumentResourcesTimer.isActive())
-        m_garbageCollectDocumentResourcesTimer.startOneShot(0);
+        m_garbageCollectDocumentResourcesTimer.startOneShot(0, FROM_HERE);
 }
 
 // Garbage collecting m_documentResources is a workaround for the
@@ -1012,25 +1083,18 @@ void ResourceFetcher::garbageCollectDocumentResources()
         m_documentResources.remove(*it);
 }
 
-void ResourceFetcher::performPostLoadActions()
-{
-    checkForPendingPreloads();
-}
-
 void ResourceFetcher::notifyLoadedFromMemoryCache(Resource* resource)
 {
     if (!frame() || !frame()->page() || resource->status() != Resource::Cached || m_validatedURLs.contains(resource->url()))
         return;
-    if (!resource->shouldSendResourceLoadCallbacks())
-        return;
 
     ResourceRequest request(resource->url());
     unsigned long identifier = createUniqueIdentifier();
     context().dispatchDidLoadResourceFromMemoryCache(request, resource->response());
     // FIXME: If willSendRequest changes the request, we don't respect it.
-    willSendRequest(identifier, request, ResourceResponse(), resource->options());
+    willSendRequest(identifier, request, ResourceResponse(), resource->options().initiatorInfo);
     InspectorInstrumentation::markResourceAsCached(frame()->page(), identifier);
-    context().sendRemainingDelegateMessages(m_documentLoader, identifier, resource->response(), 0, resource->encodedSize(), 0, ResourceError());
+    context().sendRemainingDelegateMessages(m_documentLoader, identifier, resource->response(), resource->encodedSize());
 }
 
 void ResourceFetcher::incrementRequestCount(const Resource* res)
@@ -1055,25 +1119,11 @@ void ResourceFetcher::preload(Resource::Type type, FetchRequest& request, const
     requestPreload(type, request, charset);
 }
 
-void ResourceFetcher::checkForPendingPreloads()
-{
-    // FIXME: It seems wrong to poke body()->renderer() here.
-    if (m_pendingPreloads.isEmpty() || !m_document->body() || !m_document->body()->renderer())
-        return;
-    while (!m_pendingPreloads.isEmpty()) {
-        PendingPreload preload = m_pendingPreloads.takeFirst();
-        // Don't request preload if the resource already loaded normally (this will result in double load if the page is being reloaded with cached results ignored).
-        if (!cachedResource(preload.m_request.resourceRequest().url()))
-            requestPreload(preload.m_type, preload.m_request, preload.m_charset);
-    }
-    m_pendingPreloads.clear();
-}
-
 void ResourceFetcher::requestPreload(Resource::Type type, FetchRequest& request, const String& charset)
 {
     String encoding;
     if (type == Resource::Script || type == Resource::CSSStyleSheet)
-        encoding = charset.isEmpty() ? m_document->charset() : charset;
+        encoding = charset.isEmpty() ? m_document->charset().string() : charset;
 
     request.setCharset(encoding);
     request.setForPreload(true);
@@ -1081,7 +1131,7 @@ void ResourceFetcher::requestPreload(Resource::Type type, FetchRequest& request,
     ResourcePtr<Resource> resource = requestResource(type, request);
     if (!resource || (m_preloads && m_preloads->contains(resource.get())))
         return;
-    TRACE_EVENT_ASYNC_STEP0("net", "Resource", resource.get(), "Preload");
+    TRACE_EVENT_ASYNC_STEP_INTO0("net", "Resource", resource.get(), "Preload");
     resource->increasePreloadCount();
 
     if (!m_preloads)
@@ -1089,7 +1139,7 @@ void ResourceFetcher::requestPreload(Resource::Type type, FetchRequest& request,
     m_preloads->add(resource.get());
 
 #if PRELOAD_DEBUG
-    printf("PRELOADING %s\n",  resource->url().latin1().data());
+    printf("PRELOADING %s\n",  resource->url().string().latin1().data());
 #endif
 }
 
@@ -1106,12 +1156,6 @@ bool ResourceFetcher::isPreloaded(const String& urlString) const
         }
     }
 
-    Deque<PendingPreload>::const_iterator dequeEnd = m_pendingPreloads.end();
-    for (Deque<PendingPreload>::const_iterator it = m_pendingPreloads.begin(); it != dequeEnd; ++it) {
-        PendingPreload pendingPreload = *it;
-        if (pendingPreload.m_request.resourceRequest().url() == url)
-            return true;
-    }
     return false;
 }
 
@@ -1134,56 +1178,42 @@ void ResourceFetcher::clearPreloads()
     m_preloads.clear();
 }
 
-void ResourceFetcher::clearPendingPreloads()
-{
-    m_pendingPreloads.clear();
-}
-
-void ResourceFetcher::didFinishLoading(const Resource* resource, double finishTime, const ResourceLoaderOptions& options)
+void ResourceFetcher::didFinishLoading(const Resource* resource, double finishTime, int64_t encodedDataLength)
 {
     TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
-    if (options.sendLoadCallbacks != SendCallbacks)
-        return;
-    context().dispatchDidFinishLoading(m_documentLoader, resource->identifier(), finishTime);
+    context().dispatchDidFinishLoading(m_documentLoader, resource->identifier(), finishTime, encodedDataLength);
 }
 
-void ResourceFetcher::didChangeLoadingPriority(const Resource* resource, ResourceLoadPriority loadPriority)
+void ResourceFetcher::didChangeLoadingPriority(const Resource* resource, ResourceLoadPriority loadPriority, int intraPriorityValue)
 {
-    TRACE_EVENT_ASYNC_STEP1("net", "Resource", resource, "ChangePriority", "priority", loadPriority);
-    context().dispatchDidChangeResourcePriority(resource->identifier(), loadPriority);
+    TRACE_EVENT_ASYNC_STEP_INTO1("net", "Resource", resource, "ChangePriority", "priority", loadPriority);
+    context().dispatchDidChangeResourcePriority(resource->identifier(), loadPriority, intraPriorityValue);
 }
 
-void ResourceFetcher::didFailLoading(const Resource* resource, const ResourceError& error, const ResourceLoaderOptions& options)
+void ResourceFetcher::didFailLoading(const Resource* resource, const ResourceError& error)
 {
     TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
-    if (options.sendLoadCallbacks != SendCallbacks)
-        return;
     context().dispatchDidFail(m_documentLoader, resource->identifier(), error);
 }
 
-void ResourceFetcher::willSendRequest(unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse, const ResourceLoaderOptions& options)
+void ResourceFetcher::willSendRequest(unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse, const FetchInitiatorInfo& initiatorInfo)
 {
-    if (options.sendLoadCallbacks == SendCallbacks)
-        context().dispatchWillSendRequest(m_documentLoader, identifier, request, redirectResponse, options.initiatorInfo);
-    else
-        InspectorInstrumentation::willSendRequest(frame(), identifier, m_documentLoader, request, redirectResponse, options.initiatorInfo);
+    context().dispatchWillSendRequest(m_documentLoader, identifier, request, redirectResponse, initiatorInfo);
 }
 
-void ResourceFetcher::didReceiveResponse(const Resource* resource, const ResourceResponse& response, const ResourceLoaderOptions& options)
+void ResourceFetcher::didReceiveResponse(const Resource* resource, const ResourceResponse& response)
 {
-    if (options.sendLoadCallbacks != SendCallbacks)
-        return;
     context().dispatchDidReceiveResponse(m_documentLoader, resource->identifier(), response, resource->loader());
 }
 
-void ResourceFetcher::didReceiveData(const Resource* resource, const char* data, int dataLength, int encodedDataLength, const ResourceLoaderOptions& options)
+void ResourceFetcher::didReceiveData(const Resource* resource, const char* data, int dataLength, int encodedDataLength)
 {
-    // FIXME: use frame of master document for imported documents.
-    InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(frame(), resource->identifier(), encodedDataLength);
-    if (options.sendLoadCallbacks != SendCallbacks)
-        return;
     context().dispatchDidReceiveData(m_documentLoader, resource->identifier(), data, dataLength, encodedDataLength);
-    InspectorInstrumentation::didReceiveResourceData(cookie);
+}
+
+void ResourceFetcher::didDownloadData(const Resource* resource, int dataLength, int encodedDataLength)
+{
+    context().dispatchDidDownloadData(m_documentLoader, resource->identifier(), dataLength, encodedDataLength);
 }
 
 void ResourceFetcher::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
@@ -1192,7 +1222,7 @@ void ResourceFetcher::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* lo
         m_multipartLoaders->add(loader);
     if (m_loaders)
         m_loaders->remove(loader);
-    if (Frame* frame = this->frame())
+    if (LocalFrame* frame = this->frame())
         return frame->loader().checkLoadComplete(m_documentLoader);
 }
 
@@ -1211,7 +1241,7 @@ void ResourceFetcher::willTerminateResourceLoader(ResourceLoader* loader)
     if (!m_loaders || !m_loaders->contains(loader))
         return;
     m_loaders->remove(loader);
-    if (Frame* frame = this->frame())
+    if (LocalFrame* frame = this->frame())
         frame->loader().checkLoadComplete(m_documentLoader);
 }
 
@@ -1242,7 +1272,7 @@ void ResourceFetcher::setDefersLoading(bool defers)
 
 bool ResourceFetcher::defersLoading() const
 {
-    if (Frame* frame = this->frame())
+    if (LocalFrame* frame = this->frame())
         return frame->page()->defersLoading();
     return false;
 }
@@ -1252,10 +1282,22 @@ bool ResourceFetcher::isLoadedBy(ResourceLoaderHost* possibleOwner) const
     return this == possibleOwner;
 }
 
-bool ResourceFetcher::shouldRequest(Resource* resource, const ResourceRequest& request, const ResourceLoaderOptions& options)
+bool ResourceFetcher::canAccessRedirect(Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse, ResourceLoaderOptions& options)
 {
-    if (!canRequest(resource->type(), request.url(), options))
+    if (!canRequest(resource->type(), request.url(), options, false, FetchRequest::UseDefaultOriginRestrictionForType))
         return false;
+    if (options.corsEnabled == IsCORSEnabled) {
+        SecurityOrigin* sourceOrigin = options.securityOrigin.get();
+        if (!sourceOrigin && document())
+            sourceOrigin = document()->securityOrigin();
+
+        String errorMessage;
+        if (!CrossOriginAccessControl::handleRedirect(resource, sourceOrigin, request, redirectResponse, options, errorMessage)) {
+            if (frame() && frame()->document())
+                frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, errorMessage);
+            return false;
+        }
+    }
     if (resource->type() == Resource::Image && shouldDeferImageLoad(request.url()))
         return false;
     return true;
@@ -1274,21 +1316,24 @@ void ResourceFetcher::derefResourceLoaderHost()
 #if PRELOAD_DEBUG
 void ResourceFetcher::printPreloadStats()
 {
+    if (!m_preloads)
+        return;
+
     unsigned scripts = 0;
     unsigned scriptMisses = 0;
     unsigned stylesheets = 0;
     unsigned stylesheetMisses = 0;
     unsigned images = 0;
     unsigned imageMisses = 0;
-    ListHashSet<Resource*>::iterator end = m_preloads.end();
-    for (ListHashSet<Resource*>::iterator it = m_preloads.begin(); it != end; ++it) {
+    ListHashSet<Resource*>::iterator end = m_preloads->end();
+    for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
         Resource* res = *it;
         if (res->preloadResult() == Resource::PreloadNotReferenced)
-            printf("!! UNREFERENCED PRELOAD %s\n", res->url().latin1().data());
+            printf("!! UNREFERENCED PRELOAD %s\n", res->url().string().latin1().data());
         else if (res->preloadResult() == Resource::PreloadReferencedWhileComplete)
-            printf("HIT COMPLETE PRELOAD %s\n", res->url().latin1().data());
+            printf("HIT COMPLETE PRELOAD %s\n", res->url().string().latin1().data());
         else if (res->preloadResult() == Resource::PreloadReferencedWhileLoading)
-            printf("HIT LOADING PRELOAD %s\n", res->url().latin1().data());
+            printf("HIT LOADING PRELOAD %s\n", res->url().string().latin1().data());
 
         if (res->type() == Resource::Script) {
             scripts++;
@@ -1322,8 +1367,41 @@ void ResourceFetcher::printPreloadStats()
 
 const ResourceLoaderOptions& ResourceFetcher::defaultResourceOptions()
 {
-    DEFINE_STATIC_LOCAL(ResourceLoaderOptions, options, (SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, AskClientForCrossOriginCredentials, DoSecurityCheck, CheckContentSecurityPolicy, UseDefaultOriginRestrictionsForType, DocumentContext));
+    DEFINE_STATIC_LOCAL(ResourceLoaderOptions, options, (SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
     return options;
 }
 
+ResourceFetcher::DeadResourceStatsRecorder::DeadResourceStatsRecorder()
+    : m_useCount(0)
+    , m_revalidateCount(0)
+    , m_loadCount(0)
+{
+}
+
+ResourceFetcher::DeadResourceStatsRecorder::~DeadResourceStatsRecorder()
+{
+    blink::Platform::current()->histogramCustomCounts(
+        "WebCore.ResourceFetcher.HitCount", m_useCount, 0, 1000, 50);
+    blink::Platform::current()->histogramCustomCounts(
+        "WebCore.ResourceFetcher.RevalidateCount", m_revalidateCount, 0, 1000, 50);
+    blink::Platform::current()->histogramCustomCounts(
+        "WebCore.ResourceFetcher.LoadCount", m_loadCount, 0, 1000, 50);
+}
+
+void ResourceFetcher::DeadResourceStatsRecorder::update(RevalidationPolicy policy)
+{
+    switch (policy) {
+    case Reload:
+    case Load:
+        ++m_loadCount;
+        return;
+    case Revalidate:
+        ++m_revalidateCount;
+        return;
+    case Use:
+        ++m_useCount;
+        return;
+    }
+}
+
 }