Bug 544698 part 4: Move the creation of the encoder to the nsFormSubmission ctor. Move the call to linkHandler->OnLinkClickSync to the nsHTMLFormElement. r=jst
authorJonas Sicking <jonas@sicking.cc>
Wed, 24 Feb 2010 21:58:17 -0800
changeset 38675 a3805f7d1cca7bd485a8a35798ecb56deeb784e1
parent 38674 910467d64a1a349c04c6a0afa1fede3adb604aa9
child 38676 3250b548e80df921aae22a35e97bb50aca6b8655
push id11798
push usersicking@mozilla.com
push dateThu, 25 Feb 2010 06:06:03 +0000
treeherderautoland@00bc3f167040 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs544698
milestone1.9.3a2pre
Bug 544698 part 4: Move the creation of the encoder to the nsFormSubmission ctor. Move the call to linkHandler->OnLinkClickSync to the nsHTMLFormElement. r=jst
content/html/content/public/nsIFormSubmission.h
content/html/content/src/nsFormSubmission.cpp
content/html/content/src/nsHTMLFormElement.cpp
--- a/content/html/content/public/nsIFormSubmission.h
+++ b/content/html/content/public/nsIFormSubmission.h
@@ -57,31 +57,16 @@ class nsISaveAsCharset;
  * well as the form submission name/value pairs
  */
 class nsFormSubmission {
 
 public:
   virtual ~nsFormSubmission();
 
   /**
-   * Call to perform the submission
-   *
-   * @param aActionURL the URL to submit to (may be modified with GET contents)
-   * @param aTarget the target window
-   * @param aSource the element responsible for the submission (for web shell)
-   * @param aLinkHandler the link handler to use
-   * @param aDocShell (out param) the DocShell in which the submission was
-   *        loaded
-   * @param aRequest (out param) the Request for the submission
-   */
-  nsresult SubmitTo(nsIURI* aActionURI, const nsAString& aTarget,
-                    nsIContent* aSource, nsILinkHandler* aLinkHandler,
-                    nsIDocShell** aDocShell, nsIRequest** aRequest);
-
-  /**
    * Submit a name/value pair
    *
    * @param aName the name of the parameter
    * @param aValue the value of the parameter
    */
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue) = 0;
 
@@ -90,64 +75,60 @@ public:
    *
    * @param aName the name of the parameter
    * @param aFile the file to submit
    */
   virtual nsresult AddNameFilePair(const nsAString& aName,
                                    nsIFile* aFile) = 0;
   
   /**
+   * Given a URI and the current submission, create the final URI and data
+   * stream that will be submitted.  Subclasses *must* implement this.
+   *
+   * @param aURI the URI being submitted to [INOUT]
+   * @param aPostDataStream a data stream for POST data [OUT]
+   */
+  virtual nsresult GetEncodedSubmission(nsIURI* aURI,
+                                        nsIInputStream** aPostDataStream) = 0;
+
+  /**
    * Get the charset that will be used for submission.
    */
   void GetCharset(nsACString& aCharset)
   {
     aCharset = mCharset;
   }
 
 protected:
   /**
    * Can only be constructed by subclasses.
    *
    * @param aCharset the charset of the form as a string
-   * @param aEncoder an encoder that will encode Unicode names and values into
-   *        bytes to be sent over the wire (usually a charset transformation)
    * @param aBidiOptions the BIDI options flags for the current pres context
    */
   nsFormSubmission(const nsACString& aCharset,
-                   nsISaveAsCharset* aEncoder,
                    PRInt32 aBidiOptions);
 
   /**
-   * Given a URI and the current submission, create the final URI and data
-   * stream that will be submitted.  Subclasses *must* implement this.
-   *
-   * @param aURI the URI being submitted to [INOUT]
-   * @param aPostDataStream a data stream for POST data [OUT]
-   */
-  NS_IMETHOD GetEncodedSubmission(nsIURI* aURI,
-                                  nsIInputStream** aPostDataStream) = 0;
-
-  /**
    * 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
    * @param aResult the encoded string [OUT]
    * @throws an error if UnicodeToNewBytes fails
    */
   nsresult EncodeVal(const nsAString& aStr, nsACString& aResult);
 
   /**
    * Encode a Unicode string to bytes using an encoder.  (Used by EncodeVal)
    * @param aStr the string to encode
    * @param aEncoder the encoder to encode the bytes with (cannot be null)
    * @param aOut the encoded string [OUT] 
    * @throws an error if the encoder fails
    */
-  nsresult UnicodeToNewBytes(const nsAString& aStr, nsISaveAsCharset* aEncoder,
-                             nsACString& aOut);
+  nsresult UnicodeToNewBytes(const nsAString& aStr, nsACString& aOut);
 
   // The name of the encoder charset
   nsCString mCharset;
   // The encoder that will encode Unicode names and values
   nsCOMPtr<nsISaveAsCharset> mEncoder;
   // The BIDI options flags for the current pres context
   PRInt32 mBidiOptions;
 };
--- a/content/html/content/src/nsFormSubmission.cpp
+++ b/content/html/content/src/nsFormSubmission.cpp
@@ -90,42 +90,39 @@ SendJSWarning(nsIDocument* aDocument,
 
 // --------------------------------------------------------------------------
 
 class nsFSURLEncoded : public nsFormSubmission
 {
 public:
   /**
    * @param aCharset the charset of the form as a string
-   * @param aEncoder an encoder that will encode Unicode names and values into
-   *        bytes to be sent over the wire (usually a charset transformation)
    * @param aBidiOptions the BIDI options flags for the current pres context
    * @param aMethod the method of the submit (either NS_FORM_METHOD_GET or
    *        NS_FORM_METHOD_POST).
    */
   nsFSURLEncoded(const nsACString& aCharset,
-                 nsISaveAsCharset* aEncoder,
                  PRInt32 aBidiOptions,
                  PRInt32 aMethod,
                  nsIDocument* aDocument)
-    : nsFormSubmission(aCharset, aEncoder, aBidiOptions),
+    : nsFormSubmission(aCharset, aBidiOptions),
       mMethod(aMethod),
       mDocument(aDocument),
       mWarnedFileControl(PR_FALSE)
   {
   }
 
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue);
   virtual nsresult AddNameFilePair(const nsAString& aName,
                                    nsIFile* aFile);
+  virtual nsresult GetEncodedSubmission(nsIURI* aURI,
+                                        nsIInputStream** aPostDataStream);
 
 protected:
-  NS_IMETHOD GetEncodedSubmission(nsIURI* aURI,
-                                  nsIInputStream** aPostDataStream);
 
   /**
    * URL encode a Unicode string by encoding it to bytes, converting linebreaks
    * properly, and then escaping many bytes as %xx.
    *
    * @param aStr the string to encode
    * @param aEncoded the encoded string [OUT]
    * @throws NS_ERROR_OUT_OF_MEMORY if we run out of memory
@@ -254,17 +251,17 @@ HandleMailtoSubject(nsCString& aPath) {
       return;
     aPath.AppendLiteral("subject=");
     nsCString subjectStrEscaped;
     aPath.Append(NS_EscapeURL(NS_ConvertUTF16toUTF8(subjectStr), esc_Query,
                               subjectStrEscaped));
   }
 }
 
-NS_IMETHODIMP
+nsresult
 nsFSURLEncoded::GetEncodedSubmission(nsIURI* aURI,
                                      nsIInputStream** aPostDataStream)
 {
   nsresult rv = NS_OK;
 
   *aPostDataStream = nsnull;
 
   if (mMethod == NS_FORM_METHOD_POST) {
@@ -389,32 +386,29 @@ nsFSURLEncoded::URLEncode(const nsAStrin
  * Handle multipart/form-data encoding, which does files as well as normal
  * inputs.  This always does POST.
  */
 class nsFSMultipartFormData : public nsFormSubmission
 {
 public:
   /**
    * @param aCharset the charset of the form as a string
-   * @param aEncoder an encoder that will encode Unicode names and values into
-   *        bytes to be sent over the wire (usually a charset transformation)
    * @param aBidiOptions the BIDI options flags for the current pres context
    */
   nsFSMultipartFormData(const nsACString& aCharset,
-                        nsISaveAsCharset* aEncoder,
                         PRInt32 aBidiOptions);
  
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue);
   virtual nsresult AddNameFilePair(const nsAString& aName,
                                    nsIFile* aFile);
+  virtual nsresult GetEncodedSubmission(nsIURI* aURI,
+                                        nsIInputStream** aPostDataStream);
 
 protected:
-  NS_IMETHOD GetEncodedSubmission(nsIURI* aURI,
-                                  nsIInputStream** aPostDataStream);
 
   /**
    * Roll up the data we have so far and add it to the multiplexed data stream.
    */
   nsresult AddPostDataStream();
 
 private:
   /**
@@ -437,19 +431,18 @@ private:
    * The boundary string to use after each "part" (the boundary that marks the
    * end of a value).  This is computed randomly and is different for each
    * submission.
    */
   nsCString mBoundary;
 };
 
 nsFSMultipartFormData::nsFSMultipartFormData(const nsACString& aCharset,
-                                             nsISaveAsCharset* aEncoder,
                                              PRInt32 aBidiOptions)
-    : nsFormSubmission(aCharset, aEncoder, aBidiOptions)
+    : nsFormSubmission(aCharset, aBidiOptions)
 {
   mPostDataStream =
     do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
 
   mBoundary.AssignLiteral("---------------------------");
   mBoundary.AppendInt(rand());
   mBoundary.AppendInt(rand());
   mBoundary.AppendInt(rand());
@@ -567,17 +560,17 @@ nsFSMultipartFormData::AddNameFilePair(c
   }
 
   // CRLF after file
   mPostDataChunk.AppendLiteral(CRLF);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsFSMultipartFormData::GetEncodedSubmission(nsIURI* aURI,
                                             nsIInputStream** aPostDataStream)
 {
   nsresult rv;
 
   // Finish data
   mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
                   + NS_LITERAL_CSTRING("--" CRLF);
@@ -623,30 +616,27 @@ nsFSMultipartFormData::AddPostDataStream
 }
 
 // --------------------------------------------------------------------------
 
 class nsFSTextPlain : public nsFormSubmission
 {
 public:
   nsFSTextPlain(const nsACString& aCharset,
-                nsISaveAsCharset* aEncoder,
                 PRInt32 aBidiOptions)
-    : nsFormSubmission(aCharset, aEncoder, aBidiOptions)
+    : nsFormSubmission(aCharset, aBidiOptions)
   {
   }
 
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue);
   virtual nsresult AddNameFilePair(const nsAString& aName,
                                    nsIFile* aFile);
-
-protected:
-  NS_IMETHOD GetEncodedSubmission(nsIURI* aURI,
-                                  nsIInputStream** aPostDataStream);
+  virtual nsresult GetEncodedSubmission(nsIURI* aURI,
+                                        nsIInputStream** aPostDataStream);
 
 private:
   nsString mBody;
 };
 
 nsresult
 nsFSTextPlain::AddNameValuePair(const nsAString& aName,
                                 const nsAString& aValue)
@@ -668,17 +658,17 @@ nsFSTextPlain::AddNameFilePair(const nsA
   if (aFile) {
     aFile->GetLeafName(filename);
   }
     
   AddNameValuePair(aName, filename);
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsFSTextPlain::GetEncodedSubmission(nsIURI* aURI,
                                     nsIInputStream** aPostDataStream)
 {
   nsresult rv = NS_OK;
 
   // XXX HACK We are using the standard URL mechanism to give the body to the
   // mailer instead of passing the post data stream to it, since that sounds
   // hard.
@@ -723,55 +713,57 @@ nsFSTextPlain::GetEncodedSubmission(nsIU
   }
 
   return rv;
 }
 
 // --------------------------------------------------------------------------
 
 nsFormSubmission::nsFormSubmission(const nsACString& aCharset,
-                                   nsISaveAsCharset* aEncoder,
                                    PRInt32 aBidiOptions)
   : mCharset(aCharset),
-    mEncoder(aEncoder),
     mBidiOptions(aBidiOptions)
 {
   MOZ_COUNT_CTOR(nsFormSubmission);
+
+  nsCAutoString charset(aCharset);
+  // canonical name is passed so that we just have to check against
+  // *our* canonical names listed in charsetaliases.properties
+  if (charset.EqualsLiteral("ISO-8859-1")) {
+    charset.AssignLiteral("windows-1252");
+  }
+
+  // use UTF-8 for UTF-16* and UTF-32* (per WHATWG and existing practice of
+  // MS IE/Opera). 
+  if (StringBeginsWith(charset, NS_LITERAL_CSTRING("UTF-16")) || 
+      StringBeginsWith(charset, NS_LITERAL_CSTRING("UTF-32"))) {
+    charset.AssignLiteral("UTF-8");
+  }
+
+  mEncoder = do_CreateInstance(NS_SAVEASCHARSET_CONTRACTID);
+  if (mEncoder) {
+    nsresult rv =
+      mEncoder->Init(charset.get(),
+                     (nsISaveAsCharset::attr_EntityAfterCharsetConv + 
+                      nsISaveAsCharset::attr_FallbackDecimalNCR),
+                     0);
+    if (NS_FAILED(rv)) {
+      mEncoder = nsnull;
+    }
+  }
 }
 
 nsFormSubmission::~nsFormSubmission()
 {
   MOZ_COUNT_DTOR(nsFormSubmission);
 }
 
-nsresult
-nsFormSubmission::SubmitTo(nsIURI* aActionURI, const nsAString& aTarget,
-                           nsIContent* aSource, nsILinkHandler* aLinkHandler,
-                           nsIDocShell** aDocShell, nsIRequest** aRequest)
-{
-  nsresult rv;
-
-  // Finish encoding (get post data stream and URI)
-  nsCOMPtr<nsIInputStream> postDataStream;
-  rv = GetEncodedSubmission(aActionURI, getter_AddRefs(postDataStream));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Actually submit the data
-  NS_ENSURE_ARG_POINTER(aLinkHandler);
-
-  return aLinkHandler->OnLinkClickSync(aSource, aActionURI,
-                                       PromiseFlatString(aTarget).get(),
-                                       postDataStream, nsnull,
-                                       aDocShell, aRequest);
-}
-
 // i18n helper routines
 nsresult
-nsFormSubmission::UnicodeToNewBytes(const nsAString& aStr, 
-                                    nsISaveAsCharset* aEncoder,
+nsFormSubmission::UnicodeToNewBytes(const nsAString& aStr,
                                     nsACString& aOut)
 {
   PRUint8 ctrlsModAtSubmit = GET_BIDI_OPTION_CONTROLSTEXTMODE(mBidiOptions);
   PRUint8 textDirAtSubmit = GET_BIDI_OPTION_DIRECTION(mBidiOptions);
   //ahmed 15-1
   nsAutoString newBuffer;
   //This condition handle the RTL,LTR for a logical file
   if (ctrlsModAtSubmit == IBMBIDI_CONTROLSTEXTMODE_VISUAL
@@ -815,30 +807,29 @@ nsFormSubmission::UnicodeToNewBytes(cons
   }
   else {
     newBuffer = aStr;
   }
 
   nsXPIDLCString res;
   if (!newBuffer.IsEmpty()) {
     aOut.Truncate();
-    nsresult rv = aEncoder->Convert(newBuffer.get(), getter_Copies(res));
+    nsresult rv = mEncoder->Convert(newBuffer.get(), getter_Copies(res));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   aOut = res;
   return NS_OK;
 }
 
 nsresult
 nsFormSubmission::EncodeVal(const nsAString& aStr, nsACString& aOut)
 {
-  NS_ASSERTION(mEncoder, "Encoder not available. Losing data !");
   if (mEncoder)
-    return UnicodeToNewBytes(aStr, mEncoder, aOut);
+    return UnicodeToNewBytes(aStr, aOut);
 
   // fall back to UTF-8
   CopyUTF16toUTF8(aStr, aOut);
   return NS_OK;
 }
 
 // --------------------------------------------------------------------------
 
@@ -904,52 +895,16 @@ GetSubmitCharset(nsGenericHTMLElement* a
   }
   else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
           && oCharset.Equals(NS_LITERAL_CSTRING("UTF-8"),
                              nsCaseInsensitiveCStringComparator())) {
     oCharset.AssignLiteral("IBM864");
   }
 }
 
-static nsresult
-GetEncoder(nsGenericHTMLElement* aForm,
-           const nsACString& aCharset,
-           nsISaveAsCharset** aEncoder)
-{
-  *aEncoder = nsnull;
-  nsresult rv = NS_OK;
-
-  nsCAutoString charset(aCharset);
-  // canonical name is passed so that we just have to check against
-  // *our* canonical names listed in charsetaliases.properties
-  if (charset.EqualsLiteral("ISO-8859-1")) {
-    charset.AssignLiteral("windows-1252");
-  }
-
-  // use UTF-8 for UTF-16* and UTF-32* (per WHATWG and existing practice of
-  // MS IE/Opera). 
-  if (StringBeginsWith(charset, NS_LITERAL_CSTRING("UTF-16")) || 
-      StringBeginsWith(charset, NS_LITERAL_CSTRING("UTF-32"))) {
-    charset.AssignLiteral("UTF-8");
-  }
-
-  rv = CallCreateInstance( NS_SAVEASCHARSET_CONTRACTID, aEncoder);
-  NS_ASSERTION(NS_SUCCEEDED(rv), "create nsISaveAsCharset failed");
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = (*aEncoder)->Init(charset.get(),
-                         (nsISaveAsCharset::attr_EntityAfterCharsetConv + 
-                          nsISaveAsCharset::attr_FallbackDecimalNCR),
-                         0);
-  NS_ASSERTION(NS_SUCCEEDED(rv), "initialize nsISaveAsCharset failed");
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
 static void
 GetEnumAttr(nsGenericHTMLElement* aContent,
             nsIAtom* atom, PRInt32* aValue)
 {
   const nsAttrValue* value = aContent->GetParsedAttr(atom);
   if (value && value->Type() == nsAttrValue::eEnum) {
     *aValue = value->GetEnumValue();
   }
@@ -975,36 +930,31 @@ GetSubmissionFromForm(nsGenericHTMLEleme
   // Get method (default: GET)
   PRInt32 method = NS_FORM_METHOD_GET;
   GetEnumAttr(aForm, nsGkAtoms::method, &method);
 
   // Get charset
   nsCAutoString charset;
   GetSubmitCharset(aForm, ctrlsModAtSubmit, charset);
 
-  // Get unicode encoder
-  nsCOMPtr<nsISaveAsCharset> encoder;
-  GetEncoder(aForm, charset, getter_AddRefs(encoder));
-
   // Choose encoder
   if (method == NS_FORM_METHOD_POST &&
       enctype == NS_FORM_ENCTYPE_MULTIPART) {
-    *aFormSubmission = new nsFSMultipartFormData(charset, encoder,
-                                                 bidiOptions);
+    *aFormSubmission = new nsFSMultipartFormData(charset, bidiOptions);
   } else if (method == NS_FORM_METHOD_POST &&
              enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
-    *aFormSubmission = new nsFSTextPlain(charset, encoder, bidiOptions);
+    *aFormSubmission = new nsFSTextPlain(charset, bidiOptions);
   } else {
     if (enctype == NS_FORM_ENCTYPE_MULTIPART ||
         enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
       nsAutoString enctypeStr;
       aForm->GetAttr(kNameSpaceID_None, nsGkAtoms::enctype, enctypeStr);
       const PRUnichar* enctypeStrPtr = enctypeStr.get();
       SendJSWarning(aForm->GetOwnerDoc(), "ForgotPostWarning",
                     &enctypeStrPtr, 1);
     }
-    *aFormSubmission = new nsFSURLEncoded(charset, encoder, bidiOptions,
+    *aFormSubmission = new nsFSURLEncoded(charset, bidiOptions,
                                           method, aForm->GetOwnerDoc());
   }
   NS_ENSURE_TRUE(*aFormSubmission, NS_ERROR_OUT_OF_MEMORY);
 
   return NS_OK;
 }
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -851,23 +851,29 @@ nsHTMLFormElement::SubmitSubmission(nsFo
   //
   nsCOMPtr<nsIDocShell> docShell;
 
   {
     nsAutoPopupStatePusher popupStatePusher(mSubmitPopupState);
 
     nsAutoHandlingUserInputStatePusher userInpStatePusher(mSubmitInitiatedFromUserInput, PR_FALSE);
 
-    rv = aFormSubmission->SubmitTo(actionURI, target, this, linkHandler,
-                                   getter_AddRefs(docShell),
-                                   getter_AddRefs(mSubmittingRequest));
+    nsCOMPtr<nsIInputStream> postDataStream;
+    rv = aFormSubmission->GetEncodedSubmission(actionURI,
+                                               getter_AddRefs(postDataStream));
+    NS_ENSURE_SUBMIT_SUCCESS(rv);
+
+    rv = linkHandler->OnLinkClickSync(this, actionURI,
+                                      target.get(),
+                                      postDataStream, nsnull,
+                                      getter_AddRefs(docShell),
+                                      getter_AddRefs(mSubmittingRequest));
+    NS_ENSURE_SUBMIT_SUCCESS(rv);
   }
 
-  NS_ENSURE_SUBMIT_SUCCESS(rv);
-
   // Even if the submit succeeds, it's possible for there to be no docshell
   // or request; for example, if it's to a named anchor within the same page
   // the submit will not really do anything.
   if (docShell) {
     // If the channel is pending, we have to listen for web progress.
     PRBool pending = PR_FALSE;
     mSubmittingRequest->IsPending(&pending);
     if (pending && !schemeIsJavaScript) {