From f495d0cc2ac5c95a4c90387d7aa9a493d3db8fea Mon Sep 17 00:00:00 2001 From: "jkeiser%netscape.com" Date: Sat, 16 Feb 2002 01:19:24 +0000 Subject: [PATCH] Form submission performance / maintability improvements (bug 120682) r=alexsavulov,r=sicking,sr=jst --- content/html/content/public/MANIFEST | 1 + content/html/content/public/Makefile.in | 1 + content/html/content/public/makefile.win | 1 + content/html/content/public/nsIFormControl.h | 24 +- .../html/content/public/nsIFormSubmission.h | 130 ++ content/html/content/src/Makefile.in | 2 +- content/html/content/src/makefile.win | 2 +- content/html/content/src/nsFormSubmission.cpp | 1014 +++++++++++ content/html/content/src/nsFormSubmitter.cpp | 1520 ----------------- content/html/content/src/nsFormSubmitter.h | 104 -- .../html/content/src/nsHTMLButtonElement.cpp | 85 +- .../content/src/nsHTMLFieldSetElement.cpp | 30 +- .../html/content/src/nsHTMLFormElement.cpp | 419 ++++- .../html/content/src/nsHTMLInputElement.cpp | 377 ++-- .../html/content/src/nsHTMLLabelElement.cpp | 32 +- .../html/content/src/nsHTMLLegendElement.cpp | 32 +- .../html/content/src/nsHTMLSelectElement.cpp | 110 +- .../content/src/nsHTMLTextAreaElement.cpp | 78 +- netwerk/base/public/MANIFEST_IDL | 1 + netwerk/base/public/Makefile.in | 1 + netwerk/base/public/makefile.win | 1 + netwerk/base/public/nsIMIMEInputStream.idl | 75 + netwerk/base/src/Makefile.in | 1 + netwerk/base/src/makefile.win | 1 + netwerk/base/src/nsBufferedStreams.cpp | 9 +- netwerk/base/src/nsMIMEInputStream.cpp | 314 ++++ netwerk/base/src/nsMIMEInputStream.h | 63 + netwerk/build/nsNetModule.cpp | 5 + netwerk/macbuild/netwerk.xml | 54 + netwerk/macbuild/netwerkIDL.xml | 30 + xpcom/build/nsXPComInit.cpp | 2 + xpcom/io/MANIFEST_IDL | 1 + xpcom/io/Makefile.in | 2 + xpcom/io/makefile.win | 2 + xpcom/io/nsIMultiplexInputStream.idl | 88 + xpcom/io/nsMultiplexInputStream.cpp | 393 +++++ xpcom/io/nsMultiplexInputStream.h | 63 + xpcom/macbuild/XPCOMIDL.xml | 30 + xpcom/macbuild/xpcomPPC.xml | 30 + 39 files changed, 3046 insertions(+), 2082 deletions(-) create mode 100644 content/html/content/public/nsIFormSubmission.h create mode 100644 content/html/content/src/nsFormSubmission.cpp delete mode 100644 content/html/content/src/nsFormSubmitter.cpp delete mode 100644 content/html/content/src/nsFormSubmitter.h create mode 100644 netwerk/base/public/nsIMIMEInputStream.idl create mode 100644 netwerk/base/src/nsMIMEInputStream.cpp create mode 100644 netwerk/base/src/nsMIMEInputStream.h create mode 100644 xpcom/io/nsIMultiplexInputStream.idl create mode 100644 xpcom/io/nsMultiplexInputStream.cpp create mode 100644 xpcom/io/nsMultiplexInputStream.h diff --git a/content/html/content/public/MANIFEST b/content/html/content/public/MANIFEST index 5a7b36f6fec1..a763d0e78ccd 100644 --- a/content/html/content/public/MANIFEST +++ b/content/html/content/public/MANIFEST @@ -3,6 +3,7 @@ # nsIForm.h nsIFormControl.h +nsIFormSubmission.h nsILink.h nsIOptionElement.h nsIScriptElement.h diff --git a/content/html/content/public/Makefile.in b/content/html/content/public/Makefile.in index 85d271d275a5..418a4eafde4b 100644 --- a/content/html/content/public/Makefile.in +++ b/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/content/html/content/public/makefile.win b/content/html/content/public/makefile.win index ee38ae56a8f2..19c256fcd774 100644 --- a/content/html/content/public/makefile.win +++ b/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/content/html/content/public/nsIFormControl.h b/content/html/content/public/nsIFormControl.h index 7176bdd7cfe7..c12270eaa6d0 100644 --- a/content/html/content/public/nsIFormControl.h +++ b/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/content/html/content/public/nsIFormSubmission.h b/content/html/content/public/nsIFormSubmission.h new file mode 100644 index 000000000000..56a5edd14554 --- /dev/null +++ b/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/content/html/content/src/Makefile.in b/content/html/content/src/Makefile.in index 39d06e8db9a2..5f8e5dee5642 100644 --- a/content/html/content/src/Makefile.in +++ b/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/content/html/content/src/makefile.win b/content/html/content/src/makefile.win index 30b13ae78a7c..548e4ab316fd 100644 --- a/content/html/content/src/makefile.win +++ b/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/content/html/content/src/nsFormSubmission.cpp b/content/html/content/src/nsFormSubmission.cpp new file mode 100644 index 000000000000..a340025b210f --- /dev/null +++ b/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/content/html/content/src/nsFormSubmitter.cpp b/content/html/content/src/nsFormSubmitter.cpp deleted file mode 100644 index 82471dd23ff7..000000000000 --- a/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/content/html/content/src/nsFormSubmitter.h b/content/html/content/src/nsFormSubmitter.h deleted file mode 100644 index e409b4a254b3..000000000000 --- a/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/content/html/content/src/nsHTMLButtonElement.cpp b/content/html/content/src/nsHTMLButtonElement.cpp index f467c09e9346..b7aa4fa7ffd2 100644 --- a/content/html/content/src/nsHTMLButtonElement.cpp +++ b/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/content/html/content/src/nsHTMLFieldSetElement.cpp b/content/html/content/src/nsHTMLFieldSetElement.cpp index f9a0f8d9d35d..212fbb490a76 100644 --- a/content/html/content/src/nsHTMLFieldSetElement.cpp +++ b/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/content/html/content/src/nsHTMLFormElement.cpp b/content/html/content/src/nsHTMLFormElement.cpp index 1b3e6467549e..afa7b4e619d0 100644 --- a/content/html/content/src/nsHTMLFormElement.cpp +++ b/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/content/html/content/src/nsHTMLInputElement.cpp b/content/html/content/src/nsHTMLInputElement.cpp index 2cea3eb69128..990e6f68918f 100644 --- a/content/html/content/src/nsHTMLInputElement.cpp +++ b/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/content/html/content/src/nsHTMLLabelElement.cpp b/content/html/content/src/nsHTMLLabelElement.cpp index 75d3fafc1f2c..96f6d5c99cc6 100644 --- a/content/html/content/src/nsHTMLLabelElement.cpp +++ b/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/content/html/content/src/nsHTMLLegendElement.cpp b/content/html/content/src/nsHTMLLegendElement.cpp index 5247e8c4fc3c..e1714d085d9b 100644 --- a/content/html/content/src/nsHTMLLegendElement.cpp +++ b/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/content/html/content/src/nsHTMLSelectElement.cpp b/content/html/content/src/nsHTMLSelectElement.cpp index 6daf2cdda181..9f2656b19ca4 100644 --- a/content/html/content/src/nsHTMLSelectElement.cpp +++ b/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/content/html/content/src/nsHTMLTextAreaElement.cpp b/content/html/content/src/nsHTMLTextAreaElement.cpp index fa3a2632d3fb..c953ceb9f73c 100644 --- a/content/html/content/src/nsHTMLTextAreaElement.cpp +++ b/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/netwerk/base/public/MANIFEST_IDL b/netwerk/base/public/MANIFEST_IDL index 250f4e33aa33..92aa3e330bc9 100644 --- a/netwerk/base/public/MANIFEST_IDL +++ b/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/netwerk/base/public/Makefile.in b/netwerk/base/public/Makefile.in index 141cd85e5009..26671b605999 100644 --- a/netwerk/base/public/Makefile.in +++ b/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/netwerk/base/public/makefile.win b/netwerk/base/public/makefile.win index 73678cfa35e4..5624f0a02aab 100644 --- a/netwerk/base/public/makefile.win +++ b/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/netwerk/base/public/nsIMIMEInputStream.idl b/netwerk/base/public/nsIMIMEInputStream.idl new file mode 100644 index 000000000000..b4594f7db6c0 --- /dev/null +++ b/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/netwerk/base/src/Makefile.in b/netwerk/base/src/Makefile.in index 90c63bbeb482..39db20e021b5 100644 --- a/netwerk/base/src/Makefile.in +++ b/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/netwerk/base/src/makefile.win b/netwerk/base/src/makefile.win index ee4009e92ce0..50a05bed6b55 100644 --- a/netwerk/base/src/makefile.win +++ b/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/netwerk/base/src/nsBufferedStreams.cpp b/netwerk/base/src/nsBufferedStreams.cpp index 239def802d3b..b756dde1068c 100644 --- a/netwerk/base/src/nsBufferedStreams.cpp +++ b/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/netwerk/base/src/nsMIMEInputStream.cpp b/netwerk/base/src/nsMIMEInputStream.cpp new file mode 100644 index 000000000000..647e2f98a6df --- /dev/null +++ b/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/netwerk/base/src/nsMIMEInputStream.h b/netwerk/base/src/nsMIMEInputStream.h new file mode 100644 index 000000000000..fc58bc30d12a --- /dev/null +++ b/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/netwerk/build/nsNetModule.cpp b/netwerk/build/nsNetModule.cpp index 8f6e7c372216..a8390db73658 100644 --- a/netwerk/build/nsNetModule.cpp +++ b/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/netwerk/macbuild/netwerk.xml b/netwerk/macbuild/netwerk.xml index c6e49708bab9..f4c191074bff 100644 --- a/netwerk/macbuild/netwerk.xml +++ b/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/netwerk/macbuild/netwerkIDL.xml b/netwerk/macbuild/netwerkIDL.xml index 063d07b766c9..2b5c8ba14652 100644 --- a/netwerk/macbuild/netwerkIDL.xml +++ b/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/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index 1203ff5430bd..f8a14143e800 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/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/xpcom/io/MANIFEST_IDL b/xpcom/io/MANIFEST_IDL index 5b50c6846f3e..17eac585b3ee 100644 --- a/xpcom/io/MANIFEST_IDL +++ b/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/xpcom/io/Makefile.in b/xpcom/io/Makefile.in index 8c5002a0aeec..f19ca9d09236 100644 --- a/xpcom/io/Makefile.in +++ b/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/xpcom/io/makefile.win b/xpcom/io/makefile.win index 15fbc3ae8507..ce41b2cdd280 100644 --- a/xpcom/io/makefile.win +++ b/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/xpcom/io/nsIMultiplexInputStream.idl b/xpcom/io/nsIMultiplexInputStream.idl new file mode 100644 index 000000000000..ec309ecd8ef1 --- /dev/null +++ b/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/xpcom/io/nsMultiplexInputStream.cpp b/xpcom/io/nsMultiplexInputStream.cpp new file mode 100644 index 000000000000..f95f2dfaa073 --- /dev/null +++ b/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/xpcom/io/nsMultiplexInputStream.h b/xpcom/io/nsMultiplexInputStream.h new file mode 100644 index 000000000000..32d3026de84c --- /dev/null +++ b/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/xpcom/macbuild/XPCOMIDL.xml b/xpcom/macbuild/XPCOMIDL.xml index 196a574e7c0c..8bd805c00fa6 100644 --- a/xpcom/macbuild/XPCOMIDL.xml +++ b/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/xpcom/macbuild/xpcomPPC.xml b/xpcom/macbuild/xpcomPPC.xml index 147dda796372..9fe8e11577e4 100644 --- a/xpcom/macbuild/xpcomPPC.xml +++ b/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