void SVGUseElement::updateExternalDocument() { URL externalDocumentURL; if (inDocument() && isExternalURIReference(href(), document())) { externalDocumentURL = document().completeURL(href()); if (!externalDocumentURL.hasFragmentIdentifier()) externalDocumentURL = URL(); } if (externalDocumentURL == (m_externalDocument ? m_externalDocument->url() : URL())) return; if (m_externalDocument) m_externalDocument->removeClient(this); if (externalDocumentURL.isNull()) m_externalDocument = nullptr; else { ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); options.setContentSecurityPolicyImposition(isInUserAgentShadowTree() ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck); CachedResourceRequest request { ResourceRequest { externalDocumentURL }, options }; request.setInitiator(this); m_externalDocument = document().cachedResourceLoader().requestSVGDocument(request); if (m_externalDocument) m_externalDocument->addClient(this); } invalidateShadowTree(); }
static RefPtr<StyleImage> loadPendingImage(Document& document, const StyleImage& image, const Element* element, LoadPolicy loadPolicy = LoadPolicy::Normal) { auto& pendingImage = downcast<StylePendingImage>(image); ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); options.setContentSecurityPolicyImposition(element && element->isInUserAgentShadowTree() ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck); // FIXME: Why does shape-outside have different policy than other properties? if (loadPolicy == LoadPolicy::ShapeOutside) { options.mode = FetchOptions::Mode::Cors; options.setAllowCredentials(DoNotAllowStoredCredentials); } if (auto imageValue = pendingImage.cssImageValue()) return imageValue->cachedImage(document.cachedResourceLoader(), options); if (auto imageGeneratorValue = pendingImage.cssImageGeneratorValue()) { imageGeneratorValue->loadSubimages(document.cachedResourceLoader(), options); return StyleGeneratedImage::create(*imageGeneratorValue); } if (auto cursorImageValue = pendingImage.cssCursorImageValue()) return cursorImageValue->cachedImage(document.cachedResourceLoader(), options); #if ENABLE(CSS_IMAGE_SET) if (auto imageSetValue = pendingImage.cssImageSetValue()) return imageSetValue->cachedImageSet(document.cachedResourceLoader(), options); #endif return nullptr; }
bool TextTrackLoader::load(const URL& url, const String& crossOriginMode, bool isInitiatingElementInUserAgentShadowTree) { cancelLoad(); ASSERT(is<Document>(m_scriptExecutionContext)); Document* document = downcast<Document>(m_scriptExecutionContext); ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); options.setContentSecurityPolicyImposition(isInitiatingElementInUserAgentShadowTree ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck); CachedResourceRequest cueRequest(ResourceRequest(document->completeURL(url)), options); if (!crossOriginMode.isNull()) { m_crossOriginMode = crossOriginMode; StoredCredentials allowCredentials = equalLettersIgnoringASCIICase(crossOriginMode, "use-credentials") ? AllowStoredCredentials : DoNotAllowStoredCredentials; updateRequestForAccessControl(cueRequest.mutableResourceRequest(), document->securityOrigin(), allowCredentials); } else { // Cross-origin resources that are not suitably CORS-enabled may not load. if (!document->securityOrigin()->canRequest(url)) { corsPolicyPreventedLoad(); return false; } } m_resource = document->cachedResourceLoader().requestTextTrack(cueRequest); if (!m_resource) return false; m_resource->addClient(this); return true; }
static void loadPendingSVGFilters(const PendingResources& pendingResources, Document& document, const Element* element) { if (pendingResources.pendingSVGFilters.isEmpty()) return; ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); options.setContentSecurityPolicyImposition(element && element->isInUserAgentShadowTree() ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck); for (auto& filterOperation : pendingResources.pendingSVGFilters) filterOperation->getOrCreateCachedSVGDocumentReference()->load(document.cachedResourceLoader(), options); }
void SVGFEImageElement::requestImageResource() { ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); options.setContentSecurityPolicyImposition(isInUserAgentShadowTree() ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck); CachedResourceRequest request(ResourceRequest(document().completeURL(href())), options); request.setInitiator(this); m_cachedImage = document().cachedResourceLoader().requestImage(request); if (m_cachedImage) m_cachedImage->addClient(this); }
ResourceLoader::ResourceLoader(Frame& frame, ResourceLoaderOptions options) : m_frame(&frame) , m_documentLoader(frame.loader().activeDocumentLoader()) , m_defersLoading(options.defersLoadingPolicy() == DefersLoadingPolicy::AllowDefersLoading && frame.page()->defersLoading()) , m_options(options) { }
void SVGFontFaceUriElement::loadFont() { if (m_cachedFont) m_cachedFont->removeClient(this); const AtomicString& href = getAttribute(XLinkNames::hrefAttr); if (!href.isNull()) { ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); options.setContentSecurityPolicyImposition(isInUserAgentShadowTree() ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck); CachedResourceLoader& cachedResourceLoader = document().cachedResourceLoader(); CachedResourceRequest request(ResourceRequest(document().completeURL(href)), options); request.setInitiator(this); m_cachedFont = cachedResourceLoader.requestFont(request, isSVGFontTarget(*this)); if (m_cachedFont) { m_cachedFont->addClient(this); m_cachedFont->beginLoadIfNeeded(cachedResourceLoader); } } else m_cachedFont = nullptr; }
ResourceLoader::ResourceLoader(Frame* frame, ResourceLoaderOptions options) : m_frame(frame) , m_documentLoader(frame->loader().activeDocumentLoader()) , m_identifier(0) , m_reachedTerminalState(false) , m_notifiedLoadComplete(false) , m_cancellationStatus(NotCancelled) , m_defersLoading(options.defersLoadingPolicy() == DefersLoadingPolicy::AllowDefersLoading && frame->page()->defersLoading()) , m_options(options) , m_isQuickLookResource(false) #if ENABLE(CONTENT_EXTENSIONS) , m_resourceType(ResourceType::Invalid) #endif { }
void ImageLoader::updateFromElement() { // If we're not making renderers for the page, then don't load images. We don't want to slow // down the raw HTML parsing case by loading images we don't intend to display. Document& document = element().document(); if (!document.hasLivingRenderTree()) return; AtomicString attr = element().imageSourceURL(); // Avoid loading a URL we already failed to load. if (!m_failedLoadURL.isEmpty() && attr == m_failedLoadURL) return; // Do not load any image if the 'src' attribute is missing or if it is // an empty string. CachedResourceHandle<CachedImage> newImage = nullptr; if (!attr.isNull() && !stripLeadingAndTrailingHTMLSpaces(attr).isEmpty()) { ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); options.setContentSecurityPolicyImposition(element().isInUserAgentShadowTree() ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck); CachedResourceRequest request(ResourceRequest(document.completeURL(sourceURI(attr))), options); request.setInitiator(&element()); String crossOriginMode = element().fastGetAttribute(HTMLNames::crossoriginAttr); if (!crossOriginMode.isNull()) { StoredCredentials allowCredentials = equalIgnoringCase(crossOriginMode, "use-credentials") ? AllowStoredCredentials : DoNotAllowStoredCredentials; updateRequestForAccessControl(request.mutableResourceRequest(), document.securityOrigin(), allowCredentials); } if (m_loadManually) { bool autoLoadOtherImages = document.cachedResourceLoader().autoLoadImages(); document.cachedResourceLoader().setAutoLoadImages(false); newImage = new CachedImage(request.resourceRequest(), m_element.document().page()->sessionID()); newImage->setLoading(true); newImage->setOwningCachedResourceLoader(&document.cachedResourceLoader()); document.cachedResourceLoader().m_documentResources.set(newImage->url(), newImage.get()); document.cachedResourceLoader().setAutoLoadImages(autoLoadOtherImages); } else newImage = document.cachedResourceLoader().requestImage(request); // If we do not have an image here, it means that a cross-site // violation occurred, or that the image was blocked via Content // Security Policy, or the page is being dismissed. Trigger an // error event if the page is not being dismissed. if (!newImage && !pageIsBeingDismissed(document)) { m_failedLoadURL = attr; m_hasPendingErrorEvent = true; errorEventSender().dispatchEventSoon(*this); } else clearFailedLoadURL(); } else if (!attr.isNull()) { // Fire an error event if the url is empty. m_failedLoadURL = attr; m_hasPendingErrorEvent = true; errorEventSender().dispatchEventSoon(*this); } CachedImage* oldImage = m_image.get(); if (newImage != oldImage) { if (m_hasPendingBeforeLoadEvent) { beforeLoadEventSender().cancelEvent(*this); m_hasPendingBeforeLoadEvent = false; } if (m_hasPendingLoadEvent) { loadEventSender().cancelEvent(*this); m_hasPendingLoadEvent = false; } // Cancel error events that belong to the previous load, which is now cancelled by changing the src attribute. // If newImage is null and m_hasPendingErrorEvent is true, we know the error event has been just posted by // this load and we should not cancel the event. // FIXME: If both previous load and this one got blocked with an error, we can receive one error event instead of two. if (m_hasPendingErrorEvent && newImage) { errorEventSender().cancelEvent(*this); m_hasPendingErrorEvent = false; } m_image = newImage; m_hasPendingBeforeLoadEvent = !document.isImageDocument() && newImage; m_hasPendingLoadEvent = newImage; m_imageComplete = !newImage; if (newImage) { if (!document.isImageDocument()) { if (!document.hasListenerType(Document::BEFORELOAD_LISTENER)) dispatchPendingBeforeLoadEvent(); else beforeLoadEventSender().dispatchEventSoon(*this); } else updateRenderer(); // If newImage is cached, addClient() will result in the load event // being queued to fire. Ensure this happens after beforeload is // dispatched. newImage->addClient(this); } if (oldImage) { oldImage->removeClient(this); updateRenderer(); } } if (RenderImageResource* imageResource = renderImageResource()) imageResource->resetAnimation(); // Only consider updating the protection ref-count of the Element immediately before returning // from this function as doing so might result in the destruction of this ImageLoader. updatedHasPendingEvent(); }
void CachedResource::load(CachedResourceLoader* cachedResourceLoader, const ResourceLoaderOptions& options) { if (!cachedResourceLoader->frame()) { failBeforeStarting(); return; } FrameLoader& frameLoader = cachedResourceLoader->frame()->loader(); if (options.securityCheck() == DoSecurityCheck && (frameLoader.state() == FrameStateProvisional || !frameLoader.activeDocumentLoader() || frameLoader.activeDocumentLoader()->isStopping())) { failBeforeStarting(); return; } m_options = options; m_loading = true; #if USE(QUICK_LOOK) if (!m_resourceRequest.isNull() && m_resourceRequest.url().protocolIs(QLPreviewProtocol())) { // When QuickLook is invoked to convert a document, it returns a unique URL in the // NSURLReponse for the main document. To make safeQLURLForDocumentURLAndResourceURL() // work, we need to use the QL URL not the original URL. const URL& documentURL = cachedResourceLoader->frame() ? cachedResourceLoader->frame()->loader().documentLoader()->response().url() : cachedResourceLoader->document()->url(); m_resourceRequest.setURL(safeQLURLForDocumentURLAndResourceURL(documentURL, url())); } #endif if (!accept().isEmpty()) m_resourceRequest.setHTTPAccept(accept()); if (isCacheValidator()) { CachedResource* resourceToRevalidate = m_resourceToRevalidate; ASSERT(resourceToRevalidate->canUseCacheValidator()); ASSERT(resourceToRevalidate->isLoaded()); const String& lastModified = resourceToRevalidate->response().httpHeaderField(HTTPHeaderName::LastModified); const String& eTag = resourceToRevalidate->response().httpHeaderField(HTTPHeaderName::ETag); if (!lastModified.isEmpty() || !eTag.isEmpty()) { ASSERT(cachedResourceLoader->cachePolicy(type()) != CachePolicyReload); if (cachedResourceLoader->cachePolicy(type()) == CachePolicyRevalidate) m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0"); if (!lastModified.isEmpty()) m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified); if (!eTag.isEmpty()) m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag); } } #if ENABLE(LINK_PREFETCH) if (type() == CachedResource::LinkPrefetch || type() == CachedResource::LinkSubresource) m_resourceRequest.setHTTPHeaderField(HTTPHeaderName::Purpose, "prefetch"); #endif m_resourceRequest.setPriority(loadPriority()); if (type() != MainResource) addAdditionalRequestHeaders(cachedResourceLoader); // FIXME: It's unfortunate that the cache layer and below get to know anything about fragment identifiers. // We should look into removing the expectation of that knowledge from the platform network stacks. ResourceRequest request(m_resourceRequest); if (!m_fragmentIdentifierForRequest.isNull()) { URL url = request.url(); url.setFragmentIdentifier(m_fragmentIdentifierForRequest); request.setURL(url); m_fragmentIdentifierForRequest = String(); } m_loader = platformStrategies()->loaderStrategy()->resourceLoadScheduler()->scheduleSubresourceLoad(cachedResourceLoader->frame(), this, request, request.priority(), options); if (!m_loader) { failBeforeStarting(); return; } m_status = Pending; }