Bug 1709577 - Fix invalid src events for images. r=edgar
☠☠ backed out by 1dee84afd395 ☠ ☠
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 07 May 2021 00:11:07 +0000
changeset 578818 0da1dba1749cffc285321331d3cbbedfa30de4f4
parent 578817 bab974107b3b417bf3dc231e8d98345fb7f5b20f
child 578819 640d8a87b172e06d4753e5e535900610d475d7c6
push id142729
push userealvarez@mozilla.com
push dateFri, 07 May 2021 00:32:56 +0000
treeherderautoland@0da1dba1749c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersedgar
bugs1709577, 1466138
milestone90.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1709577 - Fix invalid src events for images. r=edgar My previous patch still causes one WPT regression (invalid-src.html), because we stopped firing error event for src="". However that test times out because it doesn't correctly handle the invalid URI case. This patch fixes it and cleans up the code a bit. This fixes bug 1466138 too, and matches Chrome. Differential Revision: https://phabricator.services.mozilla.com/D114495
dom/base/nsImageLoadingContent.cpp
dom/base/nsImageLoadingContent.h
dom/html/HTMLImageElement.cpp
testing/web-platform/meta/html/semantics/embedded-content/the-img-element/invalid-src.html.ini
--- a/dom/base/nsImageLoadingContent.cpp
+++ b/dom/base/nsImageLoadingContent.cpp
@@ -994,19 +994,18 @@ void nsImageLoadingContent::ForceReload(
     return;
   }
 
   // We keep this flag around along with the old URI even for failed requests
   // without a live request object
   ImageLoadType loadType = (mCurrentRequestFlags & REQUEST_IS_IMAGESET)
                                ? eImageLoadType_Imageset
                                : eImageLoadType_Normal;
-  nsresult rv =
-      LoadImage(currentURI, true, aNotify, loadType,
-                nsIRequest::VALIDATE_ALWAYS | LoadFlags(), true, nullptr);
+  nsresult rv = LoadImage(currentURI, true, aNotify, loadType,
+                          nsIRequest::VALIDATE_ALWAYS | LoadFlags());
   if (NS_FAILED(rv)) {
     aError.Throw(rv);
   }
 }
 
 /*
  * Non-interface methods
  */
@@ -1017,63 +1016,55 @@ nsresult nsImageLoadingContent::LoadImag
                                           nsIPrincipal* aTriggeringPrincipal) {
   // First, get a document (needed for security checks and the like)
   Document* doc = GetOurOwnerDoc();
   if (!doc) {
     // No reason to bother, I think...
     return NS_OK;
   }
 
-  // Pending load/error events need to be canceled in some situations. This
-  // is not documented in the spec, but can cause site compat problems if not
-  // done. See bug 1309461 and https://github.com/whatwg/html/issues/1872.
-  CancelPendingEvent();
-
-  if (aNewURI.IsEmpty()) {
-    // Cancel image requests and then fire only error event per spec.
-    CancelImageRequests(aNotify);
-    // Mark error event as cancelable only for src="" case, since only this
-    // error causes site compat problem (bug 1308069) for now.
-    FireEvent(u"error"_ns, true);
-    return NS_OK;
+  // Parse the URI string to get image URI
+  nsCOMPtr<nsIURI> imageURI;
+  if (!aNewURI.IsEmpty()) {
+    Unused << StringToURI(aNewURI, doc, getter_AddRefs(imageURI));
   }
 
-  // Fire loadstart event
-  FireEvent(u"loadstart"_ns);
-
-  // Parse the URI string to get image URI
-  nsCOMPtr<nsIURI> imageURI;
-  nsresult rv = StringToURI(aNewURI, doc, getter_AddRefs(imageURI));
-  NS_ENSURE_SUCCESS(rv, rv);
-  // XXXbiesi fire onerror if that failed?
-
-  return LoadImage(imageURI, aForce, aNotify, aImageLoadType, LoadFlags(),
-                   false, doc, aTriggeringPrincipal);
+  return LoadImage(imageURI, aForce, aNotify, aImageLoadType, LoadFlags(), doc,
+                   aTriggeringPrincipal);
 }
 
 nsresult nsImageLoadingContent::LoadImage(nsIURI* aNewURI, bool aForce,
                                           bool aNotify,
                                           ImageLoadType aImageLoadType,
                                           nsLoadFlags aLoadFlags,
-                                          bool aLoadStart, Document* aDocument,
+                                          Document* aDocument,
                                           nsIPrincipal* aTriggeringPrincipal) {
   MOZ_ASSERT(!mIsStartingImageLoad, "some evil code is reentering LoadImage.");
   if (mIsStartingImageLoad) {
     return NS_OK;
   }
 
   // Pending load/error events need to be canceled in some situations. This
   // is not documented in the spec, but can cause site compat problems if not
   // done. See bug 1309461 and https://github.com/whatwg/html/issues/1872.
   CancelPendingEvent();
 
+  if (!aNewURI) {
+    // Cancel image requests and then fire only error event per spec.
+    CancelImageRequests(aNotify);
+    if (aImageLoadType == eImageLoadType_Normal) {
+      // Mark error event as cancelable only for src="" case, since only this
+      // error causes site compat problem (bug 1308069) for now.
+      FireEvent(u"error"_ns, true);
+    }
+    return NS_OK;
+  }
+
   // Fire loadstart event if required
-  if (aLoadStart) {
-    FireEvent(u"loadstart"_ns);
-  }
+  FireEvent(u"loadstart"_ns);
 
   if (!mLoadingEnabled) {
     // XXX Why fire an error here? seems like the callers to SetLoadingEnabled
     // don't want/need it.
     FireEvent(u"error"_ns);
     FireEvent(u"loadend"_ns);
     return NS_OK;
   }
--- a/dom/base/nsImageLoadingContent.h
+++ b/dom/base/nsImageLoadingContent.h
@@ -139,35 +139,33 @@ class nsImageLoadingContent : public nsI
    * URI object already available, they should use this method.
    *
    * @param aNewURI the URI to be loaded
    * @param aForce If true, make sure to load the URI.  If false, only
    *        load if the URI is different from the currently loaded URI.
    * @param aNotify If true, nsIDocumentObserver state change notifications
    *                will be sent as needed.
    * @param aImageLoadType The ImageLoadType for this request
-   * @param aLoadStart If true, dispatch "loadstart" event.
    * @param aDocument Optional parameter giving the document this node is in.
    *        This is purely a performance optimization.
    * @param aLoadFlags Optional parameter specifying load flags to use for
    *        the image load
    * @param aTriggeringPrincipal Optional parameter specifying the triggering
    *        principal to use for the image load
    */
   nsresult LoadImage(nsIURI* aNewURI, bool aForce, bool aNotify,
                      ImageLoadType aImageLoadType, nsLoadFlags aLoadFlags,
-                     bool aLoadStart = true,
                      mozilla::dom::Document* aDocument = nullptr,
                      nsIPrincipal* aTriggeringPrincipal = nullptr);
 
   nsresult LoadImage(nsIURI* aNewURI, bool aForce, bool aNotify,
                      ImageLoadType aImageLoadType,
                      nsIPrincipal* aTriggeringPrincipal) {
     return LoadImage(aNewURI, aForce, aNotify, aImageLoadType, LoadFlags(),
-                     true, nullptr, aTriggeringPrincipal);
+                     nullptr, aTriggeringPrincipal);
   }
 
   /**
    * helpers to get the document for this content (from the nodeinfo
    * and such).  Not named GetOwnerDoc/GetCurrentDoc to prevent ambiguous
    * method names in subclasses
    *
    * @return the document we belong to
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -883,31 +883,29 @@ nsresult HTMLImageElement::LoadSelectedI
     if (!sourceChanged && !aAlwaysLoad) {
       UpdateDensityOnly();
       return NS_OK;
     }
   } else if (mResponsiveSelector) {
     currentDensity = mResponsiveSelector->GetSelectedImageDensity();
   }
 
-  nsresult rv = NS_ERROR_FAILURE;
   nsCOMPtr<nsIURI> selectedSource;
   nsCOMPtr<nsIPrincipal> triggeringPrincipal;
   ImageLoadType type = eImageLoadType_Normal;
+  bool hasSrc = false;
   if (mResponsiveSelector) {
     selectedSource = mResponsiveSelector->GetSelectedImageURL();
     triggeringPrincipal =
         mResponsiveSelector->GetSelectedImageTriggeringPrincipal();
     type = eImageLoadType_Imageset;
   } else {
     nsAutoString src;
-    if (!GetAttr(nsGkAtoms::src, src) || src.IsEmpty()) {
-      CancelImageRequests(aNotify);
-      rv = NS_OK;
-    } else {
+    hasSrc = GetAttr(nsGkAtoms::src, src);
+    if (hasSrc && !src.IsEmpty()) {
       Document* doc = OwnerDoc();
       StringToURI(src, doc, getter_AddRefs(selectedSource));
       if (HaveSrcsetOrInPicture()) {
         // If we have a srcset attribute or are in a <picture> element, we
         // always use the Imageset load type, even if we parsed no valid
         // responsive sources from either, per spec.
         type = eImageLoadType_Imageset;
       }
@@ -915,28 +913,33 @@ nsresult HTMLImageElement::LoadSelectedI
     }
   }
 
   if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource)) {
     UpdateDensityOnly();
     return NS_OK;
   }
 
-  if (selectedSource) {
-    // Before we actually defer the lazy-loading
-    if (mLazyLoading) {
-      if (!nsContentUtils::IsImageAvailable(
-              this, selectedSource, triggeringPrincipal, GetCORSMode())) {
-        return NS_OK;
-      }
-      StopLazyLoading(FromIntersectionObserver::No, StartLoading::No);
+  // Before we actually defer the lazy-loading
+  if (mLazyLoading) {
+    if (!selectedSource ||
+        !nsContentUtils::IsImageAvailable(this, selectedSource,
+                                          triggeringPrincipal, GetCORSMode())) {
+      return NS_OK;
     }
+    StopLazyLoading(FromIntersectionObserver::No, StartLoading::No);
+  }
 
+  nsresult rv = NS_ERROR_FAILURE;
+
+  // src triggers an error event on invalid URI, unlike other loads.
+  if (selectedSource || hasSrc) {
     rv = LoadImage(selectedSource, aForce, aNotify, type, triggeringPrincipal);
   }
+
   mLastSelectedSource = selectedSource;
   mCurrentDensity = currentDensity;
 
   if (NS_FAILED(rv)) {
     CancelImageRequests(aNotify);
   }
   return rv;
 }
deleted file mode 100644
--- a/testing/web-platform/meta/html/semantics/embedded-content/the-img-element/invalid-src.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[invalid-src.html]
-  expected: TIMEOUT
-  [src="http://["]
-    expected: TIMEOUT
-