Stop using CookiesStrategy
[WebKit-https.git] / Source / WebCore / loader / ImageLoader.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23 #include "ImageLoader.h"
24
25 #include "BitmapImage.h"
26 #include "CachedImage.h"
27 #include "CachedResourceLoader.h"
28 #include "CachedResourceRequest.h"
29 #include "CrossOriginAccessControl.h"
30 #include "Document.h"
31 #include "Element.h"
32 #include "Event.h"
33 #include "EventNames.h"
34 #include "EventSender.h"
35 #include "Frame.h"
36 #include "FrameLoader.h"
37 #include "HTMLNames.h"
38 #include "HTMLObjectElement.h"
39 #include "HTMLParserIdioms.h"
40 #include "InspectorInstrumentation.h"
41 #include "Page.h"
42 #include "RenderImage.h"
43 #include "RenderSVGImage.h"
44 #include <wtf/NeverDestroyed.h>
45
46 #if ENABLE(VIDEO)
47 #include "RenderVideo.h"
48 #endif
49
50 #if !ASSERT_DISABLED
51 // ImageLoader objects are allocated as members of other objects, so generic pointer check would always fail.
52 namespace WTF {
53
54 template<> struct ValueCheck<WebCore::ImageLoader*> {
55     typedef WebCore::ImageLoader* TraitType;
56     static void checkConsistency(const WebCore::ImageLoader* p)
57     {
58         if (!p)
59             return;
60         ValueCheck<WebCore::Element*>::checkConsistency(&p->element());
61     }
62 };
63
64 }
65 #endif
66
67 namespace WebCore {
68
69 static ImageEventSender& beforeLoadEventSender()
70 {
71     static NeverDestroyed<ImageEventSender> sender(eventNames().beforeloadEvent);
72     return sender;
73 }
74
75 static ImageEventSender& loadEventSender()
76 {
77     static NeverDestroyed<ImageEventSender> sender(eventNames().loadEvent);
78     return sender;
79 }
80
81 static ImageEventSender& errorEventSender()
82 {
83     static NeverDestroyed<ImageEventSender> sender(eventNames().errorEvent);
84     return sender;
85 }
86
87 static inline bool pageIsBeingDismissed(Document& document)
88 {
89     Frame* frame = document.frame();
90     return frame && frame->loader().pageDismissalEventBeingDispatched() != FrameLoader::PageDismissalType::None;
91 }
92
93 ImageLoader::ImageLoader(Element& element)
94     : m_element(element)
95     , m_image(nullptr)
96     , m_derefElementTimer(*this, &ImageLoader::timerFired)
97     , m_hasPendingBeforeLoadEvent(false)
98     , m_hasPendingLoadEvent(false)
99     , m_hasPendingErrorEvent(false)
100     , m_imageComplete(true)
101     , m_loadManually(false)
102     , m_elementIsProtected(false)
103 {
104 }
105
106 ImageLoader::~ImageLoader()
107 {
108     if (m_image)
109         m_image->removeClient(*this);
110
111     ASSERT(m_hasPendingBeforeLoadEvent || !beforeLoadEventSender().hasPendingEvents(*this));
112     if (m_hasPendingBeforeLoadEvent)
113         beforeLoadEventSender().cancelEvent(*this);
114
115     ASSERT(m_hasPendingLoadEvent || !loadEventSender().hasPendingEvents(*this));
116     if (m_hasPendingLoadEvent)
117         loadEventSender().cancelEvent(*this);
118
119     ASSERT(m_hasPendingErrorEvent || !errorEventSender().hasPendingEvents(*this));
120     if (m_hasPendingErrorEvent)
121         errorEventSender().cancelEvent(*this);
122 }
123
124 void ImageLoader::clearImage()
125 {
126     clearImageWithoutConsideringPendingLoadEvent();
127
128     // Only consider updating the protection ref-count of the Element immediately before returning
129     // from this function as doing so might result in the destruction of this ImageLoader.
130     updatedHasPendingEvent();
131 }
132
133 void ImageLoader::clearImageWithoutConsideringPendingLoadEvent()
134 {
135     ASSERT(m_failedLoadURL.isEmpty());
136     CachedImage* oldImage = m_image.get();
137     if (oldImage) {
138         m_image = nullptr;
139         if (m_hasPendingBeforeLoadEvent) {
140             beforeLoadEventSender().cancelEvent(*this);
141             m_hasPendingBeforeLoadEvent = false;
142         }
143         if (m_hasPendingLoadEvent) {
144             loadEventSender().cancelEvent(*this);
145             m_hasPendingLoadEvent = false;
146         }
147         if (m_hasPendingErrorEvent) {
148             errorEventSender().cancelEvent(*this);
149             m_hasPendingErrorEvent = false;
150         }
151         m_imageComplete = true;
152         if (oldImage)
153             oldImage->removeClient(*this);
154     }
155
156     if (RenderImageResource* imageResource = renderImageResource())
157         imageResource->resetAnimation();
158 }
159
160 void ImageLoader::updateFromElement()
161 {
162     // If we're not making renderers for the page, then don't load images. We don't want to slow
163     // down the raw HTML parsing case by loading images we don't intend to display.
164     Document& document = element().document();
165     if (!document.hasLivingRenderTree())
166         return;
167
168     AtomicString attr = element().imageSourceURL();
169
170     // Avoid loading a URL we already failed to load.
171     if (!m_failedLoadURL.isEmpty() && attr == m_failedLoadURL)
172         return;
173
174     // Do not load any image if the 'src' attribute is missing or if it is
175     // an empty string.
176     CachedResourceHandle<CachedImage> newImage = nullptr;
177     if (!attr.isNull() && !stripLeadingAndTrailingHTMLSpaces(attr).isEmpty()) {
178         ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions();
179         options.contentSecurityPolicyImposition = element().isInUserAgentShadowTree() ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck;
180         options.sameOriginDataURLFlag = SameOriginDataURLFlag::Set;
181
182         auto crossOriginAttribute = element().attributeWithoutSynchronization(HTMLNames::crossoriginAttr);
183
184         ResourceRequest resourceRequest(document.completeURL(sourceURI(attr)));
185         resourceRequest.setInspectorInitiatorNodeIdentifier(InspectorInstrumentation::identifierForNode(m_element));
186
187         auto request = createPotentialAccessControlRequest(WTFMove(resourceRequest), document, crossOriginAttribute, WTFMove(options));
188         request.setInitiator(element());
189
190         if (m_loadManually) {
191             bool autoLoadOtherImages = document.cachedResourceLoader().autoLoadImages();
192             document.cachedResourceLoader().setAutoLoadImages(false);
193             auto* page = m_element.document().page();
194             newImage = new CachedImage(WTFMove(request), page->sessionID(), &page->cookieJar());
195             newImage->setStatus(CachedResource::Pending);
196             newImage->setLoading(true);
197             newImage->setOwningCachedResourceLoader(&document.cachedResourceLoader());
198             document.cachedResourceLoader().m_documentResources.set(newImage->url(), newImage.get());
199             document.cachedResourceLoader().setAutoLoadImages(autoLoadOtherImages);
200         } else
201             newImage = document.cachedResourceLoader().requestImage(WTFMove(request)).value_or(nullptr);
202
203         // If we do not have an image here, it means that a cross-site
204         // violation occurred, or that the image was blocked via Content
205         // Security Policy, or the page is being dismissed. Trigger an
206         // error event if the page is not being dismissed.
207         if (!newImage && !pageIsBeingDismissed(document)) {
208             m_failedLoadURL = attr;
209             m_hasPendingErrorEvent = true;
210             errorEventSender().dispatchEventSoon(*this);
211         } else
212             clearFailedLoadURL();
213     } else if (!attr.isNull()) {
214         // Fire an error event if the url is empty.
215         m_failedLoadURL = attr;
216         m_hasPendingErrorEvent = true;
217         errorEventSender().dispatchEventSoon(*this);
218     }
219
220     CachedImage* oldImage = m_image.get();
221     if (newImage != oldImage) {
222         if (m_hasPendingBeforeLoadEvent) {
223             beforeLoadEventSender().cancelEvent(*this);
224             m_hasPendingBeforeLoadEvent = false;
225         }
226         if (m_hasPendingLoadEvent) {
227             loadEventSender().cancelEvent(*this);
228             m_hasPendingLoadEvent = false;
229         }
230
231         // Cancel error events that belong to the previous load, which is now cancelled by changing the src attribute.
232         // If newImage is null and m_hasPendingErrorEvent is true, we know the error event has been just posted by
233         // this load and we should not cancel the event.
234         // FIXME: If both previous load and this one got blocked with an error, we can receive one error event instead of two.
235         if (m_hasPendingErrorEvent && newImage) {
236             errorEventSender().cancelEvent(*this);
237             m_hasPendingErrorEvent = false;
238         }
239
240         m_image = newImage;
241         m_hasPendingBeforeLoadEvent = !document.isImageDocument() && newImage;
242         m_hasPendingLoadEvent = newImage;
243         m_imageComplete = !newImage;
244
245         if (newImage) {
246             if (!document.isImageDocument()) {
247                 if (!document.hasListenerType(Document::BEFORELOAD_LISTENER))
248                     dispatchPendingBeforeLoadEvent();
249                 else
250                     beforeLoadEventSender().dispatchEventSoon(*this);
251             } else
252                 updateRenderer();
253
254             // If newImage is cached, addClient() will result in the load event
255             // being queued to fire. Ensure this happens after beforeload is
256             // dispatched.
257             newImage->addClient(*this);
258         }
259         if (oldImage) {
260             oldImage->removeClient(*this);
261             updateRenderer();
262         }
263     }
264
265     if (RenderImageResource* imageResource = renderImageResource())
266         imageResource->resetAnimation();
267
268     // Only consider updating the protection ref-count of the Element immediately before returning
269     // from this function as doing so might result in the destruction of this ImageLoader.
270     updatedHasPendingEvent();
271 }
272
273 void ImageLoader::updateFromElementIgnoringPreviousError()
274 {
275     clearFailedLoadURL();
276     updateFromElement();
277 }
278
279 void ImageLoader::notifyFinished(CachedResource& resource)
280 {
281     ASSERT(m_failedLoadURL.isEmpty());
282     ASSERT_UNUSED(resource, &resource == m_image.get());
283
284     m_imageComplete = true;
285     if (!hasPendingBeforeLoadEvent())
286         updateRenderer();
287
288     if (!m_hasPendingLoadEvent)
289         return;
290
291     if (m_image->resourceError().isAccessControl()) {
292         URL imageURL = m_image->url();
293
294         clearImageWithoutConsideringPendingLoadEvent();
295
296         m_hasPendingErrorEvent = true;
297         errorEventSender().dispatchEventSoon(*this);
298
299         auto message = makeString("Cannot load image ", imageURL.string(), " due to access control checks.");
300         element().document().addConsoleMessage(MessageSource::Security, MessageLevel::Error, message);
301
302         if (hasPendingDecodePromises())
303             decodeError("Access control error.");
304         
305         ASSERT(!m_hasPendingLoadEvent);
306
307         // Only consider updating the protection ref-count of the Element immediately before returning
308         // from this function as doing so might result in the destruction of this ImageLoader.
309         updatedHasPendingEvent();
310         return;
311     }
312
313     if (m_image->wasCanceled()) {
314         if (hasPendingDecodePromises())
315             decodeError("Loading was canceled.");
316         m_hasPendingLoadEvent = false;
317         // Only consider updating the protection ref-count of the Element immediately before returning
318         // from this function as doing so might result in the destruction of this ImageLoader.
319         updatedHasPendingEvent();
320         return;
321     }
322
323     if (hasPendingDecodePromises())
324         decode();
325     loadEventSender().dispatchEventSoon(*this);
326 }
327
328 RenderImageResource* ImageLoader::renderImageResource()
329 {
330     auto* renderer = element().renderer();
331     if (!renderer)
332         return nullptr;
333
334     // We don't return style generated image because it doesn't belong to the ImageLoader.
335     // See <https://bugs.webkit.org/show_bug.cgi?id=42840>
336     if (is<RenderImage>(*renderer) && !downcast<RenderImage>(*renderer).isGeneratedContent())
337         return &downcast<RenderImage>(*renderer).imageResource();
338
339     if (is<RenderSVGImage>(*renderer))
340         return &downcast<RenderSVGImage>(*renderer).imageResource();
341
342 #if ENABLE(VIDEO)
343     if (is<RenderVideo>(*renderer))
344         return &downcast<RenderVideo>(*renderer).imageResource();
345 #endif
346
347     return nullptr;
348 }
349
350 void ImageLoader::updateRenderer()
351 {
352     RenderImageResource* imageResource = renderImageResource();
353
354     if (!imageResource)
355         return;
356
357     // Only update the renderer if it doesn't have an image or if what we have
358     // is a complete image. This prevents flickering in the case where a dynamic
359     // change is happening between two images.
360     CachedImage* cachedImage = imageResource->cachedImage();
361     if (m_image != cachedImage && (m_imageComplete || !cachedImage))
362         imageResource->setCachedImage(m_image.get());
363 }
364
365 void ImageLoader::updatedHasPendingEvent()
366 {
367     // If an Element that does image loading is removed from the DOM the load/error event for the image is still observable.
368     // As long as the ImageLoader is actively loading, the Element itself needs to be ref'ed to keep it from being
369     // destroyed by DOM manipulation or garbage collection.
370     // If such an Element wishes for the load to stop when removed from the DOM it needs to stop the ImageLoader explicitly.
371     bool wasProtected = m_elementIsProtected;
372     m_elementIsProtected = m_hasPendingLoadEvent || m_hasPendingErrorEvent;
373     if (wasProtected == m_elementIsProtected)
374         return;
375
376     if (m_elementIsProtected) {
377         if (m_derefElementTimer.isActive())
378             m_derefElementTimer.stop();
379         else
380             m_protectedElement = &element();
381     } else {
382         ASSERT(!m_derefElementTimer.isActive());
383         m_derefElementTimer.startOneShot(0_s);
384     }   
385 }
386
387 void ImageLoader::decode(Ref<DeferredPromise>&& promise)
388 {
389     m_decodingPromises.append(WTFMove(promise));
390     
391     if (!element().document().domWindow()) {
392         decodeError("Inactive document.");
393         return;
394     }
395     
396     AtomicString attr = element().imageSourceURL();
397     if (stripLeadingAndTrailingHTMLSpaces(attr).isEmpty()) {
398         decodeError("Missing source URL.");
399         return;
400     }
401     
402     if (m_imageComplete)
403         decode();
404 }
405
406 void ImageLoader::decodeError(const char* message)
407 {
408     ASSERT(hasPendingDecodePromises());
409     for (auto& promise : m_decodingPromises)
410         promise->reject(Exception { EncodingError, message });
411     m_decodingPromises.clear();
412 }
413
414 void ImageLoader::decode()
415 {
416     ASSERT(hasPendingDecodePromises());
417     
418     if (!element().document().domWindow()) {
419         decodeError("Inactive document.");
420         return;
421     }
422
423     if (!m_image || !m_image->image() || m_image->errorOccurred()) {
424         decodeError("Loading error.");
425         return;
426     }
427
428     Image* image = m_image->image();
429     if (!is<BitmapImage>(image)) {
430         decodeError("Invalid image type.");
431         return;
432     }
433
434     auto& bitmapImage = downcast<BitmapImage>(*image);
435     bitmapImage.decode([promises = WTFMove(m_decodingPromises)]() mutable {
436         for (auto& promise : promises)
437             promise->resolve();
438     });
439 }
440
441 void ImageLoader::timerFired()
442 {
443     m_protectedElement = nullptr;
444 }
445
446 void ImageLoader::dispatchPendingEvent(ImageEventSender* eventSender)
447 {
448     ASSERT(eventSender == &beforeLoadEventSender() || eventSender == &loadEventSender() || eventSender == &errorEventSender());
449     const AtomicString& eventType = eventSender->eventType();
450     if (eventType == eventNames().beforeloadEvent)
451         dispatchPendingBeforeLoadEvent();
452     if (eventType == eventNames().loadEvent)
453         dispatchPendingLoadEvent();
454     if (eventType == eventNames().errorEvent)
455         dispatchPendingErrorEvent();
456 }
457
458 void ImageLoader::dispatchPendingBeforeLoadEvent()
459 {
460     if (!m_hasPendingBeforeLoadEvent)
461         return;
462     if (!m_image)
463         return;
464     if (!element().document().hasLivingRenderTree())
465         return;
466     m_hasPendingBeforeLoadEvent = false;
467     Ref<Document> originalDocument = element().document();
468     if (element().dispatchBeforeLoadEvent(m_image->url())) {
469         bool didEventListenerDisconnectThisElement = !element().isConnected() || &element().document() != originalDocument.ptr();
470         if (didEventListenerDisconnectThisElement)
471             return;
472         
473         updateRenderer();
474         return;
475     }
476     if (m_image) {
477         m_image->removeClient(*this);
478         m_image = nullptr;
479     }
480
481     loadEventSender().cancelEvent(*this);
482     m_hasPendingLoadEvent = false;
483     
484     if (is<HTMLObjectElement>(element()))
485         downcast<HTMLObjectElement>(element()).renderFallbackContent();
486
487     // Only consider updating the protection ref-count of the Element immediately before returning
488     // from this function as doing so might result in the destruction of this ImageLoader.
489     updatedHasPendingEvent();
490 }
491
492 void ImageLoader::dispatchPendingLoadEvent()
493 {
494     if (!m_hasPendingLoadEvent)
495         return;
496     if (!m_image)
497         return;
498     m_hasPendingLoadEvent = false;
499     if (element().document().hasLivingRenderTree())
500         dispatchLoadEvent();
501
502     // Only consider updating the protection ref-count of the Element immediately before returning
503     // from this function as doing so might result in the destruction of this ImageLoader.
504     updatedHasPendingEvent();
505 }
506
507 void ImageLoader::dispatchPendingErrorEvent()
508 {
509     if (!m_hasPendingErrorEvent)
510         return;
511     m_hasPendingErrorEvent = false;
512     if (element().document().hasLivingRenderTree())
513         element().dispatchEvent(Event::create(eventNames().errorEvent, Event::CanBubble::No, Event::IsCancelable::No));
514
515     // Only consider updating the protection ref-count of the Element immediately before returning
516     // from this function as doing so might result in the destruction of this ImageLoader.
517     updatedHasPendingEvent();
518 }
519
520 void ImageLoader::dispatchPendingBeforeLoadEvents()
521 {
522     beforeLoadEventSender().dispatchPendingEvents();
523 }
524
525 void ImageLoader::dispatchPendingLoadEvents()
526 {
527     loadEventSender().dispatchPendingEvents();
528 }
529
530 void ImageLoader::dispatchPendingErrorEvents()
531 {
532     errorEventSender().dispatchPendingEvents();
533 }
534
535 void ImageLoader::elementDidMoveToNewDocument()
536 {
537     clearFailedLoadURL();
538     clearImage();
539 }
540
541 inline void ImageLoader::clearFailedLoadURL()
542 {
543     m_failedLoadURL = nullAtom();
544 }
545
546 }