diff --git a/mozilla/content/html/content/public/MANIFEST b/mozilla/content/html/content/public/MANIFEST
index 5a7b36f6fec..a763d0e78cc 100644
--- a/mozilla/content/html/content/public/MANIFEST
+++ b/mozilla/content/html/content/public/MANIFEST
@@ -3,6 +3,7 @@
#
nsIForm.h
nsIFormControl.h
+nsIFormSubmission.h
nsILink.h
nsIOptionElement.h
nsIScriptElement.h
diff --git a/mozilla/content/html/content/public/Makefile.in b/mozilla/content/html/content/public/Makefile.in
index 85d271d275a..418a4eafde4 100644
--- a/mozilla/content/html/content/public/Makefile.in
+++ b/mozilla/content/html/content/public/Makefile.in
@@ -40,6 +40,7 @@ EXPORTS = \
nsIOptionElement.h \
nsITextControlElement.h \
nsIScriptElement.h \
+ nsIFormSubmission.h \
$(NULL)
include $(topsrcdir)/config/rules.mk
diff --git a/mozilla/content/html/content/public/makefile.win b/mozilla/content/html/content/public/makefile.win
index ee38ae56a8f..19c256fcd77 100644
--- a/mozilla/content/html/content/public/makefile.win
+++ b/mozilla/content/html/content/public/makefile.win
@@ -32,6 +32,7 @@ EXPORTS= \
nsIOptionElement.h \
nsIScriptElement.h \
nsITextControlElement.h \
+ nsIFormSubmission.h \
$(NULL)
MODULE=content
diff --git a/mozilla/content/html/content/public/nsIFormControl.h b/mozilla/content/html/content/public/nsIFormControl.h
index 7176bdd7cfe..c12270eaa6d 100644
--- a/mozilla/content/html/content/public/nsIFormControl.h
+++ b/mozilla/content/html/content/public/nsIFormControl.h
@@ -45,6 +45,7 @@ class nsIPresState;
class nsIContent;
class nsString;
class nsIFormProcessor;
+class nsIFormSubmission;
#define NS_FORM_BROWSE 0
#define NS_FORM_BUTTON_BUTTON 1
@@ -97,6 +98,8 @@ public:
/**
* Set the form for this form control.
* @param aForm the form
+ * @param aRemoveFromForm set false if you do not want this element removed
+ * from the form. (Used by evil DemoteForm() method.)
* @return NS_OK
*/
NS_IMETHOD SetForm(nsIDOMHTMLFormElement* aForm,
@@ -109,16 +112,21 @@ public:
*/
NS_IMETHOD GetType(PRInt32* aType) = 0;
+ /**
+ * Reset this form control
+ */
NS_IMETHOD Reset() = 0;
- NS_IMETHOD IsSuccessful(nsIContent* aSubmitElement, PRBool *_retval) = 0;
-
- NS_IMETHOD GetMaxNumValues(PRInt32 *_retval) = 0;
-
- NS_IMETHOD GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames) = 0;
+ /**
+ * Tells the form control to submit its names and values to the form
+ * submission object
+ * @param aFormSubmission the form submission to notify of names/values/files
+ * to submit
+ * @param aSubmitElement the element that was pressed to submit (possibly
+ * null)
+ */
+ NS_IMETHOD SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement) = 0;
/**
* Save to presentation state
diff --git a/mozilla/content/html/content/public/nsIFormSubmission.h b/mozilla/content/html/content/public/nsIFormSubmission.h
new file mode 100644
index 00000000000..56a5edd1455
--- /dev/null
+++ b/mozilla/content/html/content/public/nsIFormSubmission.h
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#ifndef nsIFormSubmission_h___
+#define nsIFormSubmission_h___
+
+#include "nsISupports.h"
+class nsAString;
+class nsACString;
+class nsIURI;
+class nsIInputStream;
+class nsIForm;
+class nsIPresContext;
+class nsIContent;
+class nsIFormControl;
+class nsIDOMHTMLElement;
+
+#define NS_IFORMSUBMITTER_IID \
+{ 0x7ee38e3a, 0x1dd2, 0x11b2, \
+ {0x89, 0x6f, 0xab, 0x28, 0x03, 0x96, 0x25, 0xa9} }
+
+/**
+ * Interface for form submissions; encompasses the function to call to submit as
+ * well as the form submission name/value pairs
+ */
+class nsIFormSubmission : public nsISupports
+{
+public:
+
+ NS_DEFINE_STATIC_IID_ACCESSOR(NS_IFORMSUBMITTER_IID)
+
+ /**
+ * Find out whether or not this form submission accepts files
+ *
+ * @param aAcceptsFiles the boolean output
+ */
+ NS_IMETHOD AcceptsFiles(PRBool* aAcceptsFiles) = 0;
+
+ /**
+ * 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 aPresContext the presentation context
+ */
+ NS_IMETHOD SubmitTo(nsIURI* aActionURL, const nsAString& aTarget,
+ nsIContent* aSource, nsIPresContext* aPresContext) = 0;
+
+ /**
+ * Submit a name/value pair
+ *
+ * @param aSource the control sending the parameter
+ * @param aName the name of the parameter
+ * @param aValue the value of the parameter
+ */
+ NS_IMETHOD AddNameValuePair(nsIDOMHTMLElement* aSource,
+ const nsAString& aName,
+ const nsAString& aValue) = 0;
+
+ /**
+ * Submit a name/file pair
+ *
+ * @param aSource the control sending the parameter
+ * @param aName the name of the parameter
+ * @param aFilename the name of the file (pass null to provide no name)
+ * @param aStream the stream containing the file data to be sent
+ * @param aContentType the content-type of the file data being sent
+ * @param aMoreFilesToCome true if another name/file pair with the same name
+ * will be sent soon
+ */
+ NS_IMETHOD AddNameFilePair(nsIDOMHTMLElement* aSource,
+ const nsAString& aName,
+ const nsAString& aFilename,
+ nsIInputStream* aStream,
+ const nsACString& aContentType,
+ PRBool aMoreFilesToCome) = 0;
+
+};
+
+//
+// Factory methods
+//
+
+/**
+ * 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 aPresContext the presentation context
+ * @param aFormSubmission the form submission object (out param)
+ */
+nsresult GetSubmissionFromForm(nsIForm* aForm, nsIPresContext* aPresContext,
+ nsIFormSubmission** aFormSubmission);
+
+
+#endif /* nsIFormSubmission_h___ */
diff --git a/mozilla/content/html/content/src/Makefile.in b/mozilla/content/html/content/src/Makefile.in
index 39d06e8db9a..5f8e5dee564 100644
--- a/mozilla/content/html/content/src/Makefile.in
+++ b/mozilla/content/html/content/src/Makefile.in
@@ -59,7 +59,7 @@ CPPSRCS = \
nsGenericHTMLElement.cpp \
nsGenericDOMHTMLCollection.cpp \
GenericElementCollection.cpp \
- nsFormSubmitter.cpp \
+ nsFormSubmission.cpp \
nsHTMLAnchorElement.cpp \
nsHTMLAppletElement.cpp \
nsHTMLAreaElement.cpp \
diff --git a/mozilla/content/html/content/src/makefile.win b/mozilla/content/html/content/src/makefile.win
index 30b13ae78a7..548e4ab316f 100644
--- a/mozilla/content/html/content/src/makefile.win
+++ b/mozilla/content/html/content/src/makefile.win
@@ -65,7 +65,7 @@ CPP_OBJS= \
.\$(OBJDIR)\nsGenericHTMLElement.obj \
.\$(OBJDIR)\nsGenericDOMHTMLCollection.obj \
.\$(OBJDIR)\GenericElementCollection.obj \
- .\$(OBJDIR)\nsFormSubmitter.obj \
+ .\$(OBJDIR)\nsFormSubmission.obj \
.\$(OBJDIR)\nsHTMLAnchorElement.obj \
.\$(OBJDIR)\nsHTMLAppletElement.obj \
.\$(OBJDIR)\nsHTMLAreaElement.obj \
diff --git a/mozilla/content/html/content/src/nsFormSubmission.cpp b/mozilla/content/html/content/src/nsFormSubmission.cpp
new file mode 100644
index 00000000000..a340025b210
--- /dev/null
+++ b/mozilla/content/html/content/src/nsFormSubmission.cpp
@@ -0,0 +1,1014 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * The contents of this file are subject to the Netscape Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is Mozilla Communicator client code.
+ *
+ * The Initial Developer of the Original Code is Netscape Communications
+ * Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ */
+
+#include "nsIFormSubmission.h"
+
+#include "nsIPresContext.h"
+#include "nsCOMPtr.h"
+#include "nsIForm.h"
+#include "nsILinkHandler.h"
+#include "nsIDocument.h"
+#include "nsHTMLAtoms.h"
+#include "nsIHTMLDocument.h"
+#include "nsIFormControl.h"
+#include "nsIScriptGlobalObject.h"
+#include "nsIDOMHTMLFormElement.h"
+#include "nsDOMError.h"
+#include "nsHTMLValue.h"
+#include "nsGenericElement.h"
+
+// JBK added for submit move from content frame
+#include "nsIFile.h"
+#include "nsIFileStreams.h"
+#include "nsIFileSpec.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsIFormProcessor.h"
+static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID);
+#include "nsIURI.h"
+#include "nsNetUtil.h"
+static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
+#include "nsIUnicodeEncoder.h"
+#include "nsIPref.h"
+#include "nsSpecialSystemDirectory.h"
+#include "nsLinebreakConverter.h"
+#include "nsICharsetConverterManager.h"
+static NS_DEFINE_CID(kCharsetConverterManagerCID,
+ NS_ICHARSETCONVERTERMANAGER_CID);
+#include "xp_path.h"
+#include "nsICharsetAlias.h"
+#include "nsEscape.h"
+#include "nsUnicharUtils.h"
+#include "nsIMultiplexInputStream.h"
+#include "nsIMIMEInputStream.h"
+
+//BIDI
+#ifdef IBMBIDI
+#include "nsIUBidiUtils.h"
+//static NS_DEFINE_CID(kUBidiUtilCID, NS_UNICHARBIDIUTIL_CID);
+#else
+//
+// Make BIDI stuff work when BIDI is off
+//
+#define GET_BIDI_OPTION_CONTROLSTEXTMODE(x) 0
+#define GET_BIDI_OPTION_DIRECTION(x) 0
+#endif
+//end
+
+
+//
+// CLASS nsFormSubmission
+//
+
+class nsFormSubmission : public nsIFormSubmission {
+
+public:
+
+ nsFormSubmission(const nsAString& aCharset,
+ nsIUnicodeEncoder* aEncoder,
+ nsIFormProcessor* aFormProcessor,
+ PRInt32 aBidiOptions)
+ : mCharset(aCharset),
+ mEncoder(aEncoder),
+ mFormProcessor(aFormProcessor),
+ mBidiOptions(aBidiOptions)
+ { NS_INIT_ISUPPORTS(); };
+ virtual ~nsFormSubmission() { };
+
+ NS_DECL_ISUPPORTS
+
+ //
+ // nsIFormSubmission
+ //
+ NS_IMETHOD SubmitTo(nsIURI* aActionURL, const nsAString& aTarget,
+ nsIContent* aSource, nsIPresContext* aPresContext);
+
+
+ NS_IMETHOD Init() = 0;
+
+protected:
+ // this is essentially the nsFormSubmission interface
+ NS_IMETHOD GetEncodedSubmission(nsIURI* aURL,
+ nsIInputStream** aPostDataStream) = 0;
+
+ // Helpers
+ nsString* ProcessValue(nsIDOMHTMLElement* aSource,
+ const nsAString& aName, const nsAString& aValue);
+
+ // Encoding Helpers
+ char* EncodeVal(const nsAString& aIn);
+ char* UnicodeToNewBytes(const PRUnichar* aSrc, PRUint32 aLen,
+ nsIUnicodeEncoder* aEncoder);
+
+ nsString mCharset;
+ nsCOMPtr mEncoder;
+ nsCOMPtr mFormProcessor;
+ PRInt32 mBidiOptions;
+
+public:
+ // Static helpers
+ static void GetSubmitCharset(nsIForm* form,
+ PRUint8 aCtrlsModAtSubmit,
+ nsAString& oCharset);
+ static nsresult GetEncoder(nsIForm* form,
+ nsIPresContext* aPresContext,
+ PRUint8 aCtrlsModAtSubmit,
+ const nsAString& aCharset,
+ nsIUnicodeEncoder** encoder);
+ static nsresult GetEnumAttr(nsIForm* form, nsIAtom* atom, PRInt32* aValue);
+};
+
+
+//
+// CLASS nsFSURLEncoded
+//
+class nsFSURLEncoded : public nsFormSubmission
+{
+public:
+ nsFSURLEncoded(const nsAString& aCharset,
+ nsIUnicodeEncoder* aEncoder,
+ nsIFormProcessor* aFormProcessor,
+ PRInt32 aBidiOptions,
+ PRInt32 aMethod)
+ : nsFormSubmission(aCharset, aEncoder, aFormProcessor, aBidiOptions),
+ mMethod(aMethod), mNumPairs(0)
+ { }
+ virtual ~nsFSURLEncoded() { }
+
+ NS_DECL_ISUPPORTS_INHERITED
+
+ // nsIFormSubmission
+ NS_IMETHOD AddNameValuePair(nsIDOMHTMLElement* aSource,
+ const nsAString& aName,
+ const nsAString& aValue);
+ NS_IMETHOD AddNameFilePair(nsIDOMHTMLElement* aSource,
+ const nsAString& aName,
+ const nsAString& aFilename,
+ nsIInputStream* aStream,
+ const nsACString& aContentType,
+ PRBool aMoreFilesToCome);
+
+ NS_IMETHOD Init();
+
+protected:
+ // nsFormSubmission
+ NS_IMETHOD GetEncodedSubmission(nsIURI* aURI,
+ nsIInputStream** aPostDataStream);
+ NS_IMETHOD AcceptsFiles(PRBool* aAcceptsFiles)
+ { *aAcceptsFiles = PR_FALSE; return NS_OK; }
+
+ // Helpers
+ void URLEncode(const nsAString& aString, nsCString& aEncoded);
+
+private:
+ // Method (NS_FORM_METHOD_(POST|GET))
+ PRInt32 mMethod;
+ // Number of pairs parsed so far
+ PRInt32 mNumPairs;
+
+ nsCString mQueryString;
+};
+
+NS_IMPL_RELEASE_INHERITED(nsFSURLEncoded, nsFormSubmission)
+NS_IMPL_ADDREF_INHERITED(nsFSURLEncoded, nsFormSubmission)
+NS_IMPL_QUERY_INTERFACE_INHERITED0(nsFSURLEncoded, nsFormSubmission)
+
+NS_IMETHODIMP
+nsFSURLEncoded::AddNameValuePair(nsIDOMHTMLElement* aSource,
+ const nsAString& aName,
+ const nsAString& aValue)
+{
+ //
+ // Let external code process (and possibly change) value
+ //
+ nsString* processedValue = ProcessValue(aSource, aName, aValue);
+
+ //
+ // Encode name
+ //
+ nsCString convName;
+ URLEncode(aName, convName);
+
+ //
+ // Encode value
+ //
+ nsCString convValue;
+ if (processedValue) {
+ URLEncode(*processedValue, convValue);
+ } else {
+ URLEncode(aValue, convValue);
+ }
+
+ //
+ // Append data to string
+ //
+ if (mNumPairs == 0) {
+ mQueryString += convName + NS_LITERAL_CSTRING("=") + convValue;
+ } else {
+ mQueryString += NS_LITERAL_CSTRING("&") + convName
+ + NS_LITERAL_CSTRING("=") + convValue;
+ }
+
+ delete processedValue;
+
+ mNumPairs++;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFSURLEncoded::AddNameFilePair(nsIDOMHTMLElement* aSource,
+ const nsAString& aName,
+ const nsAString& aFilename,
+ nsIInputStream* aStream,
+ const nsACString& aContentType,
+ PRBool aMoreFilesToCome)
+{
+ AddNameValuePair(aSource,aName,aFilename);
+ return NS_OK;
+}
+
+//
+// nsFormSubmission
+//
+NS_IMETHODIMP
+nsFSURLEncoded::Init()
+{
+ mNumPairs = 0;
+ mQueryString.Truncate();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFSURLEncoded::GetEncodedSubmission(nsIURI* aURI,
+ nsIInputStream** aPostDataStream)
+{
+ nsresult rv = NS_OK;
+
+ *aPostDataStream = nsnull;
+
+ if (mMethod == NS_FORM_METHOD_POST) {
+ nsCOMPtr dataStream;
+ // XXX We *really* need to either get the string to disown its data (and
+ // not destroy it), or make a string input stream that owns the CString
+ // that is passed to it. Right now this operation does a copy.
+ rv = NS_NewCStringInputStream(getter_AddRefs(dataStream), mQueryString);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr mimeStream(
+ do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+#ifdef SPECIFY_CHARSET_IN_CONTENT_TYPE
+ mimeStream->AddHeader("Content-Type",
+ PromiseFlatString(
+ "application/x-www-form-urlencoded; charset="
+ + mCharset
+ ).get());
+#else
+ mimeStream->AddHeader("Content-Type",
+ "application/x-www-form-urlencoded");
+#endif
+ 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;
+ }
+
+ nsXPIDLCString path;
+ rv = aURI->GetPath(getter_Copies(path));
+ NS_ENSURE_SUCCESS(rv, rv);
+ // Bug 42616: Trim off named anchor and save it to add later
+ PRInt32 namedAnchorPos = path.FindChar('#');
+ nsCAutoString namedAnchor;
+ if (kNotFound != namedAnchorPos) {
+ path.Right(namedAnchor, (path.Length() - namedAnchorPos));
+ path.Truncate(namedAnchorPos);
+ }
+
+ // Chop off old query string (bug 25330, 57333)
+ // Only do this for GET not POST (bug 41585)
+ PRInt32 queryStart = path.FindChar('?');
+ if (kNotFound != queryStart) {
+ path.Truncate(queryStart);
+ }
+
+ path.Append('?');
+ // Bug 42616: Add named anchor to end after query string
+ path.Append(mQueryString + namedAnchor);
+
+ aURI->SetPath(path.get());
+ }
+
+ return rv;
+}
+
+// i18n helper routines
+void
+nsFSURLEncoded::URLEncode(const nsAString& aString, nsCString& aEncoded)
+{
+ char* inBuf = EncodeVal(aString);
+
+ if (!inBuf)
+ inBuf = ToNewCString(aString);
+
+ // convert to CRLF breaks
+ char* convertedBuf = nsLinebreakConverter::ConvertLineBreaks(inBuf,
+ nsLinebreakConverter::eLinebreakAny,
+ nsLinebreakConverter::eLinebreakNet);
+ nsMemory::Free(inBuf);
+
+ char* escapedBuf = nsEscape(convertedBuf, url_XPAlphas);
+ nsMemory::Free(convertedBuf);
+
+ aEncoded.Adopt(escapedBuf);
+}
+
+
+
+//
+// CLASS nsFSMultipartFormData
+//
+class nsFSMultipartFormData : public nsFormSubmission
+{
+public:
+ nsFSMultipartFormData(const nsAString& aCharset,
+ nsIUnicodeEncoder* aEncoder,
+ nsIFormProcessor* aFormProcessor,
+ PRInt32 aBidiOptions);
+ virtual ~nsFSMultipartFormData() { }
+
+ NS_DECL_ISUPPORTS_INHERITED
+
+ // nsIFormSubmission
+ NS_IMETHOD AddNameValuePair(nsIDOMHTMLElement* aSource,
+ const nsAString& aName,
+ const nsAString& aValue);
+ NS_IMETHOD AddNameFilePair(nsIDOMHTMLElement* aSource,
+ const nsAString& aName,
+ const nsAString& aFilename,
+ nsIInputStream* aStream,
+ const nsACString& aContentType,
+ PRBool aMoreFilesToCome);
+
+ NS_IMETHOD Init();
+
+protected:
+ // nsFormSubmission
+ NS_IMETHOD GetEncodedSubmission(nsIURI* aURI,
+ nsIInputStream** aPostDataStream);
+ NS_IMETHOD AcceptsFiles(PRBool* aAcceptsFiles)
+ { *aAcceptsFiles = PR_TRUE; return NS_OK; }
+
+ // Helpers
+ nsresult AddPostDataStream();
+
+private:
+ PRBool mBackwardsCompatibleSubmit;
+
+ nsCOMPtr mPostDataStream;
+ nsCString mPostDataChunk;
+ nsCString mBoundary;
+};
+
+NS_IMPL_RELEASE_INHERITED(nsFSMultipartFormData, nsFormSubmission)
+NS_IMPL_ADDREF_INHERITED(nsFSMultipartFormData, nsFormSubmission)
+NS_IMPL_QUERY_INTERFACE_INHERITED0(nsFSMultipartFormData, nsFormSubmission)
+
+//
+// Constructor
+//
+nsFSMultipartFormData::nsFSMultipartFormData(const nsAString& aCharset,
+ nsIUnicodeEncoder* aEncoder,
+ nsIFormProcessor* aFormProcessor,
+ PRInt32 aBidiOptions)
+ : nsFormSubmission(aCharset, aEncoder, aFormProcessor, aBidiOptions)
+{
+ // XXX I can't *believe* we have a pref for this. ifdef, anyone?
+ mBackwardsCompatibleSubmit = PR_FALSE;
+ nsCOMPtr prefService(do_GetService(NS_PREF_CONTRACTID));
+ if (prefService)
+ prefService->GetBoolPref("browser.forms.submit.backwards_compatible",
+ &mBackwardsCompatibleSubmit);
+}
+
+//
+// nsIFormSubmission
+//
+NS_IMETHODIMP
+nsFSMultipartFormData::AddNameValuePair(nsIDOMHTMLElement* aSource,
+ const nsAString& aName,
+ const nsAString& aValue)
+{
+ //
+ // Let external code process (and possibly change) value
+ //
+ nsString* processedValue = ProcessValue(aSource, aName, aValue);
+
+ //
+ // Get name
+ //
+ nsCString nameStr;
+ nameStr.Adopt(EncodeVal(aName));
+
+ //
+ // Get value
+ //
+ nsCString valueStr;
+ if (processedValue) {
+ valueStr.Adopt(EncodeVal(*processedValue));
+ } else {
+ valueStr.Adopt(EncodeVal(aValue));
+ }
+
+ //
+ // Convert linebreaks in value
+ //
+ valueStr.Adopt(nsLinebreakConverter::ConvertLineBreaks(valueStr.get(),
+ nsLinebreakConverter::eLinebreakAny,
+ nsLinebreakConverter::eLinebreakNet));
+
+ //
+ // Make MIME block for name/value pair
+ //
+ 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);
+
+ delete processedValue;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFSMultipartFormData::AddNameFilePair(nsIDOMHTMLElement* aSource,
+ const nsAString& aName,
+ const nsAString& aFilename,
+ nsIInputStream* aStream,
+ const nsACString& aContentType,
+ PRBool aMoreFilesToCome)
+{
+ //
+ // Let external code process (and possibly change) value
+ //
+ nsString* processedValue = ProcessValue(aSource, aName, aFilename);
+
+ //
+ // Get name
+ //
+ nsCString nameStr;
+ nameStr.Adopt(EncodeVal(aName));
+
+ //
+ // Get filename
+ //
+ nsCString filenameStr;
+ if (processedValue) {
+ filenameStr.Adopt(EncodeVal(*processedValue));
+ } else {
+ filenameStr.Adopt(EncodeVal(aFilename));
+ }
+
+ //
+ // Convert linebreaks in filename
+ //
+ filenameStr.Adopt(nsLinebreakConverter::ConvertLineBreaks(filenameStr.get(),
+ nsLinebreakConverter::eLinebreakAny,
+ nsLinebreakConverter::eLinebreakNet));
+
+ //
+ // Make MIME block for name/value pair
+ //
+ // more appropriate than always using binary?
+ mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
+ + NS_LITERAL_CSTRING(CRLF);
+ if (!mBackwardsCompatibleSubmit) {
+ // XXX Is there any way to tell when "8bit" or "7bit" etc may be
+ mPostDataChunk +=
+ NS_LITERAL_CSTRING("Content-Transfer-Encoding: binary" CRLF);
+ }
+ mPostDataChunk +=
+ NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
+ + nameStr + NS_LITERAL_CSTRING("\"; filename=\"")
+ + filenameStr + NS_LITERAL_CSTRING("\"" CRLF)
+ + NS_LITERAL_CSTRING("Content-Type: ") + aContentType
+ + NS_LITERAL_CSTRING(CRLF CRLF);
+
+ //
+ // 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();
+
+ //
+ // Add the file to the stream
+ //
+ mPostDataStream->AppendStream(aStream);
+
+ //
+ // CRLF after file
+ //
+ mPostDataChunk += NS_LITERAL_CSTRING(CRLF);
+
+ delete processedValue;
+
+ return NS_OK;
+}
+
+//
+// nsFormSubmission
+//
+NS_IMETHODIMP
+nsFSMultipartFormData::Init()
+{
+ nsresult rv;
+
+ //
+ // Create the POST stream
+ //
+ mPostDataStream =
+ do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!mPostDataStream) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ //
+ // Build boundary
+ //
+ mBoundary = NS_LITERAL_CSTRING("---------------------------");
+ mBoundary.AppendInt(rand());
+ mBoundary.AppendInt(rand());
+ mBoundary.AppendInt(rand());
+
+ 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 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());
+ mimeStream->SetAddContentLength(PR_TRUE);
+ mimeStream->SetData(mPostDataStream);
+
+ *aPostDataStream = mimeStream;
+
+ NS_ADDREF(*aPostDataStream);
+
+ return NS_OK;
+}
+
+nsresult
+nsFSMultipartFormData::AddPostDataStream()
+{
+ nsresult rv = NS_OK;
+
+ nsCOMPtr postDataChunkStream;
+ rv = NS_NewCStringInputStream(getter_AddRefs(postDataChunkStream),
+ mPostDataChunk);
+ NS_ASSERTION(postDataChunkStream, "Could not open a stream for POST!");
+ if (postDataChunkStream) {
+ mPostDataStream->AppendStream(postDataChunkStream);
+ }
+
+ mPostDataChunk.Truncate();
+
+ return rv;
+}
+
+
+//
+// CLASS nsFormSubmission
+//
+
+//
+// nsISupports stuff
+//
+
+NS_IMPL_ADDREF(nsFormSubmission)
+NS_IMPL_RELEASE(nsFormSubmission)
+
+NS_INTERFACE_MAP_BEGIN(nsFormSubmission)
+ NS_INTERFACE_MAP_ENTRY(nsIFormSubmission)
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+
+// JBK moved from nsFormFrame - bug 34297
+// submission
+
+// static
+nsresult
+GetSubmissionFromForm(nsIForm* aForm,
+ nsIPresContext* aPresContext,
+ nsIFormSubmission** aFormSubmission)
+{
+ nsresult rv = NS_OK;
+
+ //
+ // Get all the information necessary to encode the form data
+ //
+
+ // Get BIDI options
+ PRUint32 bidiOptions = 0;
+ PRUint8 ctrlsModAtSubmit = 0;
+#ifdef IBMBIDI
+ aPresContext->GetBidi(&bidiOptions);
+ ctrlsModAtSubmit = GET_BIDI_OPTION_CONTROLSTEXTMODE(bidiOptions);
+#endif
+
+ // Get encoding type (default: urlencoded)
+ PRInt32 enctype = NS_FORM_ENCTYPE_URLENCODED;
+ nsFormSubmission::GetEnumAttr(aForm, nsHTMLAtoms::enctype, &enctype);
+
+ // Get method (default: GET)
+ PRInt32 method = NS_FORM_METHOD_GET;
+ nsFormSubmission::GetEnumAttr(aForm, nsHTMLAtoms::method, &method);
+
+ // Get charset
+ nsAutoString charset;
+ nsFormSubmission::GetSubmitCharset(aForm, ctrlsModAtSubmit, charset);
+
+ // Get unicode encoder
+ nsCOMPtr encoder;
+ nsFormSubmission::GetEncoder(aForm, aPresContext, ctrlsModAtSubmit, charset,
+ getter_AddRefs(encoder));
+
+ // Get form processor
+ nsCOMPtr formProcessor =
+ do_GetService(kFormProcessorCID, &rv);
+
+ //
+ // 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,
+ formProcessor, bidiOptions);
+ } else {
+ *aFormSubmission = new nsFSURLEncoded(charset, encoder,
+ formProcessor, bidiOptions, method);
+ }
+ NS_ENSURE_TRUE(*aFormSubmission, NS_ERROR_OUT_OF_MEMORY);
+ NS_ADDREF(*aFormSubmission);
+
+
+ // This ASSUMES that all encodings above inherit from nsFormSubmission, which
+ // they currently do. If that changes, change this too.
+ NS_STATIC_CAST(nsFormSubmission*, *aFormSubmission)->Init();
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFormSubmission::SubmitTo(nsIURI* aActionURL, const nsAString& aTarget,
+ nsIContent* aSource, nsIPresContext* aPresContext)
+{
+ nsresult rv;
+
+ //
+ // Finish encoding (get post data stream and URL)
+ //
+ nsCOMPtr postDataStream;
+ rv = GetEncodedSubmission(aActionURL, getter_AddRefs(postDataStream));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ //
+ // Actually submit the data
+ //
+ nsCOMPtr handler;
+ aPresContext->GetLinkHandler(getter_AddRefs(handler));
+ if (handler) {
+ nsXPIDLCString actionURLSpec;
+ aActionURL->GetSpec(getter_Copies(actionURLSpec));
+
+ handler->OnLinkClick(aSource, eLinkVerb_Replace,
+ NS_ConvertUTF8toUCS2(actionURLSpec).get(),
+ PromiseFlatString(aTarget).get(), postDataStream);
+ }
+
+ return rv;
+}
+
+// JBK moved from nsFormFrame - bug 34297
+// static
+void
+nsFormSubmission::GetSubmitCharset(nsIForm* form,
+ PRUint8 aCtrlsModAtSubmit,
+ nsAString& oCharset)
+{
+ oCharset = NS_LITERAL_STRING("UTF-8"); // default to utf-8
+
+ nsresult rv = NS_OK;
+ nsAutoString acceptCharsetValue;
+ nsCOMPtr formContent = do_QueryInterface(form);
+ nsHTMLValue value;
+ rv = formContent->GetHTMLAttribute(nsHTMLAtoms::acceptcharset, value);
+ if (rv == NS_CONTENT_ATTR_HAS_VALUE && value.GetUnit() == eHTMLUnit_String) {
+ value.GetStringValue(acceptCharsetValue);
+ }
+
+#ifdef DEBUG_ftang
+ printf("accept-charset = %s\n", acceptCharsetValue.ToNewUTF8String());
+#endif
+ PRInt32 charsetLen = acceptCharsetValue.Length();
+ if (charsetLen > 0) {
+ PRInt32 offset=0;
+ PRInt32 spPos=0;
+ // get charset from charsets one by one
+ nsCOMPtr calias(do_GetService(kCharsetAliasCID, &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 charset;
+ acceptCharsetValue.Mid(charset, offset, cnt);
+#ifdef DEBUG_ftang
+ printf("charset[i] = %s\n",charset.ToNewUTF8String());
+#endif
+ if (NS_SUCCEEDED(calias->GetPreferred(charset, 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
+ nsCOMPtr formElement = do_QueryInterface(form);
+ if (formElement) {
+ nsIDocument* doc = nsnull;
+ formElement->GetDocument(doc);
+ if (doc) {
+ rv = doc->GetDocumentCharacterSet(oCharset);
+ NS_RELEASE(doc);
+ }
+ }
+
+#ifdef IBMBIDI
+ if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
+ && oCharset.Equals(NS_LITERAL_STRING("windows-1256"),
+ nsCaseInsensitiveStringComparator())) {
+//Mohamed
+ oCharset = NS_LITERAL_STRING("IBM864");
+ }
+ else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_LOGICAL
+ && oCharset.Equals(NS_LITERAL_STRING("IBM864"),
+ nsCaseInsensitiveStringComparator())) {
+ oCharset = NS_LITERAL_STRING("IBM864i");
+ }
+ else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
+ && oCharset.Equals(NS_LITERAL_STRING("ISO-8859-6"),
+ nsCaseInsensitiveStringComparator())) {
+ oCharset = NS_LITERAL_STRING("IBM864");
+ }
+ else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
+ && oCharset.Equals(NS_LITERAL_STRING("UTF-8"),
+ nsCaseInsensitiveStringComparator())) {
+ oCharset = NS_LITERAL_STRING("IBM864");
+ }
+
+#endif
+}
+
+// JBK moved from nsFormFrame - bug 34297
+// static
+nsresult
+nsFormSubmission::GetEncoder(nsIForm* form,
+ nsIPresContext* aPresContext,
+ PRUint8 aCtrlsModAtSubmit,
+ const nsAString& aCharset,
+ nsIUnicodeEncoder** encoder)
+{
+ *encoder = nsnull;
+ nsresult rv = NS_OK;
+#ifdef DEBUG_ftang
+ printf("charset=%s\n", ToNewCString(charset));
+#endif
+
+ // Get Charset, get the encoder.
+ nsCOMPtr ccm(
+ do_GetService(kCharsetConverterManagerCID, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (ccm) {
+ nsString charset(aCharset);
+ if (charset.Equals(NS_LITERAL_STRING("ISO-8859-1")))
+ charset.Assign(NS_LITERAL_STRING("windows-1252"));
+ rv = ccm->GetUnicodeEncoder(&charset, encoder);
+ nsServiceManager::ReleaseService( kCharsetConverterManagerCID, ccm);
+ NS_ENSURE_SUCCESS(rv, rv);
+ // XXX Commenting this out for now since it was never called up until now
+ // and no one appears to have noticed. But it appears to be useful stuff,
+ // so it stays for the day when we realize we're doing it wrong.
+ // rv = (*encoder)->SetOutputErrorBehavior(
+ // nsIUnicodeEncoder::kOnError_Replace,
+ // nsnull,
+ // (PRUnichar)'?');
+ }
+ return NS_OK;
+}
+
+// i18n helper routines
+char*
+nsFormSubmission::UnicodeToNewBytes(const PRUnichar* aSrc, PRUint32 aLen,
+ nsIUnicodeEncoder* aEncoder)
+{
+ nsresult rv = NS_OK;
+
+#ifdef IBMBIDI
+ PRUint8 ctrlsModAtSubmit = GET_BIDI_OPTION_CONTROLSTEXTMODE(mBidiOptions);
+ PRUint8 textDirAtSubmit = GET_BIDI_OPTION_DIRECTION(mBidiOptions);
+ //ahmed 15-1
+ nsAutoString temp;
+ nsCOMPtr bidiUtils(
+ do_GetService("@mozilla.org/intl/unicharbidiutil;1", &rv));
+
+ nsAutoString newBuffer;
+ //This condition handle the RTL,LTR for a logical file
+ if (ctrlsModAtSubmit == IBMBIDI_CONTROLSTEXTMODE_VISUAL
+ && mCharset.Equals(NS_LITERAL_STRING("windows-1256"),
+ nsCaseInsensitiveStringComparator())) {
+ bidiUtils->Conv_06_FE_WithReverse(nsString(aSrc),
+ newBuffer,
+ textDirAtSubmit);
+ aSrc = (PRUnichar*)newBuffer.get();
+ aLen=newBuffer.Length();
+ }
+ else if (ctrlsModAtSubmit == IBMBIDI_CONTROLSTEXTMODE_LOGICAL
+ && mCharset.Equals(NS_LITERAL_STRING("IBM864"),
+ nsCaseInsensitiveStringComparator())) {
+ //For 864 file, When it is logical, if LTR then only convert
+ //If RTL will mak a reverse for the buffer
+ bidiUtils->Conv_FE_06(nsString(aSrc), newBuffer);
+ aSrc = (PRUnichar*)newBuffer.get();
+ temp = newBuffer;
+ aLen=newBuffer.Length();
+ if (textDirAtSubmit == 2) { //RTL
+ //Now we need to reverse the Buffer, it is by searching the buffer
+ PRUint32 loop = aLen;
+ PRUint32 z;
+ for (z=0; z<=aLen; z++) {
+ temp.SetCharAt((PRUnichar)aSrc[loop], z);
+ loop--;
+ }
+ }
+ aSrc = (PRUnichar*)temp.get();
+ }
+ else if (ctrlsModAtSubmit == IBMBIDI_CONTROLSTEXTMODE_VISUAL
+ && mCharset.Equals(NS_LITERAL_STRING("IBM864"),
+ nsCaseInsensitiveStringComparator())
+ && textDirAtSubmit == IBMBIDI_TEXTDIRECTION_RTL) {
+
+ bidiUtils->Conv_FE_06(nsString(aSrc), newBuffer);
+ aSrc = (PRUnichar*)newBuffer.get();
+ temp = newBuffer;
+ aLen=newBuffer.Length();
+ //Now we need to reverse the Buffer, it is by searching the buffer
+ PRUint32 loop = aLen;
+ PRUint32 z;
+ for (z=0; z<=aLen; z++) {
+ temp.SetCharAt((PRUnichar)aSrc[loop], z);
+ loop--;
+ }
+ aSrc = (PRUnichar*)temp.get();
+ }
+#endif
+
+ char* res = nsnull;
+ rv = aEncoder->Reset();
+ if (NS_FAILED(rv)) {
+ return nsnull;
+ }
+
+ PRInt32 maxByteLen = 0;
+ rv = aEncoder->GetMaxLength(aSrc, (PRInt32)aLen, &maxByteLen);
+ if (NS_FAILED(rv)) {
+ return nsnull;
+ }
+
+ res = new char[maxByteLen+1];
+ if (res) {
+ PRInt32 reslen = maxByteLen;
+ PRInt32 reslen2;
+ PRInt32 srclen = aLen;
+ aEncoder->Convert(aSrc, &srclen, res, &reslen);
+ reslen2 = maxByteLen - reslen;
+ aEncoder->Finish(res + reslen, &reslen2);
+ res[reslen+reslen2] = '\0';
+ }
+ return res;
+}
+
+
+// static
+nsresult
+nsFormSubmission::GetEnumAttr(nsIForm* form, nsIAtom* atom, PRInt32* aValue)
+{
+ nsCOMPtr content = do_QueryInterface(form);
+ if (content) {
+ nsHTMLValue value;
+ if (content->GetHTMLAttribute(atom, value) == NS_CONTENT_ATTR_HAS_VALUE) {
+ if (eHTMLUnit_Enumerated == value.GetUnit()) {
+ (*aValue) = value.GetIntValue();
+ }
+ }
+ }
+ return NS_OK;
+}
+
+char*
+nsFormSubmission::EncodeVal(const nsAString& aIn)
+{
+ char* retval;
+ if (mEncoder) {
+ retval = UnicodeToNewBytes(PromiseFlatString(aIn).get(), aIn.Length(),
+ mEncoder);
+ } else {
+ retval = ToNewCString(aIn);
+ }
+
+ return retval;
+}
+
+nsString*
+nsFormSubmission::ProcessValue(nsIDOMHTMLElement* aSource,
+ const nsAString& aName, const nsAString& aValue)
+{
+ nsString* retval = nsnull;
+ if (mFormProcessor) {
+ // XXX We need to change the ProcessValue interface to take nsAString
+ nsString tmpNameStr(aName);
+ retval = new nsString(aValue);
+ if (!retval) {
+ return nsnull;
+ }
+
+ nsresult rv = mFormProcessor->ProcessValue(aSource, tmpNameStr, *retval);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to Notify form process observer");
+ }
+
+ return retval;
+}
diff --git a/mozilla/content/html/content/src/nsFormSubmitter.cpp b/mozilla/content/html/content/src/nsFormSubmitter.cpp
deleted file mode 100644
index 82471dd23ff..00000000000
--- a/mozilla/content/html/content/src/nsFormSubmitter.cpp
+++ /dev/null
@@ -1,1520 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/NPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is Mozilla Communicator client code.
- *
- * The Initial Developer of the Original Code is Netscape Communications
- * Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- */
-
-#include "nsFormSubmitter.h"
-
-#include "nsIPresContext.h"
-#include "nsCOMPtr.h"
-#include "nsIForm.h"
-#include "nsILinkHandler.h"
-#include "nsIDocument.h"
-#include "nsHTMLAtoms.h"
-#include "nsIHTMLDocument.h"
-#include "nsIFormControl.h"
-#include "nsIScriptGlobalObject.h"
-#include "nsIDOMHTMLFormElement.h"
-#include "nsDOMError.h"
-#include "nsHTMLValue.h"
-#include "nsGenericElement.h"
-
-// JBK added for submit move from content frame
-#include "nsIFile.h"
-#include "nsIFileStreams.h"
-#include "nsIFileSpec.h"
-#include "nsDirectoryServiceDefs.h"
-#include "nsIFormProcessor.h"
-static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID);
-#include "nsIURI.h"
-#include "nsIScriptSecurityManager.h"
-#include "nsNetUtil.h"
-static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
-#include "nsIObserverService.h"
-#include "nsIFormSubmitObserver.h"
-#include "nsIDOMWindowInternal.h"
-#include "nsIUnicodeEncoder.h"
-#include "nsIPref.h"
-#include "nsSpecialSystemDirectory.h"
-#include "nsLinebreakConverter.h"
-#include "nsIPlatformCharset.h"
-#include "nsICharsetConverterManager.h"
-static NS_DEFINE_CID(kCharsetConverterManagerCID,
- NS_ICHARSETCONVERTERMANAGER_CID);
-#include "xp_path.h"
-#include "nsIMIMEService.h"
-#include "nsCExternalHandlerService.h"
-#include "nsICharsetAlias.h"
-#include "nsEscape.h"
-#include "nsISimpleEnumerator.h"
-#include "nsUnicharUtils.h"
-#include "nsICategoryManager.h"
-
-#include "nsIDOMNode.h"
-#include "nsRange.h"
-
-//BIDI
-#ifdef IBMBIDI
-#include "nsIUBidiUtils.h"
-//static NS_DEFINE_CID(kUBidiUtilCID, NS_UNICHARBIDIUTIL_CID);
-#endif
-//end
-#define CONTENT_DISP "Content-Disposition: form-data; name=\""
-#define FILENAME "\"; filename=\""
-#define CONTENT_TYPE "Content-Type: "
-#define CONTENT_TRANSFER "Content-Transfer-Encoding: "
-#define BINARY_CONTENT "binary"
-#define BUFSIZE 1024
-#define MULTIPART "multipart/form-data"
-#define SEP "--"
-
-/* XXX This should be punted in favor of nsAutoArrayPtr (see
- * xpcom/base/nsAutoPtr.h) once that class is made public
- */
-class
-nsStringAutoArrayPtr
-{
- public:
- nsStringAutoArrayPtr() : mPtr(0) { }
- nsStringAutoArrayPtr(nsString* aPtr) : mPtr(aPtr) {}
- ~nsStringAutoArrayPtr() { delete[] mPtr; }
-
- operator nsString*() const { return mPtr; }
- nsString* get() const { return mPtr; }
-
- private:
- nsString* mPtr;
-
-};
-
-// End added JBK
-
-// JBK moved from nsFormFrame - bug 34297
-// submission
-
-PRBool nsFormSubmitter::gFirstFormSubmitted = PR_FALSE;
-
-// static
-nsresult
-nsFormSubmitter::CompareNodes(nsIDOMNode* a, nsIDOMNode* b, PRInt32* retval)
-{
- nsresult rv;
-
- nsCOMPtr aParent;
- PRInt32 aIndex;
- rv = a->GetParentNode(getter_AddRefs(aParent));
- if (NS_FAILED(rv)) {
- return rv;
- }
- {
- // To get the index, we must turn them both into contents
- // and do IndexOf(). Ick.
- nsCOMPtr aParentContent(do_QueryInterface(aParent));
- nsCOMPtr aContent(do_QueryInterface(a));
- rv = aParentContent->IndexOf(aContent, aIndex);
- if (NS_FAILED(rv)) {
- return rv;
- }
- }
-
- nsCOMPtr bParent;
- PRInt32 bIndex;
- rv = b->GetParentNode(getter_AddRefs(bParent));
- if (NS_FAILED(rv)) {
- return rv;
- }
- {
- // To get the index, we must turn them both into contents
- // and do IndexOf(). Ick.
- nsCOMPtr bParentContent(do_QueryInterface(bParent));
- nsCOMPtr bContent(do_QueryInterface(b));
- rv = bParentContent->IndexOf(bContent, bIndex);
- if (NS_FAILED(rv)) {
- return rv;
- }
- }
-
- *retval = ComparePoints(aParent, aIndex, bParent, bIndex);
- return NS_OK;
-}
-
-// static
-nsresult
-nsFormSubmitter::OnSubmit(nsIForm* form,
- nsIPresContext* aPresContext,
- nsIContent* aSubmitElement)
-{
- PRUint8 ctrlsModAtSubmit=0;
- PRUint8 textDirAtSubmit=0;
-#ifdef IBMBIDI
-//ahmed
- PRUint32 bidiOptions;
- aPresContext->GetBidi(&bidiOptions);
- ctrlsModAtSubmit = GET_BIDI_OPTION_CONTROLSTEXTMODE(bidiOptions);
- textDirAtSubmit = GET_BIDI_OPTION_DIRECTION(bidiOptions);
-//ahmed end
-#endif
-
- // If the submitElement is input type=image, find out where in the control
- // array it should have gone so we can submit it there.
- PRInt32 submitPosition = -1;
- {
- nsCOMPtr submitControl(do_QueryInterface(aSubmitElement));
- if (submitControl) {
- PRInt32 type;
- submitControl->GetType(&type);
- if (type == NS_FORM_INPUT_IMAGE) {
- nsCOMPtr submitNode(do_QueryInterface(aSubmitElement));
- if (submitNode) {
- // Loop through the control array and see where the image should go
- PRUint32 numElements;
- PRUint32 elementX;
- form->GetElementCount(&numElements);
- for (elementX = 0; elementX < numElements; elementX++) {
- nsCOMPtr curControl;
- form->GetElementAt(elementX, getter_AddRefs(curControl));
- nsCOMPtr curNode(do_QueryInterface(curControl));
- if (curNode) {
- PRInt32 comparison;
- nsresult rv = CompareNodes(submitNode, curNode, &comparison);
- if (NS_SUCCEEDED(rv) && comparison < 0) {
- submitPosition = elementX;
- break;
- }
- }
- }
-
- // If it was larger than everything, we put it at the end
- if (submitPosition == -1) {
- submitPosition = numElements;
- }
- }
- }
- }
- }
-
- // Get a service to process the value part of the form data
- // If one doesn't exist, that fine. It's not required.
- nsresult rv = NS_OK;
- nsCOMPtr formProcessor =
- do_GetService(kFormProcessorCID, &rv);
-
- PRInt32 method, enctype;
- FullyGetMethod(form, &method);
- FullyGetEnctype(form, &enctype);
-
- PRBool isURLEncoded = (NS_FORM_ENCTYPE_MULTIPART != enctype);
-
- // for enctype=multipart/form-data, force it to be post
- // if method is "" (not specified) use "get" as default
- PRBool isPost = (NS_FORM_METHOD_POST == method) || !isURLEncoded;
-
- nsString data; // this could be more efficient, by allocating a larger buffer
- nsCOMPtr multipartDataFile;
- if (isURLEncoded) {
- rv = ProcessAsURLEncoded(form, aPresContext, formProcessor,
- isPost, data,
- aSubmitElement, submitPosition,
- ctrlsModAtSubmit, textDirAtSubmit);
- }
- else {
- rv = ProcessAsMultipart(form, aPresContext, formProcessor,
- getter_AddRefs(multipartDataFile),
- aSubmitElement, submitPosition,
- ctrlsModAtSubmit, textDirAtSubmit);
- }
-
- // Don't bother submitting form if we failed to generate a valid submission
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- // make the url string
- nsCOMPtr handler;
- if (NS_OK == aPresContext->GetLinkHandler(getter_AddRefs(handler))) {
- nsAutoString href;
- nsCOMPtr formDOMElement = do_QueryInterface(form);
- if (formDOMElement) {
- formDOMElement->GetAction(href);
- }
-
- // Get the document.
- // We'll need it now to form the URL we're submitting to.
- // We'll also need it later to get the DOM window when notifying form submit
- // observers (bug 33203)
- nsCOMPtr formElement = do_QueryInterface(form);
- if (!formElement) return NS_OK; // same as !document
- nsCOMPtr document;
- formElement->GetDocument(*getter_AddRefs(document));
- if (!document) return NS_OK; // No doc means don't submit, see Bug 28988
-
- // Resolve url to an absolute url
- nsCOMPtr docURL;
- document->GetBaseURL(*getter_AddRefs(docURL));
- NS_ASSERTION(docURL, "No Base URL found in Form Submit!\n");
- if (!docURL) return NS_OK; // No base URL -> exit early, see Bug 30721
-
- // If an action is not specified and we are inside
- // a HTML document then reload the URL. This makes us
- // compatible with 4.x browsers.
- // If we are in some other type of document such as XML or
- // XUL, do nothing. This prevents undesirable reloading of
- // a document inside XUL.
-
- if (href.IsEmpty()) {
- nsCOMPtr htmlDoc;
- if (NS_FAILED(document->QueryInterface(NS_GET_IID(nsIHTMLDocument),
- getter_AddRefs(htmlDoc)))) {
- // Must be a XML, XUL or other non-HTML document type
- // so do nothing.
- return NS_OK;
- }
-
- // Necko's MakeAbsoluteURI doesn't reuse the baseURL's rel path if it is
- // passed a zero length rel path.
- nsXPIDLCString relPath;
- docURL->GetSpec(getter_Copies(relPath));
- NS_ASSERTION(relPath, "Rel path couldn't be formed in form submit!\n");
- if (relPath) {
- href.AppendWithConversion(relPath);
-
- } else {
- rv = NS_ERROR_OUT_OF_MEMORY;
- }
- } else {
- // Get security manager, check to see if access to action URI is allowed.
- nsCOMPtr securityManager =
- do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
- nsCOMPtr actionURL;
- if (NS_FAILED(rv)) return rv;
-
- rv = NS_NewURI(getter_AddRefs(actionURL), href, docURL);
- if (NS_SUCCEEDED(rv)) {
- rv = securityManager->CheckLoadURI(docURL, actionURL,
- nsIScriptSecurityManager::STANDARD);
- if (NS_FAILED(rv)) return rv;
- }
-
- nsXPIDLCString scheme;
- PRBool isMailto = PR_FALSE;
- if (actionURL
- && NS_FAILED(rv = actionURL->SchemeIs("mailto", &isMailto)))
- return rv;
- if (isMailto) {
- PRBool enabled;
- rv = securityManager->IsCapabilityEnabled("UniversalSendMail",
- &enabled);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (!enabled) {
- // Form submit to a mailto: URI requires UniversalSendMail privilege
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- }
- }
-
- nsAutoString target;
- if (formDOMElement) {
- formDOMElement->GetTarget(target);
- }
-
- // Add the URI encoded form values to the URI
- // Get the scheme of the URI.
- nsCOMPtr actionURL;
- nsXPIDLCString scheme;
- rv = NS_NewURI(getter_AddRefs(actionURL), href, docURL);
- if (NS_SUCCEEDED(rv)) {
- rv = actionURL->GetScheme(getter_Copies(scheme));
- }
- NS_ConvertASCIItoUCS2 theScheme(scheme);
- // Append the URI encoded variable/value pairs for GET's
- if (!isPost) {
- // Not for JS URIs, see bug 26917
- if (!theScheme.EqualsIgnoreCase("javascript")) {
-
- // Bug 42616: Trim off named anchor and save it to add later
- PRInt32 namedAnchorPos = href.FindChar('#');
- nsAutoString namedAnchor;
- if (kNotFound != namedAnchorPos) {
- href.Right(namedAnchor, (href.Length() - namedAnchorPos));
- href.Truncate(namedAnchorPos);
- }
-
- // Chop off old query string (bug 25330, 57333)
- // Only do this for GET not POST (bug 41585)
- PRInt32 queryStart = href.FindChar('?');
- if (kNotFound != queryStart) {
- href.Truncate(queryStart);
- }
-
- href.Append(PRUnichar('?'));
- href.Append(data);
-
- // Bug 42616: Add named anchor to end after query string
- if (!namedAnchor.IsEmpty()) {
- href.Append(namedAnchor);
- }
- }
- }
-
- nsAutoString absURLSpec;
- rv = NS_MakeAbsoluteURI(absURLSpec, href, docURL);
- if (NS_FAILED(rv)) return rv;
-
- // If this is the first form, bring alive the first form submit
- // category observers
- if (!gFirstFormSubmitted) {
- gFirstFormSubmitted = PR_TRUE;
- NS_CreateServicesFromCategory(NS_FIRST_FORMSUBMIT_CATEGORY,
- nsnull,
- NS_FIRST_FORMSUBMIT_CATEGORY);
- }
-
- // Notify observers that the form is being submitted.
- rv = NS_OK;
- nsCOMPtr service =
- do_GetService("@mozilla.org/observer-service;1", &rv);
- if (NS_FAILED(rv)) return rv;
-
- nsCOMPtr theEnum;
- rv = service->EnumerateObservers(NS_FORMSUBMIT_SUBJECT,
- getter_AddRefs(theEnum));
- if (NS_SUCCEEDED(rv) && theEnum) {
- nsCOMPtr inst;
- // XXX What is cancelSubmit doing anyway?
- PRBool cancelSubmit = PR_FALSE;
-
- nsCOMPtr globalObject;
- document->GetScriptGlobalObject(getter_AddRefs(globalObject));
- nsCOMPtr window = do_QueryInterface(globalObject);
-
- PRBool loop = PR_TRUE;
- while (NS_SUCCEEDED(theEnum->HasMoreElements(&loop)) && loop) {
- theEnum->GetNext(getter_AddRefs(inst));
-
- nsCOMPtr formSubmitObserver(
- do_QueryInterface(inst, &rv));
- if (formSubmitObserver) {
- nsCOMPtr formElement = do_QueryInterface(form);
- if (formElement) {
- nsresult notifyStatus = formSubmitObserver->Notify(formElement,
- window,
- actionURL,
- &cancelSubmit);
- if (NS_FAILED(notifyStatus)) { // assert/warn if we get here?
- return notifyStatus;
- }
- }
- }
- if (cancelSubmit) {
- return NS_OK;
- }
- }
- }
-
- // Now pass on absolute url to the click handler
- nsCOMPtr postDataStream;
- if (isPost) {
- if (isURLEncoded) {
- nsCAutoString postBuffer;
- postBuffer.AssignWithConversion(data);
- NS_NewPostDataStream(getter_AddRefs(postDataStream), !isURLEncoded,
- postBuffer.get(), 0);
- } else {
- // Cut-and-paste of NS_NewPostDataStream
-
- nsCOMPtr serv;
-
- if (multipartDataFile) {
- serv = do_GetService(kIOServiceCID);
- }
-
- if (serv) {
- nsCOMPtr rawStream;
- NS_NewLocalFileInputStream(getter_AddRefs(rawStream),
- multipartDataFile,
- PR_RDONLY,
- 0600,
- PR_TRUE);
- if (rawStream) {
- NS_NewBufferedInputStream(getter_AddRefs(postDataStream),
- rawStream, 8192);
- }
- }
- }
- }
- if (handler) {
-#if defined(DEBUG_rods) || defined(DEBUG_pollmann)
- {
- printf("******\n");
- char * str = ToNewCString(data);
- printf("postBuffer[%s]\n", str);
- Recycle(str);
-
- str = ToNewCString(absURLSpec);
- printf("absURLSpec[%s]\n", str);
- Recycle(str);
-
- str = ToNewCString(target);
- printf("target [%s]\n", str);
- Recycle(str);
- printf("******\n");
- }
-#endif
- nsCOMPtr formElement = do_QueryInterface(form);
- handler->OnLinkClick(formElement, eLinkVerb_Replace,
- absURLSpec.get(),
- target.get(), postDataStream);
- }
-// We need to delete the data file somewhere...
-// if (!isURLEncoded) {
-// nsFileSpec mdf = nsnull;
-// rv = multipartDataFile->GetFileSpec(&mdf);
-// if (NS_SUCCEEDED(rv) && mdf) {
-// mdf.Delete(PR_FALSE);
-// }
-// }
- }
- return rv;
-}
-
-// JBK moved from nsFormFrame - bug 34297
-// Process form stuff without worrying about FILE elements
-#define CRLF "\015\012"
-// static
-nsresult
-nsFormSubmitter::ProcessAsURLEncoded(nsIForm* form,
- nsIPresContext* aPresContext,
- nsIFormProcessor* aFormProcessor,
- PRBool isPost,
- nsAString& aData,
- nsIContent* aSubmitElement,
- PRInt32 aSubmitPosition,
- PRUint8 aCtrlsModAtSubmit,
- PRUint8 aTextDirAtSubmit)
-{
- nsresult rv = NS_OK;
- nsString buf;
- PRBool firstTime = PR_TRUE;
-
- nsAutoString charset;
- GetSubmitCharset(form, charset, aPresContext, aCtrlsModAtSubmit);
-
- nsCOMPtr encoder;
- GetEncoder(form, aPresContext, getter_AddRefs(encoder),
- aCtrlsModAtSubmit, charset);
- // Non-fatal error if fail, so encoder could be NULL
-
- // collect and encode the data from the children controls
- // JBK walk the elements[] array instead of form frame controls - bug 34297
- PRUint32 numElements;
- PRUint32 elementX;
- form->GetElementCount(&numElements);
- PRBool mustSubmitElement = (aSubmitPosition > -1);
- for (elementX = 0; elementX < numElements || mustSubmitElement; elementX++) {
- nsCOMPtr controlNode;
- if ((aSubmitPosition == (PRInt32)elementX || elementX >= numElements)
- && mustSubmitElement) {
- controlNode = do_QueryInterface(aSubmitElement);
- elementX--;
- mustSubmitElement = PR_FALSE;
- } else {
- form->GetElementAt(elementX, getter_AddRefs(controlNode));
- }
-
- if (controlNode) {
- PRBool successful;
- rv = controlNode->IsSuccessful(aSubmitElement, &successful);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (successful) {
- PRInt32 numValues = 0;
- PRInt32 maxNumValues;
- controlNode->GetMaxNumValues(&maxNumValues);
- if (0 >= maxNumValues) {
- continue;
- }
- nsString* names = new nsString[maxNumValues];
- // XXX use nsAutoArrayPtr instead when that becomes public
- nsStringAutoArrayPtr tmpNames(names);
- if (!names) {
- rv = NS_ERROR_OUT_OF_MEMORY;
- } else {
- nsString* values = new nsString[maxNumValues];
- // XXX use nsAutoArrayPtr instead when that becomes public
- nsStringAutoArrayPtr tmpValues(values);
- if (!values) {
- rv = NS_ERROR_OUT_OF_MEMORY;
- } else {
- rv = controlNode->GetNamesValues(maxNumValues, numValues,
- values, names);
- if (NS_SUCCEEDED(rv)) {
- for (int valueX = 0; valueX < numValues; valueX++) {
- if (PR_TRUE == firstTime) {
- firstTime = PR_FALSE;
- } else {
- buf.Append(NS_LITERAL_STRING("&"));
- }
- nsString* convName = URLEncode(names[valueX],
- encoder,
- aCtrlsModAtSubmit,
- aTextDirAtSubmit,
- charset);
- buf += *convName;
- delete convName;
- buf.Append(NS_LITERAL_STRING("="));
- nsAutoString newValue;
- newValue.Append(values[valueX]);
- if (aFormProcessor) {
- // No need for ProcessValue
- nsCOMPtr htmlElement(
- do_QueryInterface(controlNode));
- rv = aFormProcessor->ProcessValue(htmlElement,
- names[valueX],
- newValue);
- NS_ASSERTION(NS_SUCCEEDED(rv),
- "unable to Notify form process observer");
- }
- nsString* convValue = URLEncode(newValue,
- encoder,
- aCtrlsModAtSubmit,
- aTextDirAtSubmit,
- charset);
- buf += *convValue;
- delete convValue;
- }
- }
- }
- }
- }
- }
- }
- aData.SetLength(0);
- if (isPost) {
- char size[16];
- sprintf(size, "%d", buf.Length());
- aData = NS_LITERAL_STRING(
- "Content-type: application/x-www-form-urlencoded");
-#ifdef SPECIFY_CHARSET_IN_CONTENT_TYPE
- aData += "; charset=";
- aData += charset;
-#endif
- aData.Append(NS_LITERAL_STRING(CRLF));
- aData.Append(NS_LITERAL_STRING("Content-Length: "));
- aData.Append(NS_ConvertASCIItoUCS2(size));
- aData.Append(NS_LITERAL_STRING(CRLF));
- aData.Append(NS_LITERAL_STRING(CRLF));
- }
- aData += buf;
- return rv;
-}
-
-// static
-nsresult
-nsFormSubmitter::ProcessAsMultipart(nsIForm* form,
- nsIPresContext* aPresContext,
- nsIFormProcessor* aFormProcessor,
- nsIFile** aMultipartDataFile,
- nsIContent* aSubmitElement,
- PRInt32 aSubmitPosition,
- PRUint8 aCtrlsModAtSubmit,
- PRUint8 aTextDirAtSubmit)
-{
- PRBool compatibleSubmit = PR_TRUE;
- nsCOMPtr prefService(do_GetService(NS_PREF_CONTRACTID));
- if (prefService)
- prefService->GetBoolPref("browser.forms.submit.backwards_compatible",
- &compatibleSubmit);
-
- char buffer[BUFSIZE];
-
- // Create a temporary file to write the form post data to
- nsCOMPtr tempDir;
- nsresult rv;
- rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tempDir));
- if (tempDir) {
- tempDir->Append("formpost");
- // mode is 0600 so that it's not world-readable
- rv = tempDir->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
- }
- nsCOMPtr outStream;
- if (NS_SUCCEEDED(rv)) {
- rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream),
- tempDir,
- (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
- 0600); // 600 so others can't read our form data
- }
- NS_ASSERTION(NS_SUCCEEDED(rv), "Post data file couldn't be created!");
- if (NS_FAILED(rv)) return rv;
-
- // write the content-type, boundary to the tmp file
- char boundary[80];
- sprintf(boundary, "---------------------------%d%d%d",
- rand(), rand(), rand());
- sprintf(buffer, "Content-type: %s; boundary=%s" CRLF, MULTIPART, boundary);
- PRUint32 wantbytes = 0, gotbytes = 0;
- rv = outStream->Write(buffer, wantbytes = PL_strlen(buffer), &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) return rv;
-
- nsAutoString charset;
- GetSubmitCharset(form, charset, aPresContext, aCtrlsModAtSubmit);
-
- nsCOMPtr encoder;
- // Non-fatal error
- if (NS_FAILED(GetEncoder(form, aPresContext, getter_AddRefs(encoder),
- aCtrlsModAtSubmit, charset)))
- encoder = nsnull;
-
- nsCOMPtr platformencoder;
- // Non-fatal error
- if (NS_FAILED(GetPlatformEncoder(getter_AddRefs(platformencoder))))
- platformencoder = nsnull;
-
-
- PRInt32 boundaryLen = PL_strlen(boundary);
- PRInt32 contDispLen = PL_strlen(CONTENT_DISP);
- PRInt32 crlfLen = PL_strlen(CRLF);
- PRInt32 sepLen = PL_strlen(SEP);
-
- // compute the content length
- /////////////////////////////
-
- PRInt32 contentLen = 0;
-
- // JBK step over elements[] instead of form control frames - bug 34297
- PRUint32 numElements;
- form->GetElementCount(&numElements);
- PRBool mustSubmitElement = (aSubmitPosition > -1);
- for (PRUint32 elementX = 0;
- elementX < numElements || mustSubmitElement;
- elementX++) {
- nsCOMPtr controlNode;
- if ((aSubmitPosition == (PRInt32)elementX || elementX >= numElements)
- && mustSubmitElement) {
- controlNode = do_QueryInterface(aSubmitElement);
- elementX--;
- mustSubmitElement = PR_FALSE;
- } else {
- form->GetElementAt(elementX, getter_AddRefs(controlNode));
- }
-
- if (controlNode) {
- PRInt32 type;
- PRBool successful;
- controlNode->GetType(&type);
- controlNode->IsSuccessful(aSubmitElement, &successful);
- if (successful) {
- PRInt32 numValues = 0;
- PRInt32 maxNumValues;
- controlNode->GetMaxNumValues(&maxNumValues);
- if (maxNumValues <= 0) {
- continue;
- }
- nsString* names = new nsString[maxNumValues];
- nsString* values = new nsString[maxNumValues];
- // XXX use nsAutoArrayPtr instead when that becomes public
- nsStringAutoArrayPtr tmpNames(names);
- // XXX use nsAutoArrayPtr instead when that becomes public
- nsStringAutoArrayPtr tmpValues(values);
- if (NS_FAILED(controlNode->GetNamesValues(maxNumValues, numValues,
- values, names))) {
- continue;
- }
- for (int valueX = 0; valueX < numValues; valueX++) {
- nsCAutoString name;
- nsCAutoString value;
- nsCAutoString fname; // basename (path removed)
-
- nsString valueStr = values[valueX];
- if (aFormProcessor) {
- // No need for ProcessValue
- nsCOMPtr htmlElement(
- do_QueryInterface(controlNode));
- rv = aFormProcessor->ProcessValue(htmlElement,
- names[valueX], valueStr);
- NS_ASSERTION(NS_SUCCEEDED(rv),
- "unable to Notify form process observer");
- }
- if (encoder) {
- name.Adopt(UnicodeToNewBytes(names[valueX].get(),
- names[valueX].Length(),
- encoder,
- aCtrlsModAtSubmit,
- aTextDirAtSubmit,
- charset));
- }
-
- //use the platformencoder only for values containing file names
- PRUint32 fileNameStart = 0;
- if (NS_FORM_INPUT_FILE == type) {
- fileNameStart = GetFileNameWithinPath(valueStr);
- if (platformencoder) {
- value.Adopt(UnicodeToNewBytes(valueStr.get(),
- valueStr.Length(),
- platformencoder,
- aCtrlsModAtSubmit,
- aTextDirAtSubmit,
- charset));
-
- // filename with the leading dirs stripped
- fname.Adopt(UnicodeToNewBytes(valueStr.get() + fileNameStart,
- valueStr.Length() - fileNameStart,
- platformencoder,
- aCtrlsModAtSubmit,
- aTextDirAtSubmit,
- charset));
- }
- } else {
- if (encoder) {
- value.Adopt(UnicodeToNewBytes(valueStr.get(),
- valueStr.Length(),
- encoder,
- aCtrlsModAtSubmit,
- aTextDirAtSubmit,
- charset));
- }
- }
-
- if (name.IsEmpty())
- name.Adopt(ToNewCString(names[valueX]));
- if (value.IsEmpty())
- value.Adopt(ToNewCString(valueStr));
-
- if (names[valueX].IsEmpty()) {
- continue;
- }
-
- // convert value to CRLF line breaks
- value.Adopt(nsLinebreakConverter::ConvertLineBreaks(value.get(),
- nsLinebreakConverter::eLinebreakAny,
- nsLinebreakConverter::eLinebreakNet));
-
- // Add boundary line
- contentLen += sepLen + boundaryLen + crlfLen;
-
- // File inputs should include Content-Transfer-Encoding
- if (NS_FORM_INPUT_FILE == type && !compatibleSubmit) {
- contentLen += PL_strlen(CONTENT_TRANSFER);
- // XXX is there any way to tell when "8bit" or "7bit" etc may be
- // more appropriate than always using "binary"?
- contentLen += PL_strlen(BINARY_CONTENT);
- contentLen += crlfLen;
- }
- // End Content-Transfer-Encoding line
-
- // Add Content-Disp line
- contentLen += contDispLen;
- contentLen += name.Length();
-
- // File inputs also list filename on Content-Disp line
- if (NS_FORM_INPUT_FILE == type) {
- contentLen += PL_strlen(FILENAME);
- contentLen += fname.Length();
- }
- // End Content-Disp Line (quote plus CRLF)
- contentLen += 1 + crlfLen; // ending name quote plus CRLF
-
- // File inputs add Content-Type line
- if (NS_FORM_INPUT_FILE == type) {
- char* contentType = nsnull;
- rv = GetContentType(value.get(), &contentType);
- if (NS_FAILED(rv)) break; // Need to free up anything here?
- contentLen += PL_strlen(CONTENT_TYPE);
- contentLen += PL_strlen(contentType) + crlfLen;
- nsCRT::free(contentType);
- }
-
- // Blank line before value
- contentLen += crlfLen;
-
- // File inputs add file contents next
- if (NS_FORM_INPUT_FILE == type &&
- !value.IsEmpty()) { // Don't bother if no file specified
- do {
- // Because we have a native path to the file we can't use
- // PR_GetFileInfo on the Mac as it expects a Unix style path.
- // Instead we'll use our spiffy new nsILocalFile
- nsILocalFile* tempFile = nsnull;
- rv = NS_NewLocalFile(value.get(), PR_TRUE, &tempFile);
- NS_ASSERTION(tempFile,
- "Couldn't create nsIFileSpec to get file size!");
- if (NS_FAILED(rv) || !tempFile)
- break; // NS_ERROR_OUT_OF_MEMORY
- PRUint32 fileSize32 = 0;
- PRInt64 fileSize = LL_Zero();
- rv = tempFile->GetFileSize(&fileSize);
- if (NS_FAILED(rv)) {
- NS_RELEASE(tempFile);
- break;
- }
- LL_L2UI(fileSize32, fileSize);
- contentLen += fileSize32;
- NS_RELEASE(tempFile);
- } while (PR_FALSE);
-
- // Add CRLF after file
- contentLen += crlfLen;
- } else {
- // Non-file inputs add value line
- contentLen += value.Length() + crlfLen;
- }
- }
- }
- }
- }
-
- // Add the post file boundary line
- contentLen += sepLen + boundaryLen + sepLen + crlfLen;
-
- // write the content
- ////////////////////
-
- sprintf(buffer, "Content-Length: %d" CRLF CRLF, contentLen);
- rv = outStream->Write(buffer, wantbytes = PL_strlen(buffer), &gotbytes);
- if (NS_SUCCEEDED(rv) && (wantbytes == gotbytes)) {
-
- // write the content passing through all of the form controls a 2nd time
- PRBool mustSubmitElement = (aSubmitPosition > -1);
- for (PRUint32 elementX = 0;
- elementX < numElements || mustSubmitElement;
- elementX++) {
- nsCOMPtr controlNode;
- if ((aSubmitPosition == (PRInt32)elementX || elementX >= numElements)
- && mustSubmitElement) {
- controlNode = do_QueryInterface(aSubmitElement);
- elementX--;
- mustSubmitElement = PR_FALSE;
- } else {
- form->GetElementAt(elementX, getter_AddRefs(controlNode));
- }
-
- if (controlNode) {
- PRInt32 type;
- PRBool successful;
- controlNode->GetType(&type);
- controlNode->IsSuccessful(aSubmitElement, &successful);
- if (successful) {
- PRInt32 numValues = 0;
- PRInt32 maxNumValues;
- controlNode->GetMaxNumValues(&maxNumValues);
- if (maxNumValues <= 0) {
- continue;
- }
- nsString* names = new nsString[maxNumValues];
- // XXX use nsAutoArrayPtr instead when that becomes public
- nsStringAutoArrayPtr tmpNames(names);
- nsString* values = new nsString[maxNumValues];
- // XXX use nsAutoArrayPtr instead when that becomes public
- nsStringAutoArrayPtr tmpValues(values);
- if (NS_FAILED(controlNode->GetNamesValues(maxNumValues, numValues,
- values, names))) {
- continue;
- }
- for (int valueX = 0; valueX < numValues; valueX++) {
- nsCAutoString name;
- nsCAutoString value;
- nsCAutoString fname; // basename (path removed)
-
- nsString valueStr = values[valueX];
-
- if (encoder) {
- name.Adopt(UnicodeToNewBytes(names[valueX].get(),
- names[valueX].Length(),
- encoder,
- aCtrlsModAtSubmit,
- aTextDirAtSubmit,
- charset));
- }
-
- //use the platformencoder only for values containing file names
- PRUint32 fileNameStart = 0;
- if (NS_FORM_INPUT_FILE == type) {
- fileNameStart = GetFileNameWithinPath(valueStr);
- if (platformencoder) {
- value.Adopt(UnicodeToNewBytes(valueStr.get(),
- valueStr.Length(),
- platformencoder,
- aCtrlsModAtSubmit,
- aTextDirAtSubmit,
- charset));
-
- // filename with the leading dirs stripped
- fname.Adopt(UnicodeToNewBytes(valueStr.get() + fileNameStart,
- valueStr.Length() - fileNameStart,
- platformencoder,
- aCtrlsModAtSubmit,
- aTextDirAtSubmit,
- charset));
- }
- } else {
- if (encoder) {
- value.Adopt(UnicodeToNewBytes(valueStr.get(),
- valueStr.Length(),
- encoder,
- aCtrlsModAtSubmit,
- aTextDirAtSubmit,
- charset));
- }
- }
-
- if (name.IsEmpty())
- name.Adopt(ToNewCString(names[valueX]));
- if (value.IsEmpty())
- value.Adopt(ToNewCString(valueStr));
-
- if (names[valueX].IsEmpty()) {
- continue;
- }
-
- // convert value to CRLF line breaks
- value.Adopt(nsLinebreakConverter::ConvertLineBreaks(value.get(),
- nsLinebreakConverter::eLinebreakAny,
- nsLinebreakConverter::eLinebreakNet));
-
- // Print boundary line
- sprintf(buffer, SEP "%s" CRLF, boundary);
- wantbytes = PL_strlen(buffer);
- rv = outStream->Write(buffer, wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
-
- // File inputs should include Content-Transfer-Encoding to prep
- // server side MIME decoders
- if (NS_FORM_INPUT_FILE == type && !compatibleSubmit) {
- wantbytes = PL_strlen(CONTENT_TRANSFER);
- rv = outStream->Write(CONTENT_TRANSFER, wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
-
- // XXX is there any way to tell when "8bit" or "7bit" etc may be
- // more appropriate than always using "binary"?
-
- wantbytes = PL_strlen(BINARY_CONTENT);
- rv = outStream->Write(BINARY_CONTENT, wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
-
- wantbytes = PL_strlen(CRLF);
- rv = outStream->Write(CRLF, wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
- }
-
- // Print Content-Disp line
- wantbytes = contDispLen;
- rv = outStream->Write(CONTENT_DISP, wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
- wantbytes = name.Length();
- rv = outStream->Write(name.get(), wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
-
- // File inputs also list filename on Content-Disp line
- if (NS_FORM_INPUT_FILE == type) {
- wantbytes = PL_strlen(FILENAME);
- rv = outStream->Write(FILENAME, wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
- wantbytes = fname.Length();
- rv = outStream->Write(fname.get(), wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
- }
-
- // End Content Disp
- wantbytes = PL_strlen("\"" CRLF);
- rv = outStream->Write("\"" CRLF , wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
-
- // File inputs write Content-Type line
- if (NS_FORM_INPUT_FILE == type) {
- char* contentType = nsnull;
- rv = GetContentType(value.get(), &contentType);
- if (NS_FAILED(rv)) break;
- wantbytes = PL_strlen(CONTENT_TYPE);
- rv = outStream->Write(CONTENT_TYPE, wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
- wantbytes = PL_strlen(contentType);
- rv = outStream->Write(contentType, wantbytes, &gotbytes);
- nsCRT::free(contentType);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
- wantbytes = PL_strlen(CRLF);
- rv = outStream->Write(CRLF, wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
- // end content-type header
- }
-
- // Blank line before value
- wantbytes = PL_strlen(CRLF);
- rv = outStream->Write(CRLF, wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
-
- // File inputs print file contents next
- if (NS_FORM_INPUT_FILE == type) {
- nsIFileSpec* contentFile = nsnull;
- rv = NS_NewFileSpec(&contentFile);
- NS_ASSERTION(contentFile,
- "Post content file couldn't be created!");
- // NS_ERROR_OUT_OF_MEMORY
- if (NS_FAILED(rv) || !contentFile) break;
- rv = contentFile->SetNativePath(value.get());
- NS_ASSERTION(contentFile,
- "Post content file path couldn't be set!");
- if (NS_FAILED(rv)) {
- NS_RELEASE(contentFile);
- break;
- }
- // Print file contents
- PRInt32 size = 1;
- char* readbuffer = nsnull;
- while (1) {
- // Read() mallocs if readbuffer is null
- rv = contentFile->Read(&readbuffer, BUFSIZE, &size);
- if (NS_FAILED(rv) || 0 >= size) break;
- wantbytes = size;
- rv = outStream->Write(readbuffer, wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
- }
- nsMemory::Free(readbuffer);
- NS_RELEASE(contentFile);
- // Print CRLF after file
- wantbytes = PL_strlen(CRLF);
- rv = outStream->Write(CRLF, wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
- }
-
- // Non-file inputs print value line
- else {
- wantbytes = value.Length();
- rv = outStream->Write(value.get(), wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
- wantbytes = PL_strlen(CRLF);
- rv = outStream->Write(CRLF, wantbytes, &gotbytes);
- if (NS_FAILED(rv) || (wantbytes != gotbytes)) break;
- }
- }
- }
- }
- }
- }
-
- if (NS_SUCCEEDED(rv)) {
- sprintf(buffer, SEP "%s" SEP CRLF, boundary);
- wantbytes = PL_strlen(buffer);
- rv = outStream->Write(buffer, wantbytes, &gotbytes);
- if (NS_SUCCEEDED(rv) && (wantbytes == gotbytes)) {
- rv = outStream->Close();
- }
- }
-
- NS_ASSERTION(NS_SUCCEEDED(rv),
- "Generating the form post temp file failed.\n");
- if (NS_SUCCEEDED(rv)) {
- *aMultipartDataFile = tempDir;
- NS_ADDREF(*aMultipartDataFile);
- }
- return rv;
-}
-
-
-
-// JBK moved from nsFormFrame - bug 34297
-// static
-void
-nsFormSubmitter::GetSubmitCharset(nsIForm* form,
- nsAString& oCharset,
- nsIPresContext* aPresContext,
- PRUint8 aCtrlsModAtSubmit)
-{
- oCharset = NS_LITERAL_STRING("UTF-8"); // default to utf-8
- // XXX We may want to get it from the HTML 4 Accept-Charset attribute first
- // see 17.3 The FORM element in HTML 4 for details
- nsresult rv = NS_OK;
- nsAutoString acceptCharsetValue;
- nsCOMPtr formContent = do_QueryInterface(form);
- nsHTMLValue value;
- rv = formContent->GetHTMLAttribute(nsHTMLAtoms::acceptcharset, value);
- if (NS_CONTENT_ATTR_HAS_VALUE == rv) {
- if (eHTMLUnit_String == value.GetUnit()) {
- value.GetStringValue(acceptCharsetValue);
- }
- }
-
-#ifdef DEBUG_ftang
- printf("accept-charset = %s\n", acceptCharsetValue.ToNewUTF8String());
-#endif
- PRInt32 l = acceptCharsetValue.Length();
- if (l > 0 ) {
- PRInt32 offset=0;
- PRInt32 spPos=0;
- // get charset from charsets one by one
- nsCOMPtr calias(do_GetService(kCharsetAliasCID, &rv));
- if (NS_SUCCEEDED(rv) && calias) {
- do {
- spPos = acceptCharsetValue.FindChar(PRUnichar(' '), offset);
- PRInt32 cnt = ((-1==spPos)?(l-offset):(spPos-offset));
- if (cnt > 0) {
- nsAutoString charset;
- acceptCharsetValue.Mid(charset, offset, cnt);
-#ifdef DEBUG_ftang
- printf("charset[i] = %s\n",charset.ToNewUTF8String());
-#endif
- if (NS_SUCCEEDED(calias->GetPreferred(charset, 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
- nsCOMPtr formElement = do_QueryInterface(form);
- if (formElement) {
- nsIDocument* doc = nsnull;
- formElement->GetDocument(doc);
- if ( doc ) {
- rv = doc->GetDocumentCharacterSet(oCharset);
- NS_RELEASE(doc);
- }
- }
-
-#ifdef IBMBIDI
- if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
- && Compare(oCharset, NS_LITERAL_STRING("windows-1256"),
- nsCaseInsensitiveStringComparator()) == 0) {
-//Mohamed
- oCharset = NS_LITERAL_STRING("IBM864");
- }
- else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_LOGICAL
- && Compare(oCharset, NS_LITERAL_STRING("IBM864"),
- nsCaseInsensitiveStringComparator()) == 0) {
- oCharset = NS_LITERAL_STRING("IBM864i");
- }
- else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
- && Compare(oCharset, NS_LITERAL_STRING("ISO-8859-6"),
- nsCaseInsensitiveStringComparator()) == 0) {
- oCharset = NS_LITERAL_STRING("IBM864");
- }
- else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
- && Compare(oCharset, NS_LITERAL_STRING("UTF-8"),
- nsCaseInsensitiveStringComparator()) == 0) {
- oCharset = NS_LITERAL_STRING("IBM864");
- }
-
-#endif
-}
-
-// JBK moved from nsFormFrame - bug 34297
-// static
-nsresult
-nsFormSubmitter::GetEncoder(nsIForm* form,
- nsIPresContext* aPresContext,
- nsIUnicodeEncoder** encoder,
- PRUint8 aCtrlsModAtSubmit,
- const nsAString& aCharset)
-{
- *encoder = nsnull;
- nsresult rv = NS_OK;
-#ifdef DEBUG_ftang
- printf("charset=%s\n", ToNewCString(charset));
-#endif
-
- // Get Charset, get the encoder.
- nsICharsetConverterManager * ccm = nsnull;
- rv = nsServiceManager::GetService(kCharsetConverterManagerCID ,
- NS_GET_IID(nsICharsetConverterManager),
- (nsISupports**)&ccm);
- if (NS_SUCCEEDED(rv) && ccm) {
- nsString charset(aCharset);
- if (charset.Equals(NS_LITERAL_STRING("ISO-8859-1")))
- charset.Assign(NS_LITERAL_STRING("windows-1252"));
- rv = ccm->GetUnicodeEncoder(&charset, encoder);
- nsServiceManager::ReleaseService( kCharsetConverterManagerCID, ccm);
- if (encoder) {
- rv = NS_ERROR_FAILURE;
- }
- if (NS_SUCCEEDED(rv)) {
- rv = (*encoder)->SetOutputErrorBehavior(
- nsIUnicodeEncoder::kOnError_Replace,
- nsnull,
- (PRUnichar)'?');
- }
- }
- return NS_OK;
-}
-
-// XXX i18n helper routines
-// static
-nsString*
-nsFormSubmitter::URLEncode(const nsAString& aString,
- nsIUnicodeEncoder* encoder,
- PRUint8 aCtrlsModAtSubmit,
- PRUint8 aTextDirAtSubmit,
- const nsAString& aCharset)
-{
- char* inBuf = nsnull;
- if (encoder) {
- // XXX This is inefficient. When nsAString gets a get() equivalent,
- // use that.
- PRUnichar* strUnicode = ToNewUnicode(aString);
- inBuf = UnicodeToNewBytes(strUnicode,
- aString.Length(),
- encoder,
- aCtrlsModAtSubmit,
- aTextDirAtSubmit,
- aCharset);
- delete strUnicode;
- }
-
- if (!inBuf)
- inBuf = ToNewCString(aString);
-
- // convert to CRLF breaks
- char* convertedBuf = nsLinebreakConverter::ConvertLineBreaks(inBuf,
- nsLinebreakConverter::eLinebreakAny,
- nsLinebreakConverter::eLinebreakNet);
- delete [] inBuf;
-
- char* outBuf = nsEscape(convertedBuf, url_XPAlphas);
- nsString* result = new nsString;
- result->AssignWithConversion(outBuf);
- nsCRT::free(outBuf);
- nsMemory::Free(convertedBuf);
- return result;
-}
-
-// XXX i18n helper routines
-// static
-char*
-nsFormSubmitter::UnicodeToNewBytes(const PRUnichar* aSrc,
- PRUint32 aLen,
- nsIUnicodeEncoder* encoder,
- PRUint8 aCtrlsModAtSubmit,
- PRUint8 aTextDirAtSubmit,
- const nsAString& aCharset)
-{
-#ifdef IBMBIDI
- //ahmed 15-1
- nsAutoString temp;
- nsCOMPtr bidiUtils(
- do_GetService("@mozilla.org/intl/unicharbidiutil;1"));
- nsAutoString newBuffer;
- //This condition handle the RTL,LTR for a logical file
- if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
- && Compare(aCharset, NS_LITERAL_STRING("windows-1256"),
- nsCaseInsensitiveStringComparator()) == 0 ) {
- bidiUtils->Conv_06_FE_WithReverse(nsString(aSrc),
- newBuffer,
- aTextDirAtSubmit);
- aSrc = (PRUnichar *)newBuffer.get();
- aLen=newBuffer.Length();
- }
- else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_LOGICAL
- && Compare(aCharset, NS_LITERAL_STRING("IBM864"),
- nsCaseInsensitiveStringComparator()) == 0) {
- //For 864 file, When it is logical, if LTR then only convert
- //If RTL will mak a reverse for the buffer
- bidiUtils->Conv_FE_06(nsString(aSrc), newBuffer);
- aSrc = (PRUnichar *)newBuffer.get();
- temp = newBuffer;
- aLen=newBuffer.Length();
- if (aTextDirAtSubmit == 2) { //RTL
- //Now we need to reverse the Buffer, it is by searching the buffer
- PRUint32 loop = aLen;
- PRUint32 z;
- for (z=0; z<=aLen; z++) {
- temp.SetCharAt((PRUnichar)aSrc[loop], z);
- loop--;
- }
- }
- aSrc = (PRUnichar *)temp.get();
- }
- else if (aCtrlsModAtSubmit==IBMBIDI_CONTROLSTEXTMODE_VISUAL
- && Compare(aCharset, NS_LITERAL_STRING("IBM864"),
- nsCaseInsensitiveStringComparator()) == 0
- && aTextDirAtSubmit == IBMBIDI_TEXTDIRECTION_RTL) {
-
- bidiUtils->Conv_FE_06(nsString(aSrc), newBuffer);
- aSrc = (PRUnichar *)newBuffer.get();
- temp = newBuffer;
- aLen=newBuffer.Length();
- //Now we need to reverse the Buffer, it is by searching the buffer
- PRUint32 loop = aLen;
- PRUint32 z;
- for (z=0; z<=aLen; z++) {
- temp.SetCharAt((PRUnichar)aSrc[loop], z);
- loop--;
- }
- aSrc = (PRUnichar *)temp.get();
- }
-#endif
- char* res = nsnull;
- nsresult rv = encoder->Reset();
- if (NS_SUCCEEDED(rv)) {
- PRInt32 maxByteLen = 0;
- rv = encoder->GetMaxLength(aSrc, (PRInt32) aLen, &maxByteLen);
- if (NS_SUCCEEDED(rv)) {
- res = new char[maxByteLen+1];
- if (res) {
- PRInt32 reslen = maxByteLen;
- PRInt32 reslen2 ;
- PRInt32 srclen = aLen;
- encoder->Convert(aSrc, &srclen, res, &reslen);
- reslen2 = maxByteLen-reslen;
- encoder->Finish(res+reslen, &reslen2);
- res[reslen+reslen2] = '\0';
- }
- }
-
- }
- return res;
-}
-
-
-// static
-nsresult
-nsFormSubmitter::GetPlatformEncoder(nsIUnicodeEncoder** encoder)
-{
- *encoder = nsnull;
- nsAutoString localeCharset;
- nsresult rv = NS_OK;
-
- // Get Charset, get the encoder.
- nsICharsetConverterManager * ccm = nsnull;
- rv = nsServiceManager::GetService(kCharsetConverterManagerCID ,
- NS_GET_IID(nsICharsetConverterManager),
- (nsISupports**)&ccm);
-
- if (NS_SUCCEEDED(rv) && ccm) {
-
- nsCOMPtr platformCharset(
- do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv));
-
- if (NS_SUCCEEDED(rv)) {
- rv = platformCharset->GetCharset(kPlatformCharsetSel_FileName,
- localeCharset);
- }
-
- if (NS_FAILED(rv)) {
- NS_ASSERTION(0, "error getting locale charset, using ISO-8859-1");
- localeCharset.Assign(NS_LITERAL_STRING("ISO-8859-1"));
- rv = NS_OK;
- }
-
- // get unicode converter mgr
- //nsCOMPtr ccm =
- // do_GetService(kCharsetConverterManagerCID, &rv);
-
- if (NS_SUCCEEDED(rv)) {
- rv = ccm->GetUnicodeEncoder(&localeCharset, encoder);
- }
- }
-
- return NS_OK;
-}
-
-
-// return the filename without the leading directories (Unix basename)
-// static
-PRUint32
-nsFormSubmitter::GetFileNameWithinPath(nsString& aPathName)
-{
- // We need to operator on Unicode strings and not on nsCStrings
- // because Shift_JIS and Big5 encoded filenames can have
- // embedded directory separators in them.
-#ifdef XP_MAC
- // On a Mac the only invalid character in a file name is a :
- // so we have to avoid the test for '\'. We can't use
- // PR_DIRECTORY_SEPARATOR_STR (even though ':' is a dir sep for MacOS)
- // because this is set to '/' for reasons unknown to this coder.
- PRInt32 fileNameStart = aPathName.RFind(":");
-#else
- PRInt32 fileNameStart = aPathName.RFind(PR_DIRECTORY_SEPARATOR_STR);
-#endif
- // if no directory separator is found (-1), return the whole
- // string, otherwise return the basename only
- return (PRUint32) (fileNameStart + 1);
-}
-
-
-// static
-nsresult
-nsFormSubmitter::GetContentType(const char* aPathName, char** aContentType)
-{
- nsresult rv = NS_OK;
- NS_ASSERTION(aContentType, "null pointer");
-
- if (aPathName && *aPathName) {
- // Get file extension and mimetype from that.g936
- const char* fileExt = aPathName + nsCRT::strlen(aPathName);
- while (fileExt > aPathName) {
- if (*(--fileExt) == '.') {
- break;
- }
- }
-
- if (*fileExt == '.' && *(fileExt + 1)) {
- nsCOMPtr MIMEService =
- do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
- if (NS_FAILED(rv))
- return rv;
-
- rv = MIMEService->GetTypeFromExtension(fileExt + 1, aContentType);
-
- if (NS_SUCCEEDED(rv)) {
- return NS_OK;
- }
- }
- }
- *aContentType = nsCRT::strdup("application/octet-stream");
- if (!*aContentType) return NS_ERROR_OUT_OF_MEMORY;
- return NS_OK;
-}
-
-// static
-nsresult
-nsFormSubmitter::GetEnumAttr(nsIForm* form, nsIAtom* atom, PRInt32* aValue)
-{
- nsCOMPtr content = do_QueryInterface(form);
- if (content) {
- nsHTMLValue value;
- if (NS_CONTENT_ATTR_HAS_VALUE ==
- content->GetHTMLAttribute(atom, value)) {
- if (eHTMLUnit_Enumerated == value.GetUnit()) {
- (*aValue) = value.GetIntValue();
- }
- }
- }
- return NS_OK;
-}
-
-// JBK moved from nsFormFrame - bug 34297
-// Get the Method, with proper defaults (for submit/reset)
-// static
-nsresult
-nsFormSubmitter::FullyGetMethod(nsIForm* form, PRInt32* aMethod)
-{
- (*aMethod) = NS_FORM_METHOD_GET;
- return GetEnumAttr(form, nsHTMLAtoms::method, aMethod);
-}
-
-// JBK moved from nsFormFrame - bug 34297
-// Get the Enctype, with proper defaults (for submit/reset)
-// static
-nsresult
-nsFormSubmitter::FullyGetEnctype(nsIForm* form, PRInt32* aEnctype)
-{
- (*aEnctype) = NS_FORM_ENCTYPE_URLENCODED;
- return GetEnumAttr(form, nsHTMLAtoms::enctype, aEnctype);
-}
diff --git a/mozilla/content/html/content/src/nsFormSubmitter.h b/mozilla/content/html/content/src/nsFormSubmitter.h
deleted file mode 100644
index e409b4a254b..00000000000
--- a/mozilla/content/html/content/src/nsFormSubmitter.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/NPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is Mozilla Communicator client code.
- *
- * The Initial Developer of the Original Code is Netscape Communications
- * Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- */
-#ifndef nsFormSubmitter_h___
-#define nsFormSubmitter_h___
-
-#include "prtypes.h"
-#include "nscore.h"
-#include "nsError.h"
-
-class nsIForm;
-class nsIPresContext;
-class nsIContent;
-class nsIFormProcessor;
-class nsIFile;
-class nsString;
-class nsIPresContext;
-class nsIUnicodeEncoder;
-class nsIDOMNode;
-class nsAString;
-class nsIDOMHTMLFormElement;
-class nsIAtom;
-
-class nsFormSubmitter {
-
-public:
- // JBK moved methods necessary for submit
- static nsresult OnSubmit(nsIForm* form,
- nsIPresContext* aPresContext,
- nsIContent* submitElement);
-
-protected:
- static nsresult CompareNodes(nsIDOMNode* a,
- nsIDOMNode* b,
- PRInt32* retval);
- static nsresult ProcessAsURLEncoded(nsIForm* form,
- nsIPresContext* aPresContext,
- nsIFormProcessor* aFormProcessor,
- PRBool isPost,
- nsAString& aData,
- nsIContent* submitElement,
- PRInt32 aSubmitPosition,
- PRUint8 aCtrlsModAtSubmit,
- PRUint8 aTextDirAtSubmit);
- static nsresult ProcessAsMultipart(nsIForm* form,
- nsIPresContext* aPresContext,
- nsIFormProcessor* aFormProcessor,
- nsIFile** aMultipartDataFile,
- nsIContent* submitElement,
- PRInt32 aSubmitPosition,
- PRUint8 aCtrlsModAtSubmit,
- PRUint8 aTextDirAtSubmit);
- static void GetSubmitCharset(nsIForm* form,
- nsAString& oCharset,
- nsIPresContext*
- aPresContext,
- PRUint8 aCtrlsModAtSubmit);
- static nsresult GetEncoder(nsIForm* form,
- nsIPresContext* aPresContext,
- nsIUnicodeEncoder** encoder,
- PRUint8 aCtrlsModAtSubmit,
- const nsAString& mCharset);
- static nsString* URLEncode(const nsAString& aString,
- nsIUnicodeEncoder* encoder,
- PRUint8 aCtrlsModAtSubmit,
- PRUint8 aTextDirAtSubmit,
- const nsAString& mCharset);
- static char* UnicodeToNewBytes(const PRUnichar* aSrc,
- PRUint32 aLen,
- nsIUnicodeEncoder* encoder,
- PRUint8 aCtrlsModAtSubmit,
- PRUint8 aTextDirAtSubmit,
- const nsAString& mCharset);
- static nsresult GetPlatformEncoder(nsIUnicodeEncoder** encoder);
- static PRUint32 GetFileNameWithinPath(nsString& aPathName);
- static nsresult GetContentType(const char* aPathName, char** aContentType);
-
- static nsresult GetEnumAttr(nsIForm* form, nsIAtom* atom, PRInt32* aValue);
- static nsresult FullyGetMethod(nsIForm* form, PRInt32* aMethod);
- static nsresult FullyGetEnctype(nsIForm* form, PRInt32* aEnctype);
-
- // Detection of first form to notify observers
- static PRBool gFirstFormSubmitted;
-};
-
-#endif
diff --git a/mozilla/content/html/content/src/nsHTMLButtonElement.cpp b/mozilla/content/html/content/src/nsHTMLButtonElement.cpp
index f467c09e934..b7aa4fa7ffd 100644
--- a/mozilla/content/html/content/src/nsHTMLButtonElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLButtonElement.cpp
@@ -48,6 +48,7 @@
#include "nsIPresContext.h"
#include "nsIFormControl.h"
#include "nsIForm.h"
+#include "nsIFormSubmission.h"
#include "nsIURL.h"
#include "nsIFrame.h"
@@ -90,12 +91,8 @@ public:
// overrided nsIFormControl method
NS_IMETHOD GetType(PRInt32* aType);
NS_IMETHOD Reset();
- NS_IMETHOD IsSuccessful(nsIContent* aSubmitElement, PRBool *_retval);
- NS_IMETHOD GetMaxNumValues(PRInt32 *_retval);
- NS_IMETHOD GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames);
+ NS_IMETHOD SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement);
// nsIContent overrides...
NS_IMETHOD GetAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,
@@ -126,7 +123,6 @@ private:
// The analogue of defaultValue in the DOM for input and textarea
nsresult SetDefaultValue(const nsAReadableString& aDefaultValue);
nsresult GetDefaultValue(nsAWritableString& aDefaultValue);
-
};
@@ -582,63 +578,56 @@ nsHTMLButtonElement::SetDefaultValue(const nsAReadableString& aDefaultValue)
return SetAttr(kNameSpaceID_HTML, nsHTMLAtoms::value, aDefaultValue, PR_TRUE);
}
-nsresult
+NS_IMETHODIMP
nsHTMLButtonElement::Reset()
{
return NS_OK;
}
-nsresult
-nsHTMLButtonElement::IsSuccessful(nsIContent* aSubmitElement,
- PRBool *_retval)
+NS_IMETHODIMP
+nsHTMLButtonElement::SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement)
{
- *_retval = PR_FALSE;
+ nsresult rv = NS_OK;
+
+ //
+ // We only submit if we were the button pressed
+ //
if (aSubmitElement != this) {
return NS_OK;
}
- // if it's disabled, it won't submit
+ //
+ // Disabled elements don't submit
+ //
PRBool disabled;
- nsresult rv = GetDisabled(&disabled);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (disabled) {
- return NS_OK;
+ rv = GetDisabled(&disabled);
+ if (NS_FAILED(rv) || disabled) {
+ return rv;
}
- // If there is no name, it won't submit
- nsAutoString val;
- rv = GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, val);
- *_retval = rv != NS_CONTENT_ATTR_NOT_THERE;
- return NS_OK;
-}
-
-nsresult
-nsHTMLButtonElement::GetMaxNumValues(PRInt32 *_retval)
-{
- *_retval = 1;
- return NS_OK;
-}
-
-nsresult
-nsHTMLButtonElement::GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames)
-{
- NS_ENSURE_TRUE(aMaxNumValues >= 1, NS_ERROR_UNEXPECTED);
-
- // We'll of course use the name of the control for the submit
+ //
+ // Get the name (if no name, no submit)
+ //
nsAutoString name;
- nsresult rv = GetName(name);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, name);
+ if (NS_FAILED(rv) || rv == NS_CONTENT_ATTR_NOT_THERE) {
+ return rv;
+ }
+ //
+ // Get the value
+ //
nsAutoString value;
rv = GetValue(value);
- NS_ENSURE_SUCCESS(rv, rv);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
- aNames[0] = name;
- aValues[0] = value;
- aNumValues = 1;
- return NS_OK;
+ //
+ // Submit
+ //
+ rv = aFormSubmission->AddNameValuePair(this, name, value);
+
+ return rv;
}
diff --git a/mozilla/content/html/content/src/nsHTMLFieldSetElement.cpp b/mozilla/content/html/content/src/nsHTMLFieldSetElement.cpp
index f9a0f8d9d35..212fbb490a7 100644
--- a/mozilla/content/html/content/src/nsHTMLFieldSetElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLFieldSetElement.cpp
@@ -75,10 +75,8 @@ public:
// nsIFormControl
NS_IMETHOD GetType(PRInt32* aType);
NS_IMETHOD Reset();
- NS_IMETHOD IsSuccessful(nsIContent* aSubmitElement, PRBool *_retval);
- NS_IMETHOD GetMaxNumValues(PRInt32 *_retval);
- NS_IMETHOD GetNamesValues(PRInt32 aMaxNumValues, PRInt32& aNumValues,
- nsString* aValues, nsString* aNames);
+ NS_IMETHOD SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement);
#ifdef DEBUG
// nsIContent
@@ -208,27 +206,9 @@ nsHTMLFieldSetElement::Reset()
return NS_OK;
}
-nsresult
-nsHTMLFieldSetElement::IsSuccessful(nsIContent* aSubmitElement,
- PRBool *_retval)
+NS_IMETHODIMP
+nsHTMLFieldSetElement::SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement)
{
- *_retval = PR_FALSE;
- return NS_OK;
-}
-
-nsresult
-nsHTMLFieldSetElement::GetMaxNumValues(PRInt32 *_retval)
-{
- *_retval = 0;
- return NS_OK;
-}
-
-nsresult
-nsHTMLFieldSetElement::GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames)
-{
- aNumValues = 0;
return NS_OK;
}
diff --git a/mozilla/content/html/content/src/nsHTMLFormElement.cpp b/mozilla/content/html/content/src/nsHTMLFormElement.cpp
index 1b3e6467549..afa7b4e619d 100644
--- a/mozilla/content/html/content/src/nsHTMLFormElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLFormElement.cpp
@@ -39,7 +39,7 @@
#include "nsIForm.h"
#include "nsIFormControl.h"
#include "nsIFormManager.h"
-#include "nsFormSubmitter.h"
+#include "nsIFormSubmission.h"
#include "nsIDOMHTMLFormElement.h"
#include "nsIDOMNSHTMLFormElement.h"
#include "nsIHTMLDocument.h"
@@ -63,7 +63,18 @@
#include "nsHashtable.h"
#include "nsContentList.h"
#include "nsGUIEvent.h"
+
+// form submission
#include "nsIFormSubmitObserver.h"
+#include "nsIURI.h"
+#include "nsIObserverService.h"
+#include "nsICategoryManager.h"
+#include "nsISimpleEnumerator.h"
+#include "nsIDOMWindowInternal.h"
+#include "nsRange.h"
+#include "nsIScriptSecurityManager.h"
+#include "nsNetUtil.h"
+
static const int NS_FORM_CONTROL_LIST_HASHTABLE_SIZE = 16;
@@ -131,16 +142,72 @@ protected:
nsresult DoSubmitOrReset(nsIPresContext* aPresContext,
nsEvent* aEvent,
PRInt32 aMessage);
+ nsresult DoReset();
- NS_IMETHOD OnReset(nsIPresContext* aPresContext);
- nsresult RemoveSelfAsWebProgressListener();
+ //
+ // Submit Helpers
+ //
+ //
+ /**
+ * Actually perform the submit (called by DoSubmitOrReset)
+ *
+ * @param aPresContext the presentation context
+ * @param aEvent the DOM event that was passed to us for the submit
+ */
+ nsresult DoSubmit(nsIPresContext* aPresContext, nsEvent* aEvent);
+ /**
+ * Walk over the form elements and call SubmitNamesValues() on them to get
+ * their data pumped into the FormSubmitter.
+ *
+ * @param aFormSubmission the form submission object
+ * @param aSubmitElement the element that was clicked on (nsnull if none)
+ */
+ nsresult WalkFormElements(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement);
+ /**
+ * 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
+ */
+ nsresult GetActionURL(nsIURI** aActionURL);
+ /**
+ * Notify any submit observsers of the submit.
+ *
+ * @param aActionURL the URL being submitted to
+ * @param aCancelSubmit out param where submit observers can specify that the
+ * submit should be cancelled.
+ */
+ nsresult NotifySubmitObservers(nsIURI* aActionURL, PRBool* aCancelSubmit);
+ /**
+ * Compare two nodes in the same tree (Negative result means a < b, 0 ==,
+ * positive >). This function may fail if the nodes are not in a tree
+ * or are in different trees.
+ *
+ * @param a the first node
+ * @param b the second node
+ * @param retval whether a < b (negative), a == b (0), or a > b (positive)
+ */
+ static nsresult CompareNodes(nsIDOMNode* a,
+ nsIDOMNode* b,
+ PRInt32* retval);
+
+ //
+ // Data members
+ //
nsFormControlList *mControls;
PRPackedBool mGeneratingSubmit;
PRPackedBool mGeneratingReset;
PRPackedBool mDemotingForm;
+
+protected:
+ // Detection of first form to notify observers
+ static PRBool gFirstFormSubmitted;
};
+PRBool nsHTMLFormElement::gFirstFormSubmitted = PR_FALSE;
+
+
// nsFormControlList
class nsFormControlList : public nsIDOMNSHTMLFormControlList,
public nsIDOMHTMLCollection
@@ -324,9 +391,7 @@ nsHTMLFormElement::CloneNode(PRBool aDeep, nsIDOMNode** aReturn)
nsCOMPtr kungFuDeathGrip(it);
nsresult rv = it->Init(mNodeInfo);
-
- if (NS_FAILED(rv))
- return rv;
+ NS_ENSURE_SUCCESS(rv, rv);
CopyInnerTo(this, it, aDeep);
@@ -520,7 +585,8 @@ nsHTMLFormElement::HandleDOMEvent(nsIPresContext* aPresContext,
nsresult
nsHTMLFormElement::DoSubmitOrReset(nsIPresContext* aPresContext,
nsEvent* aEvent,
- PRInt32 aMessage) {
+ PRInt32 aMessage)
+{
NS_ENSURE_ARG_POINTER(aPresContext);
// Make sure the presentation is up-to-date
@@ -535,27 +601,16 @@ nsHTMLFormElement::DoSubmitOrReset(nsIPresContext* aPresContext,
// Submit or Reset the form
nsresult rv = NS_OK;
if (NS_FORM_RESET == aMessage) {
- rv = OnReset(aPresContext);
+ rv = DoReset();
}
else if (NS_FORM_SUBMIT == aMessage) {
- nsIContent *originatingElement = nsnull;
-
- // Get the originating frame (failure is non-fatal)
- if (aEvent) {
- if (NS_FORM_EVENT == aEvent->eventStructType) {
- originatingElement = ((nsFormEvent *)aEvent)->originator;
- }
- }
-
- // Pass the form originator
- rv = nsFormSubmitter::OnSubmit(this, aPresContext, originatingElement);
+ rv = DoSubmit(aPresContext, aEvent);
}
return rv;
}
-// JBK moved from nsFormFrame - bug 34297
-NS_IMETHODIMP
-nsHTMLFormElement::OnReset(nsIPresContext* aPresContext)
+nsresult
+nsHTMLFormElement::DoReset()
{
// JBK walk the elements[] array instead of form frame controls - bug 34297
PRUint32 numElements;
@@ -571,6 +626,326 @@ nsHTMLFormElement::OnReset(nsIPresContext* aPresContext)
return NS_OK;
}
+nsresult
+nsHTMLFormElement::DoSubmit(nsIPresContext* aPresContext, nsEvent* aEvent)
+{
+ nsIContent *originatingElement = nsnull;
+
+ // Get the originating frame (failure is non-fatal)
+ if (aEvent) {
+ if (NS_FORM_EVENT == aEvent->eventStructType) {
+ originatingElement = ((nsFormEvent *)aEvent)->originator;
+ }
+ }
+
+ //
+ // Get the submission object
+ //
+ nsCOMPtr submission;
+ nsresult rv = GetSubmissionFromForm(this, aPresContext,
+ getter_AddRefs(submission));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ //
+ // Dump the data into the submission object
+ //
+ rv = WalkFormElements(submission, originatingElement);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ //
+ // Get the action and target
+ //
+ nsCOMPtr actionURI;
+ rv = GetActionURL(getter_AddRefs(actionURI));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (actionURI) {
+ nsAutoString target;
+ rv = GetTarget(target);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ //
+ // Notify observers of submit
+ //
+ PRBool aCancelSubmit = PR_FALSE;
+ rv = NotifySubmitObservers(actionURI, &aCancelSubmit);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!aCancelSubmit) {
+ //
+ // Submit
+ //
+ rv = submission->SubmitTo(actionURI, target, this, aPresContext);
+ }
+ }
+
+ return rv;
+}
+
+
+nsresult
+nsHTMLFormElement::NotifySubmitObservers(nsIURI* aActionURL,
+ PRBool* aCancelSubmit)
+{
+ // If this is the first form, bring alive the first form submit
+ // category observers
+ if (!gFirstFormSubmitted) {
+ gFirstFormSubmitted = PR_TRUE;
+ NS_CreateServicesFromCategory(NS_FIRST_FORMSUBMIT_CATEGORY,
+ nsnull,
+ NS_FIRST_FORMSUBMIT_CATEGORY);
+ }
+
+ // Notify observers that the form is being submitted.
+ nsresult rv = NS_OK;
+ nsCOMPtr service =
+ do_GetService("@mozilla.org/observer-service;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr theEnum;
+ rv = service->EnumerateObservers(NS_FORMSUBMIT_SUBJECT,
+ getter_AddRefs(theEnum));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (theEnum) {
+ nsCOMPtr inst;
+ *aCancelSubmit = PR_FALSE;
+
+ nsCOMPtr globalObject;
+ mDocument->GetScriptGlobalObject(getter_AddRefs(globalObject));
+ nsCOMPtr window = do_QueryInterface(globalObject);
+
+ PRBool loop = PR_TRUE;
+ while (NS_SUCCEEDED(theEnum->HasMoreElements(&loop)) && loop) {
+ theEnum->GetNext(getter_AddRefs(inst));
+
+ nsCOMPtr formSubmitObserver(
+ do_QueryInterface(inst));
+ if (formSubmitObserver) {
+ rv = formSubmitObserver->Notify(this,
+ window,
+ aActionURL,
+ aCancelSubmit);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ if (*aCancelSubmit) {
+ return NS_OK;
+ }
+ }
+ }
+
+ return rv;
+}
+
+
+// static
+nsresult
+nsHTMLFormElement::CompareNodes(nsIDOMNode* a, nsIDOMNode* b, PRInt32* retval)
+{
+ nsresult rv;
+
+ nsCOMPtr parentA;
+ PRInt32 indexA;
+ rv = a->GetParentNode(getter_AddRefs(parentA));
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!parentA) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ {
+ // To get the index, we must turn them both into contents
+ // and do IndexOf(). Ick.
+ nsCOMPtr parentA(do_QueryInterface(parentA));
+ nsCOMPtr contentA(do_QueryInterface(a));
+ if (!parentA && !contentA) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ rv = parentA->IndexOf(contentA, indexA);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ nsCOMPtr parentB;
+ PRInt32 indexB;
+ rv = b->GetParentNode(getter_AddRefs(parentB));
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!parentB) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ {
+ // To get the index, we must turn them both into contents
+ // and do IndexOf(). Ick.
+ nsCOMPtr parentB(do_QueryInterface(parentB));
+ nsCOMPtr bContent(do_QueryInterface(b));
+ if (!parentB && !bContent) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ rv = parentB->IndexOf(bContent, indexB);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ *retval = ComparePoints(parentA, indexA, parentB, indexB);
+ return NS_OK;
+}
+
+
+nsresult
+nsHTMLFormElement::WalkFormElements(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement)
+{
+ //
+ // If the submitter is an input type=image element, it is not in the
+ // form.elements[] array. So we get the DOMNode pointer to it here so that
+ // later we can determine its proper position in the submit order.
+ //
+ nsCOMPtr imageElementNode;
+ {
+ nsCOMPtr submitControl = do_QueryInterface(aSubmitElement);
+ if (submitControl) {
+ PRInt32 type;
+ submitControl->GetType(&type);
+ if (type == NS_FORM_INPUT_IMAGE) {
+ imageElementNode = do_QueryInterface(aSubmitElement);
+ }
+ }
+ }
+
+ //
+ // Walk the list of nodes and call SubmitNamesValues() on the controls
+ //
+ PRUint32 numElements;
+ GetElementCount(&numElements);
+
+ PRUint32 elementX;
+ for (elementX = 0; elementX < numElements; elementX++) {
+ nsCOMPtr control;
+ GetElementAt(elementX, getter_AddRefs(control));
+
+ // Determine whether/when to submit the image element, which is not in
+ // the list of form.elements[]
+ if (imageElementNode) {
+ // If the input type=image element is before this element, submit it
+ // instead
+ nsCOMPtr controlNode(do_QueryInterface(control));
+ PRInt32 comparison;
+ CompareNodes(imageElementNode, controlNode, &comparison);
+ if (comparison < 0) {
+ nsCOMPtr image = do_QueryInterface(imageElementNode);
+ image->SubmitNamesValues(aFormSubmission, aSubmitElement);
+ imageElementNode = nsnull;
+ }
+ }
+
+ // Tell the control to submit its name/value pairs to the submission
+ control->SubmitNamesValues(aFormSubmission, aSubmitElement);
+ }
+
+ // The image appeared after all other controls
+ if (imageElementNode) {
+ nsCOMPtr image = do_QueryInterface(imageElementNode);
+ image->SubmitNamesValues(aFormSubmission, aSubmitElement);
+ }
+
+ return NS_OK;
+}
+
+nsresult
+nsHTMLFormElement::GetActionURL(nsIURI** aActionURL)
+{
+ nsresult rv = NS_OK;
+
+ *aActionURL = nsnull;
+
+ //
+ // Grab the URL string
+ //
+ nsAutoString action;
+ GetAction(action);
+
+ //
+ // Form the full action URL
+ //
+
+ // Get the document to form the URL.
+ // We'll also need it later to get the DOM window when notifying form submit
+ // observers (bug 33203)
+ if (!mDocument) {
+ return NS_OK; // No doc means don't submit, see Bug 28988
+ }
+
+ // Get base URL
+ nsCOMPtr docURL;
+ mDocument->GetBaseURL(*getter_AddRefs(docURL));
+ NS_ASSERTION(docURL, "No Base URL found in Form Submit!\n");
+ if (!docURL) {
+ return NS_OK; // No base URL -> exit early, see Bug 30721
+ }
+
+ // If an action is not specified and we are inside
+ // a HTML document then reload the URL. This makes us
+ // compatible with 4.x browsers.
+ // If we are in some other type of document such as XML or
+ // XUL, do nothing. This prevents undesirable reloading of
+ // a document inside XUL.
+
+ nsCOMPtr actionURL;
+ if (action.IsEmpty()) {
+ nsCOMPtr htmlDoc(do_QueryInterface(mDocument));
+ if (!htmlDoc) {
+ // Must be a XML, XUL or other non-HTML document type
+ // so do nothing.
+ return NS_OK;
+ }
+
+ rv = docURL->Clone(getter_AddRefs(actionURL));
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ rv = NS_NewURI(getter_AddRefs(actionURL), action, docURL);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ //
+ // Verify the URL should be reached
+ //
+ // Get security manager, check to see if access to action URI is allowed.
+ //
+ // XXX This code has not been tested. mailto: does not work in forms.
+ //
+ nsCOMPtr securityManager =
+ do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = securityManager->CheckLoadURI(docURL, actionURL,
+ nsIScriptSecurityManager::STANDARD);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsXPIDLCString scheme;
+ PRBool isMailto = PR_FALSE;
+ if (actionURL && NS_FAILED(rv = actionURL->SchemeIs("mailto", &isMailto))) {
+ return rv;
+ }
+
+ if (isMailto) {
+ PRBool enabled;
+ rv = securityManager->IsCapabilityEnabled("UniversalSendMail", &enabled);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!enabled) {
+ // Form submit to a mailto: URI requires UniversalSendMail privilege
+ return NS_ERROR_DOM_SECURITY_ERR;
+ }
+ }
+
+ //
+ // Assign to the output
+ //
+ *aActionURL = actionURL;
+ NS_ADDREF(*aActionURL);
+
+ return rv;
+}
+
+
// nsIForm
NS_IMETHODIMP
diff --git a/mozilla/content/html/content/src/nsHTMLInputElement.cpp b/mozilla/content/html/content/src/nsHTMLInputElement.cpp
index 2cea3eb6912..990e6f68918 100644
--- a/mozilla/content/html/content/src/nsHTMLInputElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLInputElement.cpp
@@ -59,6 +59,7 @@
#include "nsIHTMLAttributes.h"
#include "nsIFormControl.h"
#include "nsIForm.h"
+#include "nsIFormSubmission.h"
#include "nsIGfxTextControlFrame.h"
#include "nsIDocument.h"
#include "nsIPresShell.h"
@@ -91,6 +92,14 @@
#include "nsRuleNode.h"
+// input type=file
+#include "nsIMIMEService.h"
+#include "nsCExternalHandlerService.h"
+#include "nsIFile.h"
+#include "nsILocalFile.h"
+#include "nsIFileStreams.h"
+
+
// XXX align=left, hspace, vspace, border? other nav4 attrs
static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
@@ -142,12 +151,8 @@ public:
// Overriden nsIFormControl methods
NS_IMETHOD GetType(PRInt32* aType);
NS_IMETHOD Reset();
- NS_IMETHOD IsSuccessful(nsIContent* aSubmitElement, PRBool *_retval);
- NS_IMETHOD GetMaxNumValues(PRInt32 *_retval);
- NS_IMETHOD GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames);
+ NS_IMETHOD SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement);
NS_IMETHOD SaveState(nsIPresContext* aPresContext, nsIPresState** aState);
NS_IMETHOD RestoreState(nsIPresContext* aPresContext, nsIPresState* aState);
@@ -218,8 +223,7 @@ public:
protected:
// Helper method
- void SetPresStateChecked(nsIHTMLContent * aHTMLContent,
- PRBool aValue);
+ void SetPresStateChecked(nsIHTMLContent * aHTMLContent, PRBool aValue);
NS_IMETHOD SetValueSecure(const nsAReadableString& aValue,
nsIGfxTextControlFrame2* aFrame,
PRBool aCheckSecurity);
@@ -244,6 +248,8 @@ protected:
void FireOnChange();
+ static nsresult GetContentType(const char* aPathName, char** aContentType);
+
nsCOMPtr mControllers;
PRInt8 mType;
@@ -1848,208 +1854,216 @@ nsHTMLInputElement::Reset()
return rv;
}
-nsresult
-nsHTMLInputElement::IsSuccessful(nsIContent* aSubmitElement,
- PRBool *_retval)
+NS_IMETHODIMP
+nsHTMLInputElement::SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement)
{
- *_retval = PR_FALSE;
+ nsresult rv = NS_OK;
- // if it's disabled, it won't submit
+ //
+ // Disabled elements don't submit
+ //
PRBool disabled;
- nsresult rv = GetDisabled(&disabled);
- if (disabled) {
- return NS_OK;
+ rv = GetDisabled(&disabled);
+ if (NS_FAILED(rv) || disabled) {
+ return rv;
}
+ //
+ // Get the type (many ops depend on the type)
+ //
PRInt32 type;
- GetType(&type);
+ rv = GetType(&type);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
- // if it dosn't have a name it we don't submit
- if (type != NS_FORM_INPUT_IMAGE) {
- nsAutoString val;
- rv = GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, val);
- if (rv == NS_CONTENT_ATTR_NOT_THERE) {
- return NS_OK;
+ //
+ // For type=reset, and type=button, we just never submit, period.
+ //
+ if (type == NS_FORM_INPUT_RESET || type == NS_FORM_INPUT_BUTTON) {
+ return rv;
+ }
+
+ //
+ // For type=image and type=button, we only submit if we were the button
+ // pressed
+ //
+ if ((type == NS_FORM_INPUT_SUBMIT || type == NS_FORM_INPUT_IMAGE)
+ && aSubmitElement != this) {
+ return rv;
+ }
+
+ //
+ // For type=radio and type=checkbox, we only submit if checked=true
+ //
+ if (type == NS_FORM_INPUT_RADIO || type == NS_FORM_INPUT_CHECKBOX) {
+ PRBool checked;
+ rv = GetChecked(&checked);
+ if (NS_FAILED(rv) || !checked) {
+ return rv;
}
}
- switch (type) {
- case NS_FORM_INPUT_CHECKBOX:
- case NS_FORM_INPUT_RADIO:
- {
- GetChecked(_retval);
- break;
- }
- case NS_FORM_INPUT_HIDDEN:
- case NS_FORM_INPUT_PASSWORD:
- case NS_FORM_INPUT_TEXT:
- case NS_FORM_INPUT_FILE:
- {
- *_retval = PR_TRUE;
- break;
- }
- case NS_FORM_INPUT_RESET:
- case NS_FORM_INPUT_BUTTON:
- {
- *_retval = PR_FALSE;
- break;
- }
- case NS_FORM_INPUT_SUBMIT:
- case NS_FORM_INPUT_IMAGE:
- {
- *_retval = (this == aSubmitElement);
- }
+ //
+ // Get the name
+ //
+ nsAutoString name;
+ rv = GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, name);
+ if (NS_FAILED(rv)) {
+ return rv;
}
+ PRBool nameThere = (rv != NS_CONTENT_ATTR_NOT_THERE);
- return NS_OK;
-}
-
-nsresult
-nsHTMLInputElement::GetMaxNumValues(PRInt32 *_retval)
-{
- PRInt32 type;
- GetType(&type);
+ //
+ // Submit .x, .y for input type=image
+ //
if (type == NS_FORM_INPUT_IMAGE) {
- nsAutoString name;
- nsAutoString value;
- GetName(name);
- GetValue(value);
- if (name.IsEmpty() || value.IsEmpty()) {
- *_retval = 2;
- } else {
- *_retval = 3;
- }
- } else {
- *_retval = 1;
- }
- return NS_OK;
-}
+ // Go to the frame to find out where it was clicked. This is the only
+ // case where I can actually see using the frame, because you're talking
+ // about a value--mouse click--that is rightfully the domain of the frame.
+ //
+ // If the frame isn't there or isn't an ImageControlFrame, then we're not
+ // submitting these values no matter *how* nicely you ask.
+ PRInt32 clickedX;
+ PRInt32 clickedY;
+ nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
-nsresult
-nsHTMLInputElement::GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames)
-{
- nsresult rv;
+ nsCOMPtr imageControlFrame(
+ do_QueryInterface(formControlFrame));
+ if (imageControlFrame) {
+ imageControlFrame->GetClickedX(&clickedX);
+ imageControlFrame->GetClickedY(&clickedY);
- PRInt32 type;
- GetType(&type);
-
- switch (type) {
- case NS_FORM_INPUT_CHECKBOX:
- case NS_FORM_INPUT_RADIO:
- {
- NS_ENSURE_TRUE(aMaxNumValues >= 1, NS_ERROR_UNEXPECTED);
-
- GetName(aNames[0]);
- GetValue(aValues[0]);
- aNumValues = 1;
-
- break;
- }
- case NS_FORM_INPUT_HIDDEN:
- case NS_FORM_INPUT_PASSWORD:
- case NS_FORM_INPUT_TEXT:
- {
- NS_ENSURE_TRUE(aMaxNumValues >= 1, NS_ERROR_UNEXPECTED);
-
- GetName(aNames[0]);
- GetValue(aValues[0]);
- aNumValues = 1;
-
- break;
- }
- case NS_FORM_INPUT_FILE:
- {
- NS_ENSURE_TRUE(aMaxNumValues >= 1, NS_ERROR_UNEXPECTED);
-
- GetName(aNames[0]);
- GetValue(aValues[0]);
- aNumValues = 1;
-
- break;
- }
- case NS_FORM_INPUT_IMAGE:
- {
- NS_ENSURE_TRUE(aMaxNumValues >= 2, NS_ERROR_UNEXPECTED);
-
- // Go to the frame to find out where it was clicked. This is the only
- // case where I can actually see using the frame, because you're talking
- // about a value--mouse click--that is rightfully the domain of the frame.
- //
- // If the frame isn't there or isn't an ImageControlFrame, then we're not
- // submitting these values no matter *how* nicely you ask.
- PRInt32 clickedX;
- PRInt32 clickedY;
- nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
-
- nsCOMPtr imageControlFrame(
- do_QueryInterface(formControlFrame));
- if (imageControlFrame) {
- imageControlFrame->GetClickedX(&clickedX);
- imageControlFrame->GetClickedY(&clickedY);
- } else {
- aNumValues = 0;
- return NS_OK;
- }
-
// Convert the values to strings for submission
char buf[20];
sprintf(&buf[0], "%d", clickedX);
- aValues[0].AssignWithConversion(&buf[0]);
+ nsAutoString xVal = NS_ConvertASCIItoUCS2(buf);
sprintf(&buf[0], "%d", clickedY);
- aValues[1].AssignWithConversion(&buf[0]);
-
- // Figure out the proper name of the x and y values
- nsAutoString name;
- rv = GetName(name);
+ nsAutoString yVal = NS_ConvertASCIItoUCS2(buf);
+
if (!name.IsEmpty()) {
- aNames[0] = name;
- aNames[0].Append(NS_LITERAL_STRING(".x"));
- aNames[1] = name;
- aNames[1].Append(NS_LITERAL_STRING(".y"));
- nsAutoString value;
- rv = GetValue(value);
- if (!value.IsEmpty()) {
- aNames[2] = name;
- aValues[2] = value;
- aNumValues = 3;
- } else {
- aNumValues = 2;
- }
+ aFormSubmission->AddNameValuePair(this,
+ name + NS_LITERAL_STRING(".x"), xVal);
+ aFormSubmission->AddNameValuePair(this,
+ name + NS_LITERAL_STRING(".y"), yVal);
} else {
// If the Image Element has no name, simply return x and y
// to Nav and IE compatability.
- aNames[0] = NS_LITERAL_STRING("x");
- aNames[1] = NS_LITERAL_STRING("y");
- aNumValues = 2;
+ aFormSubmission->AddNameValuePair(this, NS_LITERAL_STRING("x"), xVal);
+ aFormSubmission->AddNameValuePair(this, NS_LITERAL_STRING("y"), yVal);
}
-
- break;
- }
- case NS_FORM_INPUT_RESET:
- case NS_FORM_INPUT_BUTTON:
- {
- aNumValues = 0;
-
- break;
- }
- case NS_FORM_INPUT_SUBMIT:
- {
- NS_ENSURE_TRUE(aMaxNumValues >= 1, NS_ERROR_UNEXPECTED);
-
- GetName(aNames[0]);
- GetValue(aValues[0]);
- aNumValues = 1;
-
- break;
}
}
- return NS_OK;
+ //
+ // Submit name=value
+ //
+
+ // If name not there, don't submit
+ if (!nameThere) {
+ return rv;
+ }
+
+ // Get the value
+ nsAutoString value;
+ rv = GetValue(value);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ //
+ // Submit file if it's input type=file and this encoding method accepts files
+ //
+ PRBool submittedValue = PR_FALSE;
+ if (type == NS_FORM_INPUT_FILE) {
+
+ //
+ // Open the file
+ //
+ nsCOMPtr file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID,
+ &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = file->InitWithUnicodePath(value.get());
+ if (NS_SUCCEEDED(rv)) {
+
+ //
+ // Get the leaf path name (to be submitted as the value)
+ //
+ PRUnichar* leafNameChars = nsnull;
+ rv = file->GetUnicodeLeafName(&leafNameChars);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (leafNameChars) {
+ nsAutoString filename;
+ filename.Adopt(leafNameChars);
+
+ PRBool acceptsFiles = PR_FALSE;
+ aFormSubmission->AcceptsFiles(&acceptsFiles);
+
+ if (acceptsFiles) {
+ //
+ // Get content type
+ //
+ nsCOMPtr MIMEService =
+ do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ char * contentTypeChars = nsnull;
+ rv = MIMEService->GetTypeFromFile(file, &contentTypeChars);
+
+ nsCAutoString contentType;
+ if (contentTypeChars) {
+ contentType.Adopt(contentTypeChars);
+ } else {
+ contentType = NS_LITERAL_CSTRING("application/octet-stream");
+ }
+
+ //
+ // Get input stream
+ //
+ nsCOMPtr rawStream;
+ rv = NS_NewLocalFileInputStream(getter_AddRefs(rawStream), file);
+ if (rawStream) {
+ nsCOMPtr bufferedStream;
+ rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
+ rawStream, 8192);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ //
+ // Submit
+ //
+ aFormSubmission->AddNameFilePair(this, name, filename,
+ bufferedStream, contentType,
+ PR_FALSE);
+ submittedValue = PR_TRUE;
+ }
+ }
+
+ //
+ // If we don't submit as a file, at least submit the truncated filename.
+ //
+ if (!submittedValue) {
+ aFormSubmission->AddNameValuePair(this, name, filename);
+ submittedValue = PR_TRUE;
+ }
+ }
+ }
+ }
+
+ if (!submittedValue) {
+ // Submit
+ // (for type=image, only submit if value is non-null)
+ if (type != NS_FORM_INPUT_IMAGE || !value.IsEmpty()) {
+ rv = aFormSubmission->AddNameValuePair(this, name, value);
+ }
+ }
+
+ return rv;
}
+
NS_IMETHODIMP
nsHTMLInputElement::SaveState(nsIPresContext* aPresContext,
nsIPresState** aState)
@@ -2109,4 +2123,3 @@ nsHTMLInputElement::RestoreState(nsIPresContext* aPresContext,
return rv;
}
-
diff --git a/mozilla/content/html/content/src/nsHTMLLabelElement.cpp b/mozilla/content/html/content/src/nsHTMLLabelElement.cpp
index 75d3fafc1f2..96f6d5c99cc 100644
--- a/mozilla/content/html/content/src/nsHTMLLabelElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLLabelElement.cpp
@@ -172,12 +172,8 @@ public:
// nsIFormControl
NS_IMETHOD GetType(PRInt32* aType);
NS_IMETHOD Reset();
- NS_IMETHOD IsSuccessful(nsIContent* aSubmitElement, PRBool *_retval);
- NS_IMETHOD GetMaxNumValues(PRInt32 *_retval);
- NS_IMETHOD GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames);
+ NS_IMETHOD SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement);
// nsIContent
NS_IMETHOD HandleDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent,
@@ -420,27 +416,9 @@ nsHTMLLabelElement::Reset()
return NS_OK;
}
-nsresult
-nsHTMLLabelElement::IsSuccessful(nsIContent* aSubmitElement,
- PRBool *_retval)
+NS_IMETHODIMP
+nsHTMLLabelElement::SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement)
{
- *_retval = PR_FALSE;
- return NS_OK;
-}
-
-nsresult
-nsHTMLLabelElement::GetMaxNumValues(PRInt32 *_retval)
-{
- *_retval = 0;
- return NS_OK;
-}
-
-nsresult
-nsHTMLLabelElement::GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames)
-{
- aNumValues = 0;
return NS_OK;
}
diff --git a/mozilla/content/html/content/src/nsHTMLLegendElement.cpp b/mozilla/content/html/content/src/nsHTMLLegendElement.cpp
index 5247e8c4fc3..e1714d085d9 100644
--- a/mozilla/content/html/content/src/nsHTMLLegendElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLLegendElement.cpp
@@ -75,12 +75,8 @@ public:
// nsIFormControl
NS_IMETHOD GetType(PRInt32* aType);
NS_IMETHOD Reset();
- NS_IMETHOD IsSuccessful(nsIContent* aSubmitElement, PRBool *_retval);
- NS_IMETHOD GetMaxNumValues(PRInt32 *_retval);
- NS_IMETHOD GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames);
+ NS_IMETHOD SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement);
// nsIContent
NS_IMETHOD StringToAttribute(nsIAtom* aAttribute,
@@ -253,27 +249,9 @@ nsHTMLLegendElement::Reset()
return NS_OK;
}
-nsresult
-nsHTMLLegendElement::IsSuccessful(nsIContent* aSubmitElement,
- PRBool *_retval)
+NS_IMETHODIMP
+nsHTMLLegendElement::SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement)
{
- *_retval = PR_FALSE;
- return NS_OK;
-}
-
-nsresult
-nsHTMLLegendElement::GetMaxNumValues(PRInt32 *_retval)
-{
- *_retval = 0;
- return NS_OK;
-}
-
-nsresult
-nsHTMLLegendElement::GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames)
-{
- aNumValues = 0;
return NS_OK;
}
diff --git a/mozilla/content/html/content/src/nsHTMLSelectElement.cpp b/mozilla/content/html/content/src/nsHTMLSelectElement.cpp
index 6daf2cdda18..9f2656b19ca 100644
--- a/mozilla/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLSelectElement.cpp
@@ -52,6 +52,7 @@
#include "nsIPresContext.h"
#include "nsIHTMLAttributes.h"
#include "nsIForm.h"
+#include "nsIFormSubmission.h"
#include "nsIDOMHTMLCollection.h"
#include "nsIDOMHTMLOptionElement.h"
#include "nsIDOMHTMLOptGroupElement.h"
@@ -175,12 +176,8 @@ public:
// Overriden nsIFormControl methods
NS_IMETHOD GetType(PRInt32* aType);
NS_IMETHOD Reset();
- NS_IMETHOD IsSuccessful(nsIContent* aSubmitElement, PRBool *_retval);
- NS_IMETHOD GetMaxNumValues(PRInt32 *_retval);
- NS_IMETHOD GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames);
+ NS_IMETHOD SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement);
// nsISelectElement
NS_DECL_NSISELECTELEMENT
@@ -1977,59 +1974,36 @@ nsHTMLSelectElement::InitializeOption(nsIDOMHTMLOptionElement * aOption,
return NS_OK;
}
-// Since this is multivalued, IsSuccessful here only really says whether
-// we're *allowed* to submit options here. There still may be no successful
-// options and nothing will submit.
-nsresult
-nsHTMLSelectElement::IsSuccessful(nsIContent* aSubmitElement,
- PRBool *_retval)
+NS_IMETHODIMP
+nsHTMLSelectElement::SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement)
{
- // if it's disabled, it won't submit
- PRBool disabled;
- nsresult rv = GetDisabled(&disabled);
- NS_ENSURE_SUCCESS(rv, rv);
+ nsresult rv = NS_OK;
- if (disabled) {
- *_retval = PR_FALSE;
- return NS_OK;
+ //
+ // Disabled elements don't submit
+ //
+ PRBool disabled;
+ rv = GetDisabled(&disabled);
+ if (NS_FAILED(rv) || disabled) {
+ return rv;
}
- // If there is no name, it won't submit
- nsAutoString val;
- rv = GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, val);
- *_retval = rv != NS_CONTENT_ATTR_NOT_THERE;
-
- return NS_OK;
-}
-
-nsresult
-nsHTMLSelectElement::GetMaxNumValues(PRInt32 *_retval)
-{
- PRUint32 length;
- nsresult rv = GetLength(&length);
- NS_ENSURE_SUCCESS(rv, rv);
-
- *_retval = length;
-
- return NS_OK;
-}
-
-nsresult
-nsHTMLSelectElement::GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames)
-{
+ //
+ // Get the name (if no name, no submit)
+ //
nsAutoString name;
- nsresult rv = GetName(name);
-
- PRInt32 sentOptions = 0;
+ rv = GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, name);
+ if (NS_FAILED(rv) || rv == NS_CONTENT_ATTR_NOT_THERE) {
+ return rv;
+ }
+ //
+ // Submit
+ //
PRUint32 len;
GetLength(&len);
- // We loop through the cached list of selected items because it's
- // hella faster than looping through all options
for (PRUint32 optIndex = 0; optIndex < len; optIndex++) {
// Don't send disabled options
PRBool disabled;
@@ -2040,30 +2014,24 @@ nsHTMLSelectElement::GetNamesValues(PRInt32 aMaxNumValues,
nsCOMPtr option;
mOptions->ItemAsOption(optIndex, getter_AddRefs(option));
- if (option) {
- PRBool isSelected;
- rv = option->GetSelected(&isSelected);
- if (NS_FAILED(rv) || !isSelected) {
- continue;
- }
+ NS_ENSURE_TRUE(option, NS_ERROR_UNEXPECTED);
- nsCOMPtr optionElement = do_QueryInterface(option);
- if (optionElement) {
- nsAutoString value;
- rv = optionElement->GetValueOrText(value);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // If the value is not there
- if (sentOptions < aMaxNumValues) {
- aNames[sentOptions] = name;
- aValues[sentOptions] = value;
- sentOptions++;
- }
- }
+ PRBool isSelected;
+ rv = option->GetSelected(&isSelected);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!isSelected) {
+ continue;
}
- }
- aNumValues = sentOptions;
+ nsCOMPtr optionElement = do_QueryInterface(option);
+ NS_ENSURE_TRUE(optionElement, NS_ERROR_UNEXPECTED);
+
+ nsAutoString value;
+ rv = optionElement->GetValueOrText(value);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = aFormSubmission->AddNameValuePair(this, name, value);
+ }
return NS_OK;
}
diff --git a/mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp b/mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp
index fa3a2632d3f..c953ceb9f73 100644
--- a/mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -47,6 +47,7 @@
#include "nsIDOMHTMLFormElement.h"
#include "nsIFormControl.h"
#include "nsIForm.h"
+#include "nsIFormSubmission.h"
#include "nsIDOMEventReceiver.h"
#include "nsIHTMLContent.h"
#include "nsGenericHTMLElement.h"
@@ -106,12 +107,8 @@ public:
// nsIFormControl
NS_IMETHOD GetType(PRInt32* aType);
NS_IMETHOD Reset();
- NS_IMETHOD IsSuccessful(nsIContent* aSubmitElement, PRBool *_retval);
- NS_IMETHOD GetMaxNumValues(PRInt32 *_retval);
- NS_IMETHOD GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames);
+ NS_IMETHOD SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement);
NS_IMETHOD SaveState(nsIPresContext* aPresContext, nsIPresState** aState);
NS_IMETHOD RestoreState(nsIPresContext* aPresContext, nsIPresState* aState);
@@ -874,55 +871,48 @@ nsHTMLTextAreaElement::Reset()
return NS_OK;
}
-nsresult
-nsHTMLTextAreaElement::IsSuccessful(nsIContent* aSubmitElement,
- PRBool *_retval)
+NS_IMETHODIMP
+nsHTMLTextAreaElement::SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement)
{
- // if it's disabled, it won't submit
+ nsresult rv = NS_OK;
+
+ //
+ // Disabled elements don't submit
+ //
PRBool disabled;
- nsresult rv = GetDisabled(&disabled);
- if (disabled) {
- *_retval = PR_FALSE;
- return NS_OK;
+ rv = GetDisabled(&disabled);
+ if (NS_FAILED(rv) || disabled) {
+ return rv;
}
- // if it dosn't have a name it we don't submit
- nsAutoString val;
- rv = GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, val);
- *_retval = rv != NS_CONTENT_ATTR_NOT_THERE;
- return NS_OK;
-}
-
-nsresult
-nsHTMLTextAreaElement::GetMaxNumValues(PRInt32 *_retval)
-{
- *_retval = 1;
- return NS_OK;
-}
-
-nsresult
-nsHTMLTextAreaElement::GetNamesValues(PRInt32 aMaxNumValues,
- PRInt32& aNumValues,
- nsString* aValues,
- nsString* aNames)
-{
- NS_ENSURE_TRUE(aMaxNumValues >= 1, NS_ERROR_UNEXPECTED);
-
- // We'll of course use the name of the control for the submit
+ //
+ // Get the name (if no name, no submit)
+ //
nsAutoString name;
- nsresult rv = GetName(name);
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, name);
+ if (NS_FAILED(rv) || rv == NS_CONTENT_ATTR_NOT_THERE) {
+ return rv;
+ }
+ //
+ // Get the value
+ //
nsAutoString value;
rv = GetValue(value);
- NS_ENSURE_SUCCESS(rv, rv);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
- aNames[0] = name;
- aValues[0] = value;
- aNumValues = 1;
- return NS_OK;
+ //
+ // Submit
+ //
+ rv = aFormSubmission->AddNameValuePair(this, name, value);
+
+ return rv;
}
+
NS_IMETHODIMP
nsHTMLTextAreaElement::SaveState(nsIPresContext* aPresContext,
nsIPresState** aState)
diff --git a/mozilla/netwerk/base/public/MANIFEST_IDL b/mozilla/netwerk/base/public/MANIFEST_IDL
index 250f4e33aa3..92aa3e330bc 100644
--- a/mozilla/netwerk/base/public/MANIFEST_IDL
+++ b/mozilla/netwerk/base/public/MANIFEST_IDL
@@ -8,6 +8,7 @@ nsIChannel.idl
nsIFileChannel.idl
nsIDownloader.idl
nsIFileTransportService.idl
+nsIMIMEInputStream.idl
nsIPasswordManager.idl
nsIPrompt.idl
nsIProtocolProxyService.idl
diff --git a/mozilla/netwerk/base/public/Makefile.in b/mozilla/netwerk/base/public/Makefile.in
index 141cd85e500..26671b60599 100644
--- a/mozilla/netwerk/base/public/Makefile.in
+++ b/mozilla/netwerk/base/public/Makefile.in
@@ -38,6 +38,7 @@ XPIDLSRCS = \
nsIFileTransportService.idl \
nsIIOService.idl \
nsILoadGroup.idl \
+ nsIMIMEInputStream.idl \
nsINetModRegEntry.idl \
nsINetModuleMgr.idl \
nsINetNotify.idl \
diff --git a/mozilla/netwerk/base/public/makefile.win b/mozilla/netwerk/base/public/makefile.win
index 73678cfa35e..5624f0a02aa 100644
--- a/mozilla/netwerk/base/public/makefile.win
+++ b/mozilla/netwerk/base/public/makefile.win
@@ -40,6 +40,7 @@ XPIDLSRCS = \
.\nsIFileTransportService.idl \
.\nsIIOService.idl \
.\nsILoadGroup.idl \
+ .\nsIMIMEInputStream.idl \
.\nsINetModRegEntry.idl \
.\nsINetModuleMgr.idl \
.\nsINetNotify.idl \
diff --git a/mozilla/netwerk/base/public/nsIMIMEInputStream.idl b/mozilla/netwerk/base/public/nsIMIMEInputStream.idl
new file mode 100644
index 00000000000..b4594f7db6c
--- /dev/null
+++ b/mozilla/netwerk/base/public/nsIMIMEInputStream.idl
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is frightening to behold.
+ *
+ * The Initial Developer of the Original Code is
+ * Jonas Sicking.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Jonas Sicking
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIInputStream.idl"
+
+/**
+ * The MIME stream separates headers and a datastream. It also allows
+ * automatic creation of the content-length header.
+ */
+
+[scriptable, uuid(dcbce63c-1dd1-11b2-b94d-91f6d49a3161)]
+interface nsIMIMEInputStream : nsIInputStream
+{
+ /**
+ * When true a "Content-Length" header is automatically added to the
+ * stream. The value of the content-length is automatically calculated
+ * using the available() method on the data stream. The value is
+ * recalculated every time the stream is rewinded to the start.
+ * Not allowed to be changed once the stream has been started to be read.
+ */
+ attribute boolean addContentLength;
+
+ /**
+ * Adds an additional header to the stream on the form "name: value". May
+ * not be called once the stream has been started to be read.
+ * @param name name of the header
+ * @param value value of the header
+ */
+ void addHeader([const] in string name, [const] in string value);
+
+ /**
+ * Sets data-stream. May not be called once the stream has been started
+ * to be read.
+ * The cursor of the new stream should be located at the beginning of the
+ * stream if the implementation of the nsIMIMEInputStream also is used as
+ * an nsISeekableStream.
+ * @param stream stream containing the data for the stream
+ */
+ void setData(in nsIInputStream stream);
+};
diff --git a/mozilla/netwerk/base/src/Makefile.in b/mozilla/netwerk/base/src/Makefile.in
index 90c63bbeb48..39db20e021b 100644
--- a/mozilla/netwerk/base/src/Makefile.in
+++ b/mozilla/netwerk/base/src/Makefile.in
@@ -49,6 +49,7 @@ CPPSRCS = \
nsInputStreamChannel.cpp \
nsIOService.cpp \
nsLoadGroup.cpp \
+ nsMIMEInputStream.cpp \
nsNetModRegEntry.cpp \
nsNetModuleMgr.cpp \
nsProtocolProxyService.cpp \
diff --git a/mozilla/netwerk/base/src/makefile.win b/mozilla/netwerk/base/src/makefile.win
index ee4009e92ce..50a05bed6b5 100644
--- a/mozilla/netwerk/base/src/makefile.win
+++ b/mozilla/netwerk/base/src/makefile.win
@@ -54,6 +54,7 @@ CPP_OBJS = \
.\$(OBJDIR)\nsURLParsers.obj \
.\$(OBJDIR)\nsStandardURL.obj \
.\$(OBJDIR)\nsSimpleURI.obj \
+ .\$(OBJDIR)\nsMIMEInputStream.obj \
.\$(OBJDIR)\nsNetModuleMgr.obj \
.\$(OBJDIR)\nsNetModRegEntry.obj \
.\$(OBJDIR)\nsLoadGroup.obj \
diff --git a/mozilla/netwerk/base/src/nsBufferedStreams.cpp b/mozilla/netwerk/base/src/nsBufferedStreams.cpp
index 239def802d3..b756dde1068 100644
--- a/mozilla/netwerk/base/src/nsBufferedStreams.cpp
+++ b/mozilla/netwerk/base/src/nsBufferedStreams.cpp
@@ -251,8 +251,13 @@ nsBufferedInputStream::Close()
NS_IMETHODIMP
nsBufferedInputStream::Available(PRUint32 *result)
{
- *result = mFillPoint - mCursor;
- return NS_OK;
+ nsresult rv = NS_OK;
+ *result = 0;
+ if (mStream) {
+ rv = Source()->Available(result);
+ }
+ *result += (mFillPoint - mCursor);
+ return rv;
}
NS_IMETHODIMP
diff --git a/mozilla/netwerk/base/src/nsMIMEInputStream.cpp b/mozilla/netwerk/base/src/nsMIMEInputStream.cpp
new file mode 100644
index 00000000000..647e2f98a6d
--- /dev/null
+++ b/mozilla/netwerk/base/src/nsMIMEInputStream.cpp
@@ -0,0 +1,314 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is frightening to behold.
+ *
+ * The Initial Developer of the Original Code is
+ * Jonas Sicking.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Jonas Sicking
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * The MIME stream separates headers and a datastream. It also allows
+ * automatic creation of the content-length header.
+ */
+
+#include "nsCOMPtr.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIMultiplexInputStream.h"
+#include "nsIMIMEInputStream.h"
+#include "nsISeekableStream.h"
+#include "nsIStringStream.h"
+
+class nsMIMEInputStream : public nsIMIMEInputStream,
+ public nsISeekableStream
+{
+public:
+ nsMIMEInputStream();
+ virtual ~nsMIMEInputStream();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIINPUTSTREAM
+ NS_DECL_NSIMIMEINPUTSTREAM
+ NS_DECL_NSISEEKABLESTREAM
+
+ NS_METHOD Init();
+
+private:
+
+ void InitStreams();
+
+ struct ReadSegmentsState {
+ nsIInputStream* mThisStream;
+ nsWriteSegmentFun mWriter;
+ void* mClosure;
+ };
+ static NS_METHOD ReadSegCb(nsIInputStream* aIn, void* aClosure,
+ const char* aFromRawSegment, PRUint32 aToOffset,
+ PRUint32 aCount, PRUint32 *aWriteCount);
+
+ nsCString mHeaders;
+ nsCOMPtr mHeaderStream;
+
+ nsCString mContentLength;
+ nsCOMPtr mCLStream;
+
+ nsCOMPtr mData;
+ nsCOMPtr mStream;
+ PRPackedBool mAddContentLength;
+ PRPackedBool mStartedReading;
+};
+
+NS_IMPL_THREADSAFE_ISUPPORTS3(nsMIMEInputStream,
+ nsIMIMEInputStream,
+ nsIInputStream,
+ nsISeekableStream);
+
+nsMIMEInputStream::nsMIMEInputStream() : mAddContentLength(PR_FALSE),
+ mStartedReading(PR_FALSE)
+{
+ NS_INIT_ISUPPORTS();
+}
+
+nsMIMEInputStream::~nsMIMEInputStream()
+{
+}
+
+NS_METHOD nsMIMEInputStream::Init()
+{
+ nsresult rv = NS_OK;
+ mStream = do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1",
+ &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mHeaderStream = do_CreateInstance("@mozilla.org/io/string-input-stream;1",
+ &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ mCLStream = do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr headerStream = do_QueryInterface(mHeaderStream);
+ nsCOMPtr clStream = do_QueryInterface(mCLStream);
+ rv = mStream->AppendStream(headerStream);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = mStream->AppendStream(clStream);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
+
+/* attribute boolean addContentLength; */
+NS_IMETHODIMP
+nsMIMEInputStream::GetAddContentLength(PRBool *aAddContentLength)
+{
+ *aAddContentLength = mAddContentLength;
+ return NS_OK;
+}
+NS_IMETHODIMP
+nsMIMEInputStream::SetAddContentLength(PRBool aAddContentLength)
+{
+ NS_ENSURE_FALSE(mStartedReading, NS_ERROR_FAILURE);
+ mAddContentLength = aAddContentLength;
+ return NS_OK;
+}
+
+/* void addHeader ([const] in string name, [const] in string value); */
+NS_IMETHODIMP
+nsMIMEInputStream::AddHeader(const char *aName, const char *aValue)
+{
+ NS_ENSURE_FALSE(mStartedReading, NS_ERROR_FAILURE);
+ mHeaders.Append(aName);
+ mHeaders.Append(": ");
+ mHeaders.Append(aValue);
+ mHeaders.Append("\r\n");
+
+ // Just in case someone somehow uses our stream, lets at least
+ // let the stream have a valid pointer. The stream will be properly
+ // initialized in nsMIMEInputStream::InitStreams
+ mHeaderStream->ShareData(mHeaders.get(), 0);
+
+ return NS_OK;
+}
+
+/* void setData (in nsIInputStream stream); */
+NS_IMETHODIMP
+nsMIMEInputStream::SetData(nsIInputStream *aStream)
+{
+ NS_ENSURE_FALSE(mStartedReading, NS_ERROR_FAILURE);
+ // Remove the old stream if there is one
+ if (mData)
+ mStream->RemoveStream(2);
+
+ mData = aStream;
+ if (aStream)
+ mStream->AppendStream(mData);
+ return NS_OK;
+}
+
+// set up the internal streams
+void nsMIMEInputStream::InitStreams()
+{
+ NS_ASSERTION(!mStartedReading,
+ "Don't call initStreams twice without rewinding");
+
+ mStartedReading = PR_TRUE;
+
+ // We'll use the content-length stream to add the final \r\n
+ if (mAddContentLength && mData) {
+ PRUint32 cl;
+ mData->Available(&cl);
+ if (!cl) {
+ mContentLength = "\r\n";
+ }
+ else {
+ mContentLength = "Content-Length: ";
+ mContentLength.AppendInt((PRInt32)cl);
+ mContentLength.Append("\r\n\r\n");
+ }
+ }
+ else {
+ mContentLength = "\r\n";
+ }
+ mCLStream->ShareData(mContentLength.get(), -1);
+ mHeaderStream->ShareData(mHeaders.get(), -1);
+}
+
+
+
+#define INITSTREAMS \
+if (!mStartedReading) { \
+ InitStreams(); \
+}
+
+// Reset mStartedReading when Seek-ing to start
+NS_IMETHODIMP
+nsMIMEInputStream::Seek(PRInt32 whence, PRInt32 offset)
+{
+ nsresult rv;
+ nsCOMPtr stream = do_QueryInterface(mStream);
+ if (whence == NS_SEEK_SET && offset == 0) {
+ rv = stream->Seek(whence, offset);
+ if (NS_SUCCEEDED(rv))
+ mStartedReading = PR_FALSE;
+ }
+ else {
+ INITSTREAMS;
+ rv = stream->Seek(whence, offset);
+ }
+
+ return rv;
+}
+
+// Proxy ReadSegments since we need to be a good little nsIInputStream
+NS_IMETHODIMP nsMIMEInputStream::ReadSegments(nsWriteSegmentFun aWriter,
+ void *aClosure, PRUint32 aCount,
+ PRUint32 *_retval)
+{
+ INITSTREAMS;
+ ReadSegmentsState state;
+ state.mThisStream = this;
+ state.mWriter = aWriter;
+ state.mClosure = aClosure;
+ return mStream->ReadSegments(ReadSegCb, &state, aCount, _retval);
+}
+
+NS_METHOD
+nsMIMEInputStream::ReadSegCb(nsIInputStream* aIn, void* aClosure,
+ const char* aFromRawSegment,
+ PRUint32 aToOffset, PRUint32 aCount,
+ PRUint32 *aWriteCount)
+{
+ ReadSegmentsState* state = (ReadSegmentsState*)aClosure;
+ return (state->mWriter)(state->mThisStream,
+ state->mClosure,
+ aFromRawSegment,
+ aToOffset,
+ aCount,
+ aWriteCount);
+}
+
+/**
+ * Forward everything else to the mStream after calling InitStreams()
+ */
+
+// nsIInputStream
+NS_IMETHODIMP nsMIMEInputStream::Close(void) { INITSTREAMS; return mStream->Close(); }
+NS_IMETHODIMP nsMIMEInputStream::Available(PRUint32 *_retval) { INITSTREAMS; return mStream->Available(_retval); }
+NS_IMETHODIMP nsMIMEInputStream::Read(char * buf, PRUint32 count, PRUint32 *_retval) { INITSTREAMS; return mStream->Read(buf, count, _retval); }
+NS_IMETHODIMP nsMIMEInputStream::GetNonBlocking(PRBool *aNonBlocking) { INITSTREAMS; return mStream->GetNonBlocking(aNonBlocking); }
+NS_IMETHODIMP nsMIMEInputStream::GetObserver(nsIInputStreamObserver * *aObserver) { INITSTREAMS; return mStream->GetObserver(aObserver); }
+NS_IMETHODIMP nsMIMEInputStream::SetObserver(nsIInputStreamObserver * aObserver) { INITSTREAMS; return mStream->SetObserver(aObserver); }
+
+// nsISeekableStream
+NS_IMETHODIMP nsMIMEInputStream::Tell(PRUint32 *_retval)
+{
+ INITSTREAMS;
+ nsCOMPtr stream = do_QueryInterface(mStream);
+ return stream->Tell(_retval);
+}
+NS_IMETHODIMP nsMIMEInputStream::SetEOF(void) {
+ INITSTREAMS;
+ nsCOMPtr stream = do_QueryInterface(mStream);
+ return stream->SetEOF();
+}
+
+
+/**
+ * Factory method used by do_CreateInstance
+ */
+
+NS_METHOD
+nsMIMEInputStreamConstructor(nsISupports *outer, REFNSIID iid, void **result)
+{
+ *result = nsnull;
+
+ if (outer)
+ return NS_ERROR_NO_AGGREGATION;
+
+ nsMIMEInputStream *inst;
+ NS_NEWXPCOM(inst, nsMIMEInputStream);
+ if (!inst)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(inst);
+
+ nsresult rv = inst->Init();
+ if (NS_FAILED(rv)) {
+ NS_RELEASE(inst);
+ return rv;
+ }
+
+ rv = inst->QueryInterface(iid, result);
+ NS_RELEASE(inst);
+
+ return rv;
+}
diff --git a/mozilla/netwerk/base/src/nsMIMEInputStream.h b/mozilla/netwerk/base/src/nsMIMEInputStream.h
new file mode 100644
index 00000000000..fc58bc30d12
--- /dev/null
+++ b/mozilla/netwerk/base/src/nsMIMEInputStream.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is frightening to behold.
+ *
+ * The Initial Developer of the Original Code is
+ * Jonas Sicking.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Jonas Sicking
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * The MIME stream separates headers and a datastream. It also allows
+ * automatic creation of the content-length header.
+ */
+
+#ifndef _nsMIMEInputStream_h_
+#define _nsMIMEInputStream_h_
+
+#include "nsIMIMEInputStream.h"
+
+#define NS_MIMEINPUTSTREAM_CLASSNAME "nsMIMEInputStream"
+#define NS_MIMEINPUTSTREAM_CONTRACTID "@mozilla.org/network/mime-input-stream;1"
+#define NS_MIMEINPUTSTREAM_CID \
+{ /* 58a1c31c-1dd2-11b2-a3f6-d36949d48268 */ \
+ 0x58a1c31c, \
+ 0x1dd2, \
+ 0x11b2, \
+ {0xa3, 0xf6, 0xd3, 0x69, 0x49, 0xd4, 0x82, 0x68} \
+}
+
+extern NS_METHOD nsMIMEInputStreamConstructor(nsISupports *outer,
+ REFNSIID iid,
+ void **result);
+
+#endif // _nsMIMEInputStream_h_
diff --git a/mozilla/netwerk/build/nsNetModule.cpp b/mozilla/netwerk/build/nsNetModule.cpp
index 8f6e7c37221..a8390db7365 100644
--- a/mozilla/netwerk/build/nsNetModule.cpp
+++ b/mozilla/netwerk/build/nsNetModule.cpp
@@ -56,6 +56,7 @@
#include "nsAsyncStreamListener.h"
#include "nsFileStreams.h"
#include "nsBufferedStreams.h"
+#include "nsMIMEInputStream.h"
#include "nsProtocolProxyService.h"
#include "nsSOCKSSocketProvider.h"
#include "nsSOCKS4SocketProvider.h"
@@ -724,6 +725,10 @@ static const nsModuleComponentInfo gNetModuleInfo[] = {
NS_BUFFEREDOUTPUTSTREAM_CID,
NS_BUFFEREDOUTPUTSTREAM_CONTRACTID,
nsBufferedOutputStream::Create },
+ { NS_MIMEINPUTSTREAM_CLASSNAME,
+ NS_MIMEINPUTSTREAM_CID,
+ NS_MIMEINPUTSTREAM_CONTRACTID,
+ nsMIMEInputStreamConstructor },
{ "Protocol Proxy Service",
NS_PROTOCOLPROXYSERVICE_CID,
"@mozilla.org/network/protocol-proxy-service;1",
diff --git a/mozilla/netwerk/macbuild/netwerk.xml b/mozilla/netwerk/macbuild/netwerk.xml
index c6e49708bab..f4c191074bf 100644
--- a/mozilla/netwerk/macbuild/netwerk.xml
+++ b/mozilla/netwerk/macbuild/netwerk.xml
@@ -1058,6 +1058,13 @@
Text
Debug
+
+ Name
+ nsMIMEInputStream.cpp
+ MacOS
+ Text
+ Debug
+
Name
nsInputStreamChannel.cpp
@@ -1664,6 +1671,11 @@
nsLoadGroup.cpp
MacOS
+
+ Name
+ nsMIMEInputStream.cpp
+ MacOS
+
Name
nsInputStreamChannel.cpp
@@ -3056,6 +3068,13 @@
Text
Debug
+
+ Name
+ nsMIMEInputStream.cpp
+ MacOS
+ Text
+ Debug
+
Name
nsInputStreamChannel.cpp
@@ -3662,6 +3681,11 @@
nsLoadGroup.cpp
MacOS
+
+ Name
+ nsMIMEInputStream.cpp
+ MacOS
+
Name
nsInputStreamChannel.cpp
@@ -5054,6 +5078,13 @@
Text
Debug
+
+ Name
+ nsMIMEInputStream.cpp
+ MacOS
+ Text
+ Debug
+
Name
nsInputStreamChannel.cpp
@@ -5646,6 +5677,11 @@
nsLoadGroup.cpp
MacOS
+
+ Name
+ nsMIMEInputStream.cpp
+ MacOS
+
Name
nsInputStreamChannel.cpp
@@ -7028,6 +7064,13 @@
Text
Debug
+
+ Name
+ nsMIMEInputStream.cpp
+ MacOS
+ Text
+ Debug
+
Name
nsInputStreamChannel.cpp
@@ -7620,6 +7663,11 @@
nsLoadGroup.cpp
MacOS
+
+ Name
+ nsMIMEInputStream.cpp
+ MacOS
+
Name
nsInputStreamChannel.cpp
@@ -8080,6 +8128,12 @@
nsLoadGroup.cpp
MacOS
+
+ Necko.shlb
+ Name
+ nsMIMEInputStream.cpp
+ MacOS
+
Necko.shlb
Name
diff --git a/mozilla/netwerk/macbuild/netwerkIDL.xml b/mozilla/netwerk/macbuild/netwerkIDL.xml
index 063d07b766c..2b5c8ba1465 100644
--- a/mozilla/netwerk/macbuild/netwerkIDL.xml
+++ b/mozilla/netwerk/macbuild/netwerkIDL.xml
@@ -1414,6 +1414,13 @@
Text
+
+ Name
+ nsIMIMEInputStream.idl
+ MacOS
+ Text
+
+
Name
nsIResumableChannel.idl
@@ -1840,6 +1847,11 @@
nsIFileProtocolHandler.idl
MacOS
+
+ Name
+ nsIMIMEInputStream.idl
+ MacOS
+
Name
nsIResumableChannel.idl
@@ -3206,6 +3218,13 @@
Text
+
+ Name
+ nsIMIMEInputStream.idl
+ MacOS
+ Text
+
+
Name
nsIResumableChannel.idl
@@ -3627,6 +3646,11 @@
nsIFileProtocolHandler.idl
MacOS
+
+ Name
+ nsIMIMEInputStream.idl
+ MacOS
+
Name
nsIResumableChannel.idl
@@ -4004,6 +4028,12 @@
nsIUploadChannel.idl
MacOS
+
+ headers
+ Name
+ nsIMIMEInputStream.idl
+ MacOS
+
mimetype
diff --git a/mozilla/xpcom/build/nsXPComInit.cpp b/mozilla/xpcom/build/nsXPComInit.cpp
index 1203ff5430b..f8a14143e80 100644
--- a/mozilla/xpcom/build/nsXPComInit.cpp
+++ b/mozilla/xpcom/build/nsXPComInit.cpp
@@ -87,6 +87,7 @@
#include "nsDirectoryServiceDefs.h"
#include "nsICategoryManager.h"
#include "nsStringStream.h"
+#include "nsMultiplexInputStream.h"
#include "nsFastLoadService.h"
@@ -278,6 +279,7 @@ static const nsModuleComponentInfo components[] = {
COMPONENT(DIRECTORYITERATOR, nsDirectoryIteratorImpl::Create),
COMPONENT(STRINGINPUTSTREAM, nsStringInputStreamConstructor),
+ COMPONENT(MULTIPLEXINPUTSTREAM, nsMultiplexInputStreamConstructor),
COMPONENT(FASTLOADSERVICE, nsFastLoadService::Create),
COMPONENT(VARIANT, nsVariantConstructor),
diff --git a/mozilla/xpcom/io/MANIFEST_IDL b/mozilla/xpcom/io/MANIFEST_IDL
index 5b50c6846f3..17eac585b3e 100644
--- a/mozilla/xpcom/io/MANIFEST_IDL
+++ b/mozilla/xpcom/io/MANIFEST_IDL
@@ -10,6 +10,7 @@ nsIInputStream.idl
nsIInputStreamTee.idl
nsILineInputStream.idl
nsILocalFile.idl
+nsIMultiplexInputStream.idl
nsIObjectInputStream.idl
nsIObjectOutputStream.idl
nsIOutputStream.idl
diff --git a/mozilla/xpcom/io/Makefile.in b/mozilla/xpcom/io/Makefile.in
index 8c5002a0aee..f19ca9d0923 100644
--- a/mozilla/xpcom/io/Makefile.in
+++ b/mozilla/xpcom/io/Makefile.in
@@ -50,6 +50,7 @@ CPPSRCS = \
nsLinebreakConverter.cpp \
nsLocalFileCommon.cpp \
nsLocalFileUnicode.cpp \
+ nsMultiplexInputStream.cpp \
nsPipe2.cpp \
nsScriptableInputStream.cpp \
nsSegmentedBuffer.cpp \
@@ -119,6 +120,7 @@ XPIDLSRCS = \
nsIInputStreamTee.idl \
nsILineInputStream.idl \
nsILocalFile.idl \
+ nsIMultiplexInputStream.idl \
nsIObjectInputStream.idl \
nsIObjectOutputStream.idl \
nsIOutputStream.idl \
diff --git a/mozilla/xpcom/io/makefile.win b/mozilla/xpcom/io/makefile.win
index 15fbc3ae850..ce41b2cdd28 100644
--- a/mozilla/xpcom/io/makefile.win
+++ b/mozilla/xpcom/io/makefile.win
@@ -62,6 +62,7 @@ XPIDLSRCS = \
.\nsIInputStreamTee.idl \
.\nsILineInputStream.idl \
.\nsILocalFile.idl \
+ .\nsIMultiplexInputStream.idl \
.\nsIObjectInputStream.idl \
.\nsIObjectOutputStream.idl \
.\nsIOutputStream.idl \
@@ -97,6 +98,7 @@ CPP_OBJS = \
.\$(OBJDIR)\nsLinebreakConverter.obj \
.\$(OBJDIR)\nsLocalFileCommon.obj \
.\$(OBJDIR)\nsLocalFileWin.obj \
+ .\$(OBJDIR)\nsMultiplexInputStream.obj \
.\$(OBJDIR)\nsPipe2.obj \
.\$(OBJDIR)\nsScriptableInputStream.obj \
.\$(OBJDIR)\nsSegmentedBuffer.obj \
diff --git a/mozilla/xpcom/io/nsIMultiplexInputStream.idl b/mozilla/xpcom/io/nsIMultiplexInputStream.idl
new file mode 100644
index 00000000000..ec309ecd8ef
--- /dev/null
+++ b/mozilla/xpcom/io/nsIMultiplexInputStream.idl
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is frightening to behold.
+ *
+ * The Initial Developer of the Original Code is
+ * Jonas Sicking.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Jonas Sicking
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIInputStream.idl"
+
+/**
+ * The multiplex stream concatinates a list of input streams into a single
+ * stream.
+ */
+
+[scriptable, uuid(a076fd12-1dd1-11b2-b19a-d53b5dffaade)]
+interface nsIMultiplexInputStream : nsIInputStream
+{
+ /**
+ * Number of streams in this multiplex-stream
+ */
+ readonly attribute unsigned long count;
+
+ /**
+ * Appends a stream to the end of the streams. The cursor of the stream
+ * should be located at the beginning of the stream if the implementation
+ * of this nsIMultiplexInputStream also is used as an nsISeekableStream.
+ * @param stream stream to append
+ */
+ void appendStream(in nsIInputStream stream);
+
+ /**
+ * Insert a stream at specified index. If the cursor of this stream is at
+ * the beginning of the stream at index, the cursor will be placed at the
+ * beginning of the inserted stream instead.
+ * The cursor of the new stream should be located at the beginning of the
+ * stream if the implementation of this nsIMultiplexInputStream also is
+ * used as an nsISeekableStream.
+ * @param stream stream to insert
+ * @param index index to insert stream at, must be <= count
+ */
+ void insertStream(in nsIInputStream stream, in unsigned long index);
+
+ /**
+ * Remove stream at specified index. If this stream is the one currently
+ * being read the readcursor is moved to the beginning of the next
+ * stream
+ * @param index remove stream at this index, must be < count
+ */
+ void removeStream(in unsigned long index);
+
+ /**
+ * Get stream at specified index.
+ * @param index return stream at this index, must be < count
+ * @return stream at specified index
+ */
+ nsIInputStream getStream(in unsigned long index);
+};
diff --git a/mozilla/xpcom/io/nsMultiplexInputStream.cpp b/mozilla/xpcom/io/nsMultiplexInputStream.cpp
new file mode 100644
index 00000000000..f95f2dfaa07
--- /dev/null
+++ b/mozilla/xpcom/io/nsMultiplexInputStream.cpp
@@ -0,0 +1,393 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is frightening to behold.
+ *
+ * The Initial Developer of the Original Code is
+ * Jonas Sicking.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Jonas Sicking
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * The multiplex stream concatenates a list of input streams into a single
+ * stream.
+ */
+
+#include "nsMultiplexInputStream.h"
+#include "nsIMultiplexInputStream.h"
+#include "nsISeekableStream.h"
+#include "nsSupportsArray.h"
+
+class nsMultiplexInputStream : public nsIMultiplexInputStream,
+ public nsISeekableStream
+{
+public:
+ nsMultiplexInputStream();
+ virtual ~nsMultiplexInputStream();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIINPUTSTREAM
+ NS_DECL_NSIMULTIPLEXINPUTSTREAM
+ NS_DECL_NSISEEKABLESTREAM
+
+ static NS_METHOD Create(nsISupports *outer, REFNSIID iid, void **result);
+
+private:
+
+ struct ReadSegmentsState {
+ nsIInputStream* mThisStream;
+ PRUint32 mOffset;
+ nsWriteSegmentFun mWriter;
+ void* mClosure;
+ PRBool mDone;
+ };
+
+ static NS_METHOD ReadSegCb(nsIInputStream* aIn, void* aClosure,
+ const char* aFromRawSegment, PRUint32 aToOffset,
+ PRUint32 aCount, PRUint32 *aWriteCount);
+
+ nsSupportsArray mStreams;
+ PRUint32 mCurrentStream;
+ PRBool mStartedReadingCurrent;
+};
+
+
+NS_IMPL_THREADSAFE_ISUPPORTS3(nsMultiplexInputStream,
+ nsIMultiplexInputStream,
+ nsIInputStream,
+ nsISeekableStream);
+
+nsMultiplexInputStream::nsMultiplexInputStream()
+ : mCurrentStream(0),
+ mStartedReadingCurrent(PR_FALSE)
+{
+ NS_INIT_ISUPPORTS();
+}
+
+nsMultiplexInputStream::~nsMultiplexInputStream()
+{
+}
+
+/* readonly attribute unsigned long count; */
+NS_IMETHODIMP
+nsMultiplexInputStream::GetCount(PRUint32 *aCount)
+{
+ mStreams.Count(aCount);
+ return NS_OK;
+}
+
+/* void appendStream (in nsIInputStream stream); */
+NS_IMETHODIMP
+nsMultiplexInputStream::AppendStream(nsIInputStream *aStream)
+{
+ return mStreams.AppendElement(aStream);
+}
+
+/* void insertStream (in nsIInputStream stream, in unsigned long index); */
+NS_IMETHODIMP
+nsMultiplexInputStream::InsertStream(nsIInputStream *aStream, PRUint32 aIndex)
+{
+ nsresult rv = mStreams.InsertElementAt(aStream, aIndex);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (mCurrentStream > aIndex ||
+ (mCurrentStream == aIndex && mStartedReadingCurrent))
+ ++mCurrentStream;
+ return rv;
+}
+
+/* void removeStream (in unsigned long index); */
+NS_IMETHODIMP
+nsMultiplexInputStream::RemoveStream(PRUint32 aIndex)
+{
+ nsresult rv = mStreams.RemoveElementAt(aIndex);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (mCurrentStream > aIndex)
+ --mCurrentStream;
+ else if (mCurrentStream == aIndex)
+ mStartedReadingCurrent = PR_FALSE;
+
+ return rv;
+}
+
+/* nsIInputStream getStream (in unsigned long index); */
+NS_IMETHODIMP
+nsMultiplexInputStream::GetStream(PRUint32 aIndex, nsIInputStream **_retval)
+{
+ return mStreams.QueryElementAt(aIndex,
+ NS_GET_IID(nsIInputStream),
+ (void**)_retval);
+}
+
+/* void close (); */
+NS_IMETHODIMP
+nsMultiplexInputStream::Close()
+{
+ PRUint32 len, i;
+ nsresult rv = NS_OK;
+
+ mStreams.Count(&len);
+ for (i = 0; i < len; ++i) {
+ nsCOMPtr stream(do_QueryElementAt(&mStreams, i));
+ nsresult rv2 = stream->Close();
+ // We still want to close all streams, but we should return an error
+ if (NS_FAILED(rv2))
+ rv = rv2;
+ }
+ return rv;
+}
+
+/* unsigned long available (); */
+NS_IMETHODIMP
+nsMultiplexInputStream::Available(PRUint32 *_retval)
+{
+ nsresult rv;
+ PRUint32 i, len, avail = 0;
+
+ mStreams.Count(&len);
+ for (i = mCurrentStream; i < len; i++) {
+ nsCOMPtr stream(do_QueryElementAt(&mStreams, i));
+
+ PRUint32 streamAvail;
+ rv = stream->Available(&streamAvail);
+ NS_ENSURE_SUCCESS(rv, rv);
+ avail += streamAvail;
+ }
+ *_retval = avail;
+ return NS_OK;
+}
+
+/* [noscript] unsigned long read (in charPtr buf, in unsigned long count); */
+NS_IMETHODIMP
+nsMultiplexInputStream::Read(char * aBuf, PRUint32 aCount, PRUint32 *_retval)
+{
+ nsresult rv;
+ PRUint32 len;
+
+ mStreams.Count(&len);
+ PRUint32 read = 0;
+ while (mCurrentStream < len && aCount > 0) {
+ nsCOMPtr stream(do_QueryElementAt(&mStreams,
+ mCurrentStream));
+ rv = stream->Read(aBuf, aCount, _retval);
+ if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
+ *_retval = read;
+ return read == 0 ? NS_BASE_STREAM_WOULD_BLOCK : NS_OK;
+ }
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!*_retval) {
+ // we're done with this stream, proceed to next
+ ++mCurrentStream;
+ mStartedReadingCurrent = PR_FALSE;
+ }
+ else {
+ read += *_retval;
+ aBuf += *_retval;
+ aCount -= *_retval;
+ mStartedReadingCurrent = PR_TRUE;
+ }
+ }
+ *_retval = read;
+ return NS_OK;
+}
+
+/* [noscript] unsigned long readSegments (in nsWriteSegmentFun writer,
+ * in voidPtr closure,
+ * in unsigned long count); */
+NS_IMETHODIMP
+nsMultiplexInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure,
+ PRUint32 aCount, PRUint32 *_retval)
+{
+ NS_ASSERTION(aWriter, "missing aWriter");
+
+ nsresult rv;
+ ReadSegmentsState state;
+ state.mThisStream = this;
+ state.mOffset = 0;
+ state.mWriter = aWriter;
+ state.mClosure = aClosure;
+ state.mDone = PR_FALSE;
+
+ PRUint32 len;
+ mStreams.Count(&len);
+ while (mCurrentStream < len) {
+ nsCOMPtr stream(do_QueryElementAt(&mStreams,
+ mCurrentStream));
+ PRUint32 read;
+ rv = stream->ReadSegments(ReadSegCb, &state, aCount, &read);
+ // If we got an NS_BASE_STREAM_WOULD_BLOCK error since the reader
+ // didn't want any more data. This might not be an error for us if
+ // data was read from a previous stream in this run
+ if (state.mDone && rv == NS_BASE_STREAM_WOULD_BLOCK &&
+ !read && state.mOffset)
+ break;
+
+ NS_ENSURE_SUCCESS(rv, rv);
+ NS_ASSERTION(aCount >= read, "Read more then requested");
+ mStartedReadingCurrent = PR_TRUE;
+ state.mOffset += read;
+ aCount -= read;
+ if (state.mDone || !aCount)
+ break;
+
+ ++mCurrentStream;
+ mStartedReadingCurrent = PR_FALSE;
+ }
+ *_retval = state.mOffset;
+ return NS_OK;
+}
+
+NS_METHOD
+nsMultiplexInputStream::ReadSegCb(nsIInputStream* aIn, void* aClosure,
+ const char* aFromRawSegment,
+ PRUint32 aToOffset, PRUint32 aCount,
+ PRUint32 *aWriteCount)
+{
+ nsresult rv;
+ ReadSegmentsState* state = (ReadSegmentsState*)aClosure;
+ rv = (state->mWriter)(state->mThisStream,
+ state->mClosure,
+ aFromRawSegment,
+ aToOffset + state->mOffset,
+ aCount,
+ aWriteCount);
+ if (rv == NS_BASE_STREAM_WOULD_BLOCK ||
+ (NS_SUCCEEDED(rv) && *aWriteCount == 0 && aCount != 0))
+ state->mDone = PR_TRUE;
+
+ return rv;
+}
+
+/* readonly attribute boolean nonBlocking; */
+NS_IMETHODIMP
+nsMultiplexInputStream::GetNonBlocking(PRBool *aNonBlocking)
+{
+ nsresult rv;
+ PRUint32 i, len;
+
+ mStreams.Count(&len);
+ for (i = 0; i < len; ++i) {
+ nsCOMPtr stream(do_QueryElementAt(&mStreams, i));
+ rv = stream->GetNonBlocking(aNonBlocking);
+ NS_ENSURE_SUCCESS(rv, rv);
+ // If one is non-blocking the entire stream becomes non-blocking
+ if (*aNonBlocking)
+ return NS_OK;
+ }
+ return NS_OK;
+}
+
+/* attribute nsIInputStreamObserver observer; */
+NS_IMETHODIMP
+nsMultiplexInputStream::GetObserver(nsIInputStreamObserver * *aObserver)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP
+nsMultiplexInputStream::SetObserver(nsIInputStreamObserver * aObserver)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* void seek (in PRInt32 whence, in PRInt32 offset); */
+NS_IMETHODIMP
+nsMultiplexInputStream::Seek(PRInt32 aWhence, PRInt32 aOffset)
+{
+ nsresult rv;
+
+ // rewinding to start is easy, and should be the most common case
+ if (aWhence == NS_SEEK_SET && aOffset == 0)
+ {
+ PRUint32 i, last;
+ last = mStartedReadingCurrent ? mCurrentStream+1 : mCurrentStream;
+ for (i = 0; i < last; ++i) {
+ nsCOMPtr stream(do_QueryElementAt(&mStreams, i));
+ NS_ENSURE_TRUE(stream, NS_ERROR_NO_INTERFACE);
+
+ rv = stream->Seek(NS_SEEK_SET, 0);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ mCurrentStream = 0;
+ mStartedReadingCurrent = PR_FALSE;
+ return NS_OK;
+ }
+
+ // other Seeks not implemented yet
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+/* PRUint32 tell (); */
+NS_IMETHODIMP
+nsMultiplexInputStream::Tell(PRUint32 *_retval)
+{
+ nsresult rv;
+ *_retval = 0;
+ PRUint32 i, last;
+ last = mStartedReadingCurrent ? mCurrentStream+1 : mCurrentStream;
+ for (i = 0; i < last; ++i) {
+ nsCOMPtr stream(do_QueryElementAt(&mStreams, i));
+ NS_ENSURE_TRUE(stream, NS_ERROR_NO_INTERFACE);
+
+ PRUint32 pos;
+ rv = stream->Tell(&pos);
+ NS_ENSURE_SUCCESS(rv, rv);
+ *_retval += pos;
+ }
+ return NS_OK;
+}
+
+/* void setEOF (); */
+NS_IMETHODIMP
+nsMultiplexInputStream::SetEOF()
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_METHOD
+nsMultiplexInputStreamConstructor(nsISupports *outer,
+ REFNSIID iid,
+ void **result)
+{
+ *result = nsnull;
+
+ if (outer)
+ return NS_ERROR_NO_AGGREGATION;
+
+ nsMultiplexInputStream *inst;
+ NS_NEWXPCOM(inst, nsMultiplexInputStream);
+ if (!inst)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(inst);
+ nsresult rv = inst->QueryInterface(iid, result);
+ NS_RELEASE(inst);
+
+ return rv;
+}
diff --git a/mozilla/xpcom/io/nsMultiplexInputStream.h b/mozilla/xpcom/io/nsMultiplexInputStream.h
new file mode 100644
index 00000000000..32d3026de84
--- /dev/null
+++ b/mozilla/xpcom/io/nsMultiplexInputStream.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is frightening to behold.
+ *
+ * The Initial Developer of the Original Code is
+ * Jonas Sicking.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Jonas Sicking
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * The multiplex stream concatinates a list of input streams into a single
+ * stream.
+ */
+
+#ifndef _nsMultiplexInputStream_h_
+#define _nsMultiplexInputStream_h_
+
+#include "nsIMultiplexInputStream.h"
+
+#define NS_MULTIPLEXINPUTSTREAM_CLASSNAME "nsMultiplexInputStream"
+#define NS_MULTIPLEXINPUTSTREAM_CONTRACTID "@mozilla.org/io/multiplex-input-stream;1"
+#define NS_MULTIPLEXINPUTSTREAM_CID \
+{ /* 565e3a2c-1dd2-11b2-8da1-b4cef17e568d */ \
+ 0x565e3a2c, \
+ 0x1dd2, \
+ 0x11b2, \
+ {0x8d, 0xa1, 0xb4, 0xce, 0xf1, 0x7e, 0x56, 0x8d} \
+}
+
+extern NS_METHOD nsMultiplexInputStreamConstructor(nsISupports *outer,
+ REFNSIID iid,
+ void **result);
+
+#endif // _nsMultiplexInputStream_h_
diff --git a/mozilla/xpcom/macbuild/XPCOMIDL.xml b/mozilla/xpcom/macbuild/XPCOMIDL.xml
index 196a574e7c0..8bd805c00fa 100644
--- a/mozilla/xpcom/macbuild/XPCOMIDL.xml
+++ b/mozilla/xpcom/macbuild/XPCOMIDL.xml
@@ -1277,6 +1277,13 @@
Text
+
+ Name
+ nsIMultiplexInputStream.idl
+ MacOS
+ Text
+
+
@@ -1634,6 +1641,11 @@
nsIStringStream.idl
MacOS
+
+ Name
+ nsIMultiplexInputStream.idl
+ MacOS
+
@@ -2860,6 +2872,13 @@
Text
+
+ Name
+ nsIMultiplexInputStream.idl
+ MacOS
+ Text
+
+
@@ -3217,6 +3236,11 @@
nsIStringStream.idl
MacOS
+
+ Name
+ nsIMultiplexInputStream.idl
+ MacOS
+
@@ -3653,6 +3677,12 @@
nsIStringStream.idl
MacOS
+
+ headers
+ Name
+ nsIMultiplexInputStream.idl
+ MacOS
+
diff --git a/mozilla/xpcom/macbuild/xpcomPPC.xml b/mozilla/xpcom/macbuild/xpcomPPC.xml
index 147dda79637..9fe8e11577e 100644
--- a/mozilla/xpcom/macbuild/xpcomPPC.xml
+++ b/mozilla/xpcom/macbuild/xpcomPPC.xml
@@ -1709,6 +1709,13 @@
Text
Debug
+
+ Name
+ nsMultiplexInputStream.cpp
+ MacOS
+ Text
+ Debug
+
Name
nsMemoryImpl.cpp
@@ -2371,6 +2378,11 @@
nsLocalFileCommon.cpp
MacOS
+
+ Name
+ nsMultiplexInputStream.cpp
+ MacOS
+
Name
nsMemoryImpl.cpp
@@ -4161,6 +4173,13 @@
Text
Debug
+
+ Name
+ nsMultiplexInputStream.cpp
+ MacOS
+ Text
+ Debug
+
Name
nsMemoryImpl.cpp
@@ -4828,6 +4847,11 @@
nsLocalFileCommon.cpp
MacOS
+
+ Name
+ nsMultiplexInputStream.cpp
+ MacOS
+
Name
nsMemoryImpl.cpp
@@ -5466,6 +5490,12 @@
nsLocalFileCommon.cpp
MacOS
+
+ xpcom.shlb
+ Name
+ nsMultiplexInputStream.cpp
+ MacOS
+
xpcom.shlb
Name