Bug 1450989 - Capture the action and target as part of the form submission creation. r=bz, a=IanN CLOSED TREE DONTBUILD SEAMONKEY_2_49_ESR_RELBRANCH
authorEdgar Chen <echen@mozilla.com>
Tue, 07 Aug 2018 09:24:25 +0200
branchSEAMONKEY_2_49_ESR_RELBRANCH
changeset 357533 5205eb5a7d31cad2b623be3bbe187066384faf24
parent 357532 da9a857954e8b0229b9ec9183bc9208be5343edb
child 357534 d43a8a8d75310c964f6115a24b4d416dfaf8a19d
push id7834
push userfrgrahl@gmx.net
push dateSun, 13 Jan 2019 12:17:02 +0000
treeherdermozilla-esr52@6e4ad8a8f2e8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, IanN
bugs1450989
milestone52.9.1
Bug 1450989 - Capture the action and target as part of the form submission creation. r=bz, a=IanN CLOSED TREE DONTBUILD mozilla-esr52 SEAMONKEY_2_49_ESR_RELBRANCH
dom/base/FormData.cpp
dom/html/HTMLFormElement.cpp
dom/html/HTMLFormElement.h
dom/html/HTMLFormSubmission.cpp
dom/html/HTMLFormSubmission.h
--- a/dom/base/FormData.cpp
+++ b/dom/base/FormData.cpp
@@ -12,17 +12,17 @@
 #include "mozilla/dom/HTMLFormElement.h"
 
 #include "MultipartBlobImpl.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 FormData::FormData(nsISupports* aOwner)
-  : HTMLFormSubmission(NS_LITERAL_CSTRING("UTF-8"), nullptr)
+  : HTMLFormSubmission(nullptr, EmptyString(), NS_LITERAL_CSTRING("UTF-8"), nullptr)
   , mOwner(aOwner)
 {
 }
 
 namespace {
 
 already_AddRefed<File>
 GetOrCreateFileCalledBlob(Blob& aBlob, ErrorResult& aRv)
@@ -397,17 +397,17 @@ FormData::Constructor(const GlobalObject
 
 // -------------------------------------------------------------------------
 // nsIXHRSendable
 
 NS_IMETHODIMP
 FormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
                       nsACString& aContentType, nsACString& aCharset)
 {
-  FSMultipartFormData fs(NS_LITERAL_CSTRING("UTF-8"), nullptr);
+  FSMultipartFormData fs(nullptr, EmptyString(), NS_LITERAL_CSTRING("UTF-8"), nullptr);
 
   for (uint32_t i = 0; i < mFormData.Length(); ++i) {
     if (mFormData[i].wasNullBlob) {
       MOZ_ASSERT(mFormData[i].value.IsUSVString());
       fs.AddNameBlobOrNullPair(mFormData[i].name, nullptr);
     } else if (mFormData[i].value.IsUSVString()) {
       fs.AddNameValuePair(mFormData[i].name,
                           mFormData[i].value.GetAsUSVString());
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -192,23 +192,16 @@ HTMLFormElement::GetElements(nsIDOMHTMLC
 
 nsresult
 HTMLFormElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                          nsIAtom* aPrefix, const nsAString& aValue,
                          bool aNotify)
 {
   if ((aName == nsGkAtoms::action || aName == nsGkAtoms::target) &&
       aNameSpaceID == kNameSpaceID_None) {
-    if (mPendingSubmission) {
-      // aha, there is a pending submission that means we're in
-      // the script and we need to flush it. let's tell it
-      // that the event was ignored to force the flush.
-      // the second argument is not playing a role at all.
-      FlushPendingSubmission();
-    }
     // Don't forget we've notified the password manager already if the
     // page sets the action/target in the during submit. (bug 343182)
     bool notifiedObservers = mNotifiedObservers;
     ForgetCurrentSubmission();
     mNotifiedObservers = notifiedObservers;
   }
   return nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
                                        aNotify);
@@ -724,25 +717,17 @@ HTMLFormElement::BuildSubmission(HTMLFor
 
   return NS_OK;
 }
 
 nsresult
 HTMLFormElement::SubmitSubmission(HTMLFormSubmission* aFormSubmission)
 {
   nsresult rv;
-  nsIContent* originatingElement = aFormSubmission->GetOriginatingElement();
-
-  //
-  // Get the action and target
-  //
-  nsCOMPtr<nsIURI> actionURI;
-  rv = GetActionURL(getter_AddRefs(actionURI), originatingElement);
-  NS_ENSURE_SUBMIT_SUCCESS(rv);
-
+  nsCOMPtr<nsIURI> actionURI = aFormSubmission->GetActionURL();
   if (!actionURI) {
     mIsSubmitting = false;
     return NS_OK;
   }
 
   // If there is no link handler, then we won't actually be able to submit.
   nsIDocument* doc = GetComposedDoc();
   nsCOMPtr<nsISupports> container = doc ? doc->GetContainer() : nullptr;
@@ -764,31 +749,16 @@ HTMLFormElement::SubmitSubmission(HTMLFo
   // we're not submitting when submitting to a JS URL.  That's kinda bogus, but
   // there we are.
   bool schemeIsJavaScript = false;
   if (NS_SUCCEEDED(actionURI->SchemeIs("javascript", &schemeIsJavaScript)) &&
       schemeIsJavaScript) {
     mIsSubmitting = false;
   }
 
-  // The target is the originating element formtarget attribute if the element
-  // is a submit control and has such an attribute.
-  // Otherwise, the target is the form owner's target attribute,
-  // if it has such an attribute.
-  // Finally, if one of the child nodes of the head element is a base element
-  // with a target attribute, then the value of the target attribute of the
-  // first such base element; or, if there is no such element, the empty string.
-  nsAutoString target;
-  if (!(originatingElement && originatingElement->GetAttr(kNameSpaceID_None,
-                                                          nsGkAtoms::formtarget,
-                                                          target)) &&
-      !GetAttr(kNameSpaceID_None, nsGkAtoms::target, target)) {
-    GetBaseTarget(target);
-  }
-
   //
   // Notify observers of submit
   //
   bool cancelSubmit = false;
   if (mNotifiedObservers) {
     cancelSubmit = mNotifiedObserversResult;
   } else {
     rv = NotifySubmitObservers(actionURI, &cancelSubmit, true);
@@ -821,16 +791,18 @@ HTMLFormElement::SubmitSubmission(HTMLFo
                                        mSubmitInitiatedFromUserInput,
                                        nullptr, doc);
 
     nsCOMPtr<nsIInputStream> postDataStream;
     rv = aFormSubmission->GetEncodedSubmission(actionURI,
                                                getter_AddRefs(postDataStream));
     NS_ENSURE_SUBMIT_SUCCESS(rv);
 
+    nsAutoString target;
+    aFormSubmission->GetTarget(target);
     rv = linkHandler->OnLinkClickSync(this, actionURI,
                                       target.get(),
                                       NullString(),
                                       postDataStream, nullptr,
                                       getter_AddRefs(docShell),
                                       getter_AddRefs(mSubmittingRequest));
     NS_ENSURE_SUBMIT_SUCCESS(rv);
   }
--- a/dom/html/HTMLFormElement.h
+++ b/dom/html/HTMLFormElement.h
@@ -508,24 +508,16 @@ protected:
 
   /**
    * Find form controls in this form with the correct value in the name
    * attribute.
    */
   already_AddRefed<nsISupports> DoResolveName(const nsAString& aName, bool aFlushContent);
 
   /**
-   * Get the full URL to submit to.  Do not submit if the returned URL is null.
-   *
-   * @param aActionURL the full, unadulterated URL you'll be submitting to [OUT]
-   * @param aOriginatingElement the originating element of the form submission [IN]
-   */
-  nsresult GetActionURL(nsIURI** aActionURL, nsIContent* aOriginatingElement);
-
-  /**
    * Check the form validity following this algorithm:
    * http://www.whatwg.org/specs/web-apps/current-work/#statically-validate-the-constraints
    *
    * @param aInvalidElements [out] parameter containing the list of unhandled
    * invalid controls.
    *
    * @return Whether the form is currently valid.
    */
@@ -550,16 +542,24 @@ protected:
 public:
   /**
    * Flush a possible pending submission. If there was a scripted submission
    * triggered by a button or image, the submission was defered. This method
    * forces the pending submission to be submitted. (happens when the handler
    * returns false or there is an action/target change in the script)
    */
   void FlushPendingSubmission();
+
+  /**
+   * Get the full URL to submit to.  Do not submit if the returned URL is null.
+   *
+   * @param aActionURL the full, unadulterated URL you'll be submitting to [OUT]
+   * @param aOriginatingElement the originating element of the form submission [IN]
+   */
+  nsresult GetActionURL(nsIURI** aActionURL, nsIContent* aOriginatingElement);
 protected:
 
   //
   // Data members
   //
   /** The list of controls (form.elements as well as stuff not in elements) */
   RefPtr<HTMLFormControlsCollection> mControls;
   /** The currently selected radio button of each group */
--- a/dom/html/HTMLFormSubmission.cpp
+++ b/dom/html/HTMLFormSubmission.cpp
@@ -88,21 +88,23 @@ RetrieveDirectoryName(Directory* aDirect
 class FSURLEncoded : public EncodingFormSubmission
 {
 public:
   /**
    * @param aCharset the charset of the form as a string
    * @param aMethod the method of the submit (either NS_FORM_METHOD_GET or
    *        NS_FORM_METHOD_POST).
    */
-  FSURLEncoded(const nsACString& aCharset,
+  FSURLEncoded(nsIURI* aActionURL,
+               const nsAString& aTarget,
+               const nsACString& aCharset,
                int32_t aMethod,
                nsIDocument* aDocument,
                nsIContent* aOriginatingElement)
-    : EncodingFormSubmission(aCharset, aOriginatingElement),
+    : EncodingFormSubmission(aActionURL, aTarget, aCharset, aOriginatingElement),
       mMethod(aMethod),
       mDocument(aDocument),
       mWarnedFileControl(false)
   {
   }
 
   virtual nsresult
   AddNameValuePair(const nsAString& aName, const nsAString& aValue) override;
@@ -421,19 +423,21 @@ FSURLEncoded::URLEncode(const nsAString&
 
   return NS_OK;
 }
 
 } // anonymous namespace
 
 // --------------------------------------------------------------------------
 
-FSMultipartFormData::FSMultipartFormData(const nsACString& aCharset,
+FSMultipartFormData::FSMultipartFormData(nsIURI* aActionURL,
+                                         const nsAString& aTarget,
+                                         const nsACString& aCharset,
                                          nsIContent* aOriginatingElement)
-    : EncodingFormSubmission(aCharset, aOriginatingElement)
+    : EncodingFormSubmission(aActionURL, aTarget, aCharset, aOriginatingElement)
 {
   mPostDataStream =
     do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
   mTotalLength = 0;
 
   mBoundary.AssignLiteral("---------------------------");
   mBoundary.AppendInt(rand());
   mBoundary.AppendInt(rand());
@@ -688,18 +692,21 @@ FSMultipartFormData::AddPostDataStream()
 
 // --------------------------------------------------------------------------
 
 namespace {
 
 class FSTextPlain : public EncodingFormSubmission
 {
 public:
-  FSTextPlain(const nsACString& aCharset, nsIContent* aOriginatingElement)
-    : EncodingFormSubmission(aCharset, aOriginatingElement)
+  FSTextPlain(nsIURI* aActionURL,
+              const nsAString& aTarget,
+              const nsACString& aCharset,
+              Element* aOriginatingElement)
+    : EncodingFormSubmission(aActionURL, aTarget, aCharset, aOriginatingElement)
   {
   }
 
   virtual nsresult
   AddNameValuePair(const nsAString& aName, const nsAString& aValue) override;
 
   virtual nsresult
   AddNameBlobOrNullPair(const nsAString& aName, Blob* aBlob) override;
@@ -806,19 +813,22 @@ FSTextPlain::GetEncodedSubmission(nsIURI
 
   return rv;
 }
 
 } // anonymous namespace
 
 // --------------------------------------------------------------------------
 
-EncodingFormSubmission::EncodingFormSubmission(const nsACString& aCharset,
-                                               nsIContent* aOriginatingElement)
-  : HTMLFormSubmission(aCharset, aOriginatingElement)
+EncodingFormSubmission::EncodingFormSubmission(
+  nsIURI* aActionURL,
+  const nsAString& aTarget,
+  const nsACString& aCharset,
+  nsIContent* aOriginatingElement)
+  : HTMLFormSubmission(aActionURL, aTarget, aCharset, aOriginatingElement)
   , mEncoder(aCharset)
 {
   if (!(aCharset.EqualsLiteral("UTF-8") || aCharset.EqualsLiteral("gb18030"))) {
     NS_ConvertUTF8toUTF16 charsetUtf16(aCharset);
     const char16_t* charsetPtr = charsetUtf16.get();
     SendJSWarning(aOriginatingElement ? aOriginatingElement->GetOwnerDocument()
                                       : nullptr,
                   "CannotEncodeAllUnicode",
@@ -901,24 +911,47 @@ GetEnumAttr(nsGenericHTMLElement* aConte
   if (value && value->Type() == nsAttrValue::eEnum) {
     *aValue = value->GetEnumValue();
   }
 }
 
 } // anonymous namespace
 
 /* static */ nsresult
-HTMLFormSubmission::GetFromForm(nsGenericHTMLElement* aForm,
+HTMLFormSubmission::GetFromForm(HTMLFormElement* aForm,
                                 nsGenericHTMLElement* aOriginatingElement,
                                 HTMLFormSubmission** aFormSubmission)
 {
   // Get all the information necessary to encode the form data
   NS_ASSERTION(aForm->GetComposedDoc(),
                "Should have doc if we're building submission!");
 
+  nsresult rv;
+
+  // Get action
+  nsCOMPtr<nsIURI> actionURL;
+  rv = aForm->GetActionURL(getter_AddRefs(actionURL), aOriginatingElement);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Get target
+  // The target is the originating element formtarget attribute if the element
+  // is a submit control and has such an attribute.
+  // Otherwise, the target is the form owner's target attribute,
+  // if it has such an attribute.
+  // Finally, if one of the child nodes of the head element is a base element
+  // with a target attribute, then the value of the target attribute of the
+  // first such base element; or, if there is no such element, the empty string.
+  nsAutoString target;
+  if (!(aOriginatingElement && aOriginatingElement->GetAttr(kNameSpaceID_None,
+                                                            nsGkAtoms::formtarget,
+                                                            target)) &&
+      !aForm->GetAttr(kNameSpaceID_None, nsGkAtoms::target, target)) {
+    aForm->GetBaseTarget(target);
+  }
+
   // Get encoding type (default: urlencoded)
   int32_t enctype = NS_FORM_ENCTYPE_URLENCODED;
   if (aOriginatingElement &&
       aOriginatingElement->HasAttr(kNameSpaceID_None, nsGkAtoms::formenctype)) {
     GetEnumAttr(aOriginatingElement, nsGkAtoms::formenctype, &enctype);
   } else {
     GetEnumAttr(aForm, nsGkAtoms::enctype, &enctype);
   }
@@ -943,20 +976,20 @@ HTMLFormSubmission::GetFromForm(nsGeneri
   // MS IE/Opera).
   if (StringBeginsWith(charset, NS_LITERAL_CSTRING("UTF-16"))) {
     charset.AssignLiteral("UTF-8");
   }
 
   // Choose encoder
   if (method == NS_FORM_METHOD_POST &&
       enctype == NS_FORM_ENCTYPE_MULTIPART) {
-    *aFormSubmission = new FSMultipartFormData(charset, aOriginatingElement);
+    *aFormSubmission = new FSMultipartFormData(actionURL, target, charset, aOriginatingElement);
   } else if (method == NS_FORM_METHOD_POST &&
              enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
-    *aFormSubmission = new FSTextPlain(charset, aOriginatingElement);
+    *aFormSubmission = new FSTextPlain(actionURL, target, charset, aOriginatingElement);
   } else {
     nsIDocument* doc = aForm->OwnerDoc();
     if (enctype == NS_FORM_ENCTYPE_MULTIPART ||
         enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
       nsAutoString enctypeStr;
       if (aOriginatingElement &&
           aOriginatingElement->HasAttr(kNameSpaceID_None,
                                        nsGkAtoms::formenctype)) {
@@ -964,17 +997,16 @@ HTMLFormSubmission::GetFromForm(nsGeneri
                                      enctypeStr);
       } else {
         aForm->GetAttr(kNameSpaceID_None, nsGkAtoms::enctype, enctypeStr);
       }
       const char16_t* enctypeStrPtr = enctypeStr.get();
       SendJSWarning(doc, "ForgotPostWarning",
                     &enctypeStrPtr, 1);
     }
-    *aFormSubmission = new FSURLEncoded(charset, method, doc,
-                                        aOriginatingElement);
+    *aFormSubmission = new FSURLEncoded(actionURL, target, charset, method, doc, aOriginatingElement);
   }
 
   return NS_OK;
 }
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/html/HTMLFormSubmission.h
+++ b/dom/html/HTMLFormSubmission.h
@@ -18,16 +18,17 @@ class nsIInputStream;
 class nsGenericHTMLElement;
 class nsIMultiplexInputStream;
 
 namespace mozilla {
 namespace dom {
 
 class Blob;
 class Directory;
+class HTMLFormElement;
 
 /**
  * Class for form submissions; encompasses the function to call to submit as
  * well as the form submission name/value pairs
  */
 class HTMLFormSubmission
 {
 public:
@@ -35,17 +36,17 @@ public:
    * Get a submission object based on attributes in the form (ENCTYPE and
    * METHOD)
    *
    * @param aForm the form to get a submission object based on
    * @param aOriginatingElement the originating element (can be null)
    * @param aFormSubmission the form submission object (out param)
    */
   static nsresult
-  GetFromForm(nsGenericHTMLElement* aForm,
+  GetFromForm(HTMLFormElement* aForm,
               nsGenericHTMLElement* aOriginatingElement,
               HTMLFormSubmission** aFormSubmission);
 
   virtual ~HTMLFormSubmission()
   {
     MOZ_COUNT_DTOR(HTMLFormSubmission);
   }
 
@@ -117,42 +118,70 @@ public:
     aCharset = mCharset;
   }
 
   nsIContent* GetOriginatingElement() const
   {
     return mOriginatingElement.get();
   }
 
+  /**
+   * Get the action URI that will be used for submission.
+   */
+  nsIURI* GetActionURL() const
+  {
+    return mActionURL;
+  }
+
+  /**
+   * Get the target that will be used for submission.
+   */
+  void GetTarget(nsAString& aTarget)
+  {
+    aTarget = mTarget;
+  }
+
 protected:
   /**
    * Can only be constructed by subclasses.
    *
    * @param aCharset the charset of the form as a string
    * @param aOriginatingElement the originating element (can be null)
    */
-  HTMLFormSubmission(const nsACString& aCharset,
+  HTMLFormSubmission(nsIURI* aActionURL,
+                     const nsAString& aTarget,
+                     const nsACString& aCharset,
                      nsIContent* aOriginatingElement)
-    : mCharset(aCharset)
+    : mActionURL(aActionURL)
+    , mTarget(aTarget)
+    , mCharset(aCharset)
     , mOriginatingElement(aOriginatingElement)
   {
     MOZ_COUNT_CTOR(HTMLFormSubmission);
   }
 
+  // The action url.
+  nsCOMPtr<nsIURI> mActionURL;
+
+  // The target.
+  nsString mTarget;
+
   // The name of the encoder charset
   nsCString mCharset;
 
   // Originating element.
   nsCOMPtr<nsIContent> mOriginatingElement;
 };
 
 class EncodingFormSubmission : public HTMLFormSubmission
 {
 public:
-  EncodingFormSubmission(const nsACString& aCharset,
+  EncodingFormSubmission(nsIURI* aActionURL,
+                         const nsAString& aTarget,
+                         const nsACString& aCharset,
                          nsIContent* aOriginatingElement);
 
   virtual ~EncodingFormSubmission();
 
   /**
    * Encode a Unicode string to bytes using the encoder (or just copy the input
    * if there is no encoder).
    * @param aStr the string to encode
@@ -174,18 +203,21 @@ private:
  * inputs.  This always does POST.
  */
 class FSMultipartFormData : public EncodingFormSubmission
 {
 public:
   /**
    * @param aCharset the charset of the form as a string
    */
-  FSMultipartFormData(const nsACString& aCharset,
+  FSMultipartFormData(nsIURI* aActionURL,
+                      const nsAString& aTarget,
+                      const nsACString& aCharset,
                       nsIContent* aOriginatingElement);
+
   ~FSMultipartFormData();
  
   virtual nsresult
   AddNameValuePair(const nsAString& aName, const nsAString& aValue) override;
 
   virtual nsresult
   AddNameBlobOrNullPair(const nsAString& aName, Blob* aBlob) override;