Bug 544698 part 2: Reorganize nsFormSubmission.cpp to make it more readable and to avoid having to forward declare functions. No actual code changes. r=jst
authorJonas Sicking <jonas@sicking.cc>
Wed, 24 Feb 2010 21:58:17 -0800
changeset 38673 9b590d74d8a65e90bfa0df765e6ea7a021136ad5
parent 38672 38c07ace8a849caff8acf77c9d17829b8d17c319
child 38674 910467d64a1a349c04c6a0afa1fede3adb604aa9
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 2: Reorganize nsFormSubmission.cpp to make it more readable and to avoid having to forward declare functions. No actual code changes. r=jst
content/html/content/src/nsFormSubmission.cpp
--- a/content/html/content/src/nsFormSubmission.cpp
+++ b/content/html/content/src/nsFormSubmission.cpp
@@ -68,63 +68,32 @@
 #include "nsIMIMEService.h"
 #include "nsIConsoleService.h"
 #include "nsIScriptError.h"
 #include "nsIStringBundle.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIFileStreams.h"
 #include "nsBidiUtils.h"
 
-/**
- * Get the submit charset for a form (suitable to pass in to the constructor).
- * @param aForm the form in question
- * @param aCtrlsModAtSubmit BIDI controls text mode.  Unused in non-BIDI
- *        builds.
- * @param aCharset the returned charset [OUT]
- */
-static void GetSubmitCharset(nsGenericHTMLElement* aForm,
-                             PRUint8 aCtrlsModAtSubmit,
-                             nsACString& aCharset);
-/**
- * Get the encoder for a form (suitable to pass in to the constructor).
- * @param aForm the form in question
- * @param aCharset the charset of the form
- * @param aEncoder the returned encoder [OUT]
- */
-static nsresult GetEncoder(nsGenericHTMLElement* aForm,
-                           const nsACString& aCharset,
-                           nsISaveAsCharset** aEncoder);
-/**
- * Get an attribute of a form as int, provided that it is an enumerated value.
- * @param aForm the form in question
- * @param aAtom the attribute (for example, nsGkAtoms::enctype) to get
- * @param aValue the result (will not be set at all if the attribute does not
- *        exist on the form, so *make sure you provide a default value*.)
- *        [OUT]
- */
-static void GetEnumAttr(nsGenericHTMLElement* aForm,
-                        nsIAtom* aAtom, PRInt32* aValue);
-
-//
-// Static helper methods that don't really have nothing to do with nsFormSub
-//
-
-/**
- * Send a warning to the JS console
- * @param aDocument the document the warning is about
- * @param aWarningName the internationalized name of the warning within
- *        layout/html/forms/src/HtmlProperties.js
- * @param aWarningArgs an array of strings to replace %S's in the warning
- * @param aWarningArgsLen the number of strings in the array
- */
 static void
 SendJSWarning(nsIDocument* aDocument,
               const char* aWarningName,
-              const PRUnichar** aWarningArgs, PRUint32 aWarningArgsLen);
+              const PRUnichar** aWarningArgs, PRUint32 aWarningArgsLen)
+{
+  nsContentUtils::ReportToConsole(nsContentUtils::eFORMS_PROPERTIES,
+                                  aWarningName,
+                                  aWarningArgs, aWarningArgsLen,
+                                  aDocument ? aDocument->GetDocumentURI() :
+                                              nsnull,
+                                  EmptyString(), 0, 0,
+                                  nsIScriptError::warningFlag,
+                                  "HTML");
+}
 
+// --------------------------------------------------------------------------
 
 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)
@@ -139,28 +108,25 @@ public:
                  nsIDocument* aDocument)
     : nsFormSubmission(aCharset, aEncoder, aBidiOptions),
       mMethod(aMethod),
       mDocument(aDocument),
       mWarnedFileControl(PR_FALSE)
   {
   }
 
-  // nsFormSubmission
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue);
   virtual nsresult AddNameFilePair(const nsAString& aName,
                                    nsIFile* aFile);
 
 protected:
-  // nsFormSubmission
   NS_IMETHOD GetEncodedSubmission(nsIURI* aURI,
                                   nsIInputStream** aPostDataStream);
 
-  // Helpers
   /**
    * 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
    */
@@ -182,34 +148,28 @@ private:
   /** Whether or not we have warned about a file control not being submitted */
   PRBool mWarnedFileControl;
 };
 
 nsresult
 nsFSURLEncoded::AddNameValuePair(const nsAString& aName,
                                  const nsAString& aValue)
 {
-  //
   // Encode value
-  //
   nsCString convValue;
   nsresult rv = URLEncode(aValue, convValue);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  //
   // Encode name
-  //
   nsCAutoString convName;
   rv = URLEncode(aName, convName);
   NS_ENSURE_SUCCESS(rv, rv);
 
 
-  //
   // Append data to string
-  //
   if (mQueryString.IsEmpty()) {
     mQueryString += convName + NS_LITERAL_CSTRING("=") + convValue;
   } else {
     mQueryString += NS_LITERAL_CSTRING("&") + convName
                   + NS_LITERAL_CSTRING("=") + convValue;
   }
 
   return NS_OK;
@@ -353,19 +313,17 @@ nsFSURLEncoded::GetEncodedSubmission(nsI
       mimeStream->SetAddContentLength(PR_TRUE);
       mimeStream->SetData(dataStream);
 
       *aPostDataStream = mimeStream;
       NS_ADDREF(*aPostDataStream);
     }
 
   } else {
-    //
     // Get the full query string
-    //
     PRBool schemeIsJavaScript;
     rv = aURI->SchemeIs("javascript", &schemeIsJavaScript);
     NS_ENSURE_SUCCESS(rv, rv);
     if (schemeIsJavaScript) {
       return NS_OK;
     }
 
     nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
@@ -420,17 +378,17 @@ nsFSURLEncoded::URLEncode(const nsAStrin
 
   char* escapedBuf = nsEscape(encodedBuf.get(), url_XPAlphas);
   NS_ENSURE_TRUE(escapedBuf, NS_ERROR_OUT_OF_MEMORY);
   aEncoded.Adopt(escapedBuf);
 
   return NS_OK;
 }
 
-
+// --------------------------------------------------------------------------
 
 /**
  * Handle multipart/form-data encoding, which does files as well as normal
  * inputs.  This always does POST.
  */
 class nsFSMultipartFormData : public nsFormSubmission
 {
 public:
@@ -439,28 +397,25 @@ public:
    * @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);
  
-  // nsFormSubmission
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue);
   virtual nsresult AddNameFilePair(const nsAString& aName,
                                    nsIFile* aFile);
 
 protected:
-  // nsFormSubmission
   NS_IMETHOD GetEncodedSubmission(nsIURI* aURI,
                                   nsIInputStream** aPostDataStream);
 
-  // Helpers
   /**
    * Roll up the data we have so far and add it to the multiplexed data stream.
    */
   nsresult AddPostDataStream();
 
 private:
   /**
    * The post data stream as it is so far.  This is a collection of smaller
@@ -481,36 +436,30 @@ 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;
 };
 
-//
-// Constructor
-//
 nsFSMultipartFormData::nsFSMultipartFormData(const nsACString& aCharset,
                                              nsISaveAsCharset* aEncoder,
                                              PRInt32 aBidiOptions)
     : nsFormSubmission(aCharset, aEncoder, aBidiOptions)
 {
   mPostDataStream =
     do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
 
   mBoundary.AssignLiteral("---------------------------");
   mBoundary.AppendInt(rand());
   mBoundary.AppendInt(rand());
   mBoundary.AppendInt(rand());
 }
 
-//
-// nsFormSubmission
-//
 nsresult
 nsFSMultipartFormData::AddNameValuePair(const nsAString& aName,
                                         const nsAString& aValue)
 {
   nsCString valueStr;
   nsCAutoString encodedVal;
   nsresult rv = EncodeVal(aValue, encodedVal);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -519,19 +468,18 @@ nsFSMultipartFormData::AddNameValuePair(
                  ConvertLineBreaks(encodedVal.get(),
                                    nsLinebreakConverter::eLinebreakAny,
                                    nsLinebreakConverter::eLinebreakNet));
 
   nsCAutoString nameStr;
   rv = EncodeVal(aName, nameStr);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  //
   // Make MIME block for name/value pair
-  //
+
   // XXX: name parameter should be encoded per RFC 2231
   // RFC 2388 specifies that RFC 2047 be used, but I think it's not 
   // consistent with MIME standard.
   mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
                  + NS_LITERAL_CSTRING(CRLF)
                  + NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
                  + nameStr + NS_LITERAL_CSTRING("\"" CRLF CRLF)
                  + valueStr + NS_LITERAL_CSTRING(CRLF);
@@ -604,55 +552,45 @@ nsFSMultipartFormData::AddNameFilePair(c
   // consistent with the MIME standard.
   mPostDataChunk +=
          NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
        + nameStr + NS_LITERAL_CSTRING("\"; filename=\"")
        + filenameStr + NS_LITERAL_CSTRING("\"" CRLF)
        + NS_LITERAL_CSTRING("Content-Type: ") + contentType
        + NS_LITERAL_CSTRING(CRLF CRLF);
 
-  //
   // Add the file to the stream
-  //
   if (fileStream) {
     // We need to dump the data up to this point into the POST data stream here,
     // since we're about to add the file input stream
     AddPostDataStream();
 
     mPostDataStream->AppendStream(fileStream);
   }
 
-  //
   // CRLF after file
-  //
   mPostDataChunk.AppendLiteral(CRLF);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFSMultipartFormData::GetEncodedSubmission(nsIURI* aURI,
                                             nsIInputStream** aPostDataStream)
 {
   nsresult rv;
 
-  //
   // Finish data
-  //
   mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
                   + NS_LITERAL_CSTRING("--" CRLF);
 
-  //
   // Add final data input stream
-  //
   AddPostDataStream();
 
-  //
   // Make header
-  //
   nsCOMPtr<nsIMIMEInputStream> mimeStream
     = do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCAutoString boundaryHeaderValue(
     NS_LITERAL_CSTRING("multipart/form-data; boundary=") + mBoundary);
 
   mimeStream->AddHeader("Content-Type", boundaryHeaderValue.get());
@@ -679,38 +617,34 @@ nsFSMultipartFormData::AddPostDataStream
     mPostDataStream->AppendStream(postDataChunkStream);
   }
 
   mPostDataChunk.Truncate();
 
   return rv;
 }
 
+// --------------------------------------------------------------------------
 
-//
-// CLASS nsFSTextPlain
-//
 class nsFSTextPlain : public nsFormSubmission
 {
 public:
   nsFSTextPlain(const nsACString& aCharset,
                 nsISaveAsCharset* aEncoder,
                 PRInt32 aBidiOptions)
     : nsFormSubmission(aCharset, aEncoder, aBidiOptions)
   {
   }
 
-  // nsFormSubmission
   virtual nsresult AddNameValuePair(const nsAString& aName,
                                     const nsAString& aValue);
   virtual nsresult AddNameFilePair(const nsAString& aName,
                                    nsIFile* aFile);
 
 protected:
-  // nsFormSubmission
   NS_IMETHOD GetEncodedSubmission(nsIURI* aURI,
                                   nsIInputStream** aPostDataStream);
 
 private:
   nsString mBody;
 };
 
 nsresult
@@ -786,16 +720,18 @@ nsFSTextPlain::GetEncodedSubmission(nsIU
     mimeStream->SetAddContentLength(PR_TRUE);
     mimeStream->SetData(bodyStream);
     CallQueryInterface(mimeStream, aPostDataStream);
   }
 
   return rv;
 }
 
+// --------------------------------------------------------------------------
+
 nsFormSubmission::nsFormSubmission(const nsACString& aCharset,
                                    nsISaveAsCharset* aEncoder,
                                    PRInt32 aBidiOptions)
   : mCharset(aCharset),
     mEncoder(aEncoder),
     mBidiOptions(aBidiOptions)
 {
 }
@@ -810,225 +746,37 @@ nsFormSubmission::Release()
   --mRefCnt;
   NS_LOG_RELEASE(this, mRefCnt, "nsFormSubmission");
   if (mRefCnt == 0) {
     mRefCnt = 1; // stabilize
     delete this;
   }
 }
 
-static void
-SendJSWarning(nsIDocument* aDocument,
-              const char* aWarningName,
-              const PRUnichar** aWarningArgs, PRUint32 aWarningArgsLen)
-{
-  nsContentUtils::ReportToConsole(nsContentUtils::eFORMS_PROPERTIES,
-                                  aWarningName,
-                                  aWarningArgs, aWarningArgsLen,
-                                  aDocument ? aDocument->GetDocumentURI() :
-                                              nsnull,
-                                  EmptyString(), 0, 0,
-                                  nsIScriptError::warningFlag,
-                                  "HTML");
-}
-
-nsresult
-GetSubmissionFromForm(nsGenericHTMLElement* aForm,
-                      nsFormSubmission** aFormSubmission)
-{
-  //
-  // Get all the information necessary to encode the form data
-  //
-  nsIDocument* doc = aForm->GetCurrentDoc();
-  NS_ASSERTION(doc, "Should have doc if we're building submission!");
-
-  // Get BIDI options
-  PRUint8 ctrlsModAtSubmit = 0;
-  PRUint32 bidiOptions = doc->GetBidiOptions();
-  ctrlsModAtSubmit = GET_BIDI_OPTION_CONTROLSTEXTMODE(bidiOptions);
-
-  // Get encoding type (default: urlencoded)
-  PRInt32 enctype = NS_FORM_ENCTYPE_URLENCODED;
-  GetEnumAttr(aForm, nsGkAtoms::enctype, &enctype);
-
-  // 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 enctype=multipart/form-data and method=post, do multipart
-  // Else do URL encoded
-  // NOTE:
-  // The rule used to be, if enctype=multipart/form-data, do multipart
-  // Else do URL encoded
-  if (method == NS_FORM_METHOD_POST &&
-      enctype == NS_FORM_ENCTYPE_MULTIPART) {
-    *aFormSubmission = new nsFSMultipartFormData(charset, encoder,
-                                                 bidiOptions);
-  } else if (method == NS_FORM_METHOD_POST &&
-             enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
-    *aFormSubmission = new nsFSTextPlain(charset, encoder, 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,
-                                          method, aForm->GetOwnerDoc());
-  }
-  NS_ENSURE_TRUE(*aFormSubmission, NS_ERROR_OUT_OF_MEMORY);
-  NS_ADDREF(*aFormSubmission);
-
-  return NS_OK;
-}
-
 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);
 }
 
-void
-GetSubmitCharset(nsGenericHTMLElement* aForm,
-                 PRUint8 aCtrlsModAtSubmit,
-                 nsACString& oCharset)
-{
-  oCharset.AssignLiteral("UTF-8"); // default to utf-8
-
-  nsresult rv = NS_OK;
-  nsAutoString acceptCharsetValue;
-  aForm->GetAttr(kNameSpaceID_None, nsGkAtoms::acceptcharset,
-                 acceptCharsetValue);
-
-  PRInt32 charsetLen = acceptCharsetValue.Length();
-  if (charsetLen > 0) {
-    PRInt32 offset=0;
-    PRInt32 spPos=0;
-    // get charset from charsets one by one
-    nsCOMPtr<nsICharsetAlias> calias(do_GetService(NS_CHARSETALIAS_CONTRACTID, &rv));
-    if (NS_FAILED(rv)) {
-      return;
-    }
-    if (calias) {
-      do {
-        spPos = acceptCharsetValue.FindChar(PRUnichar(' '), offset);
-        PRInt32 cnt = ((-1==spPos)?(charsetLen-offset):(spPos-offset));
-        if (cnt > 0) {
-          nsAutoString uCharset;
-          acceptCharsetValue.Mid(uCharset, offset, cnt);
-
-          if (NS_SUCCEEDED(calias->
-                           GetPreferred(NS_LossyConvertUTF16toASCII(uCharset),
-                                        oCharset)))
-            return;
-        }
-        offset = spPos + 1;
-      } while (spPos != -1);
-    }
-  }
-  // if there are no accept-charset or all the charset are not supported
-  // Get the charset from document
-  nsIDocument* doc = aForm->GetDocument();
-  if (doc) {
-    oCharset = doc->GetDocumentCharacterSet();
-  }
-
-  if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
-     && oCharset.Equals(NS_LITERAL_CSTRING("windows-1256"),
-                        nsCaseInsensitiveCStringComparator())) {
-//Mohamed
-    oCharset.AssignLiteral("IBM864");
-  }
-  else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_LOGICAL
-          && oCharset.Equals(NS_LITERAL_CSTRING("IBM864"),
-                             nsCaseInsensitiveCStringComparator())) {
-    oCharset.AssignLiteral("IBM864i");
-  }
-  else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
-          && oCharset.Equals(NS_LITERAL_CSTRING("ISO-8859-6"),
-                             nsCaseInsensitiveCStringComparator())) {
-    oCharset.AssignLiteral("IBM864");
-  }
-  else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
-          && oCharset.Equals(NS_LITERAL_CSTRING("UTF-8"),
-                             nsCaseInsensitiveCStringComparator())) {
-    oCharset.AssignLiteral("IBM864");
-  }
-
-}
-
-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;
-}
-
 // i18n helper routines
 nsresult
 nsFormSubmission::UnicodeToNewBytes(const nsAString& aStr, 
                                     nsISaveAsCharset* aEncoder,
                                     nsACString& aOut)
 {
   PRUint8 ctrlsModAtSubmit = GET_BIDI_OPTION_CONTROLSTEXTMODE(mBidiOptions);
   PRUint8 textDirAtSubmit = GET_BIDI_OPTION_DIRECTION(mBidiOptions);
@@ -1084,31 +832,189 @@ nsFormSubmission::UnicodeToNewBytes(cons
     nsresult rv = aEncoder->Convert(newBuffer.get(), getter_Copies(res));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   aOut = res;
   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();
-  }
-}
-
 nsresult
 nsFormSubmission::EncodeVal(const nsAString& aStr, nsACString& aOut)
 {
   NS_ASSERTION(mEncoder, "Encoder not available. Losing data !");
   if (mEncoder)
     return UnicodeToNewBytes(aStr, mEncoder, aOut);
 
   // fall back to UTF-8
   CopyUTF16toUTF8(aStr, aOut);
   return NS_OK;
 }
+
+// --------------------------------------------------------------------------
+
+static void
+GetSubmitCharset(nsGenericHTMLElement* aForm,
+                 PRUint8 aCtrlsModAtSubmit,
+                 nsACString& oCharset)
+{
+  oCharset.AssignLiteral("UTF-8"); // default to utf-8
+
+  nsresult rv = NS_OK;
+  nsAutoString acceptCharsetValue;
+  aForm->GetAttr(kNameSpaceID_None, nsGkAtoms::acceptcharset,
+                 acceptCharsetValue);
+
+  PRInt32 charsetLen = acceptCharsetValue.Length();
+  if (charsetLen > 0) {
+    PRInt32 offset=0;
+    PRInt32 spPos=0;
+    // get charset from charsets one by one
+    nsCOMPtr<nsICharsetAlias> calias(do_GetService(NS_CHARSETALIAS_CONTRACTID, &rv));
+    if (NS_FAILED(rv)) {
+      return;
+    }
+    if (calias) {
+      do {
+        spPos = acceptCharsetValue.FindChar(PRUnichar(' '), offset);
+        PRInt32 cnt = ((-1==spPos)?(charsetLen-offset):(spPos-offset));
+        if (cnt > 0) {
+          nsAutoString uCharset;
+          acceptCharsetValue.Mid(uCharset, offset, cnt);
+
+          if (NS_SUCCEEDED(calias->
+                           GetPreferred(NS_LossyConvertUTF16toASCII(uCharset),
+                                        oCharset)))
+            return;
+        }
+        offset = spPos + 1;
+      } while (spPos != -1);
+    }
+  }
+  // if there are no accept-charset or all the charset are not supported
+  // Get the charset from document
+  nsIDocument* doc = aForm->GetDocument();
+  if (doc) {
+    oCharset = doc->GetDocumentCharacterSet();
+  }
+
+  if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
+     && oCharset.Equals(NS_LITERAL_CSTRING("windows-1256"),
+                        nsCaseInsensitiveCStringComparator())) {
+    oCharset.AssignLiteral("IBM864");
+  }
+  else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_LOGICAL
+          && oCharset.Equals(NS_LITERAL_CSTRING("IBM864"),
+                             nsCaseInsensitiveCStringComparator())) {
+    oCharset.AssignLiteral("IBM864i");
+  }
+  else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
+          && oCharset.Equals(NS_LITERAL_CSTRING("ISO-8859-6"),
+                             nsCaseInsensitiveCStringComparator())) {
+    oCharset.AssignLiteral("IBM864");
+  }
+  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();
+  }
+}
+
+nsresult
+GetSubmissionFromForm(nsGenericHTMLElement* aForm,
+                      nsFormSubmission** aFormSubmission)
+{
+  // Get all the information necessary to encode the form data
+  nsIDocument* doc = aForm->GetCurrentDoc();
+  NS_ASSERTION(doc, "Should have doc if we're building submission!");
+
+  // Get BIDI options
+  PRUint8 ctrlsModAtSubmit = 0;
+  PRUint32 bidiOptions = doc->GetBidiOptions();
+  ctrlsModAtSubmit = GET_BIDI_OPTION_CONTROLSTEXTMODE(bidiOptions);
+
+  // Get encoding type (default: urlencoded)
+  PRInt32 enctype = NS_FORM_ENCTYPE_URLENCODED;
+  GetEnumAttr(aForm, nsGkAtoms::enctype, &enctype);
+
+  // 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);
+  } else if (method == NS_FORM_METHOD_POST &&
+             enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
+    *aFormSubmission = new nsFSTextPlain(charset, encoder, 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,
+                                          method, aForm->GetOwnerDoc());
+  }
+  NS_ENSURE_TRUE(*aFormSubmission, NS_ERROR_OUT_OF_MEMORY);
+  NS_ADDREF(*aFormSubmission);
+
+  return NS_OK;
+}