LCOV - code coverage report
Current view: directory - content/html/content/src - nsFormSubmission.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 357 0 0.0 %
Date: 2012-06-02 Functions: 32 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2                 :  *
       3                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla Communicator client code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "mozilla/Util.h"
      40                 : 
      41                 : #include "nsFormSubmission.h"
      42                 : 
      43                 : #include "nsCOMPtr.h"
      44                 : #include "nsIForm.h"
      45                 : #include "nsILinkHandler.h"
      46                 : #include "nsIDocument.h"
      47                 : #include "nsGkAtoms.h"
      48                 : #include "nsIHTMLDocument.h"
      49                 : #include "nsIFormControl.h"
      50                 : #include "nsIDOMHTMLFormElement.h"
      51                 : #include "nsDOMError.h"
      52                 : #include "nsGenericHTMLElement.h"
      53                 : #include "nsISaveAsCharset.h"
      54                 : #include "nsIFile.h"
      55                 : #include "nsIDOMFile.h"
      56                 : #include "nsDirectoryServiceDefs.h"
      57                 : #include "nsStringStream.h"
      58                 : #include "nsIURI.h"
      59                 : #include "nsIURL.h"
      60                 : #include "nsNetUtil.h"
      61                 : #include "nsLinebreakConverter.h"
      62                 : #include "nsICharsetConverterManager.h"
      63                 : #include "nsCharsetAlias.h"
      64                 : #include "nsEscape.h"
      65                 : #include "nsUnicharUtils.h"
      66                 : #include "nsIMultiplexInputStream.h"
      67                 : #include "nsIMIMEInputStream.h"
      68                 : #include "nsIMIMEService.h"
      69                 : #include "nsIConsoleService.h"
      70                 : #include "nsIScriptError.h"
      71                 : #include "nsIStringBundle.h"
      72                 : #include "nsCExternalHandlerService.h"
      73                 : #include "nsIFileStreams.h"
      74                 : #include "nsContentUtils.h"
      75                 : 
      76                 : using namespace mozilla;
      77                 : 
      78                 : static void
      79               0 : SendJSWarning(nsIDocument* aDocument,
      80                 :               const char* aWarningName,
      81                 :               const PRUnichar** aWarningArgs, PRUint32 aWarningArgsLen)
      82                 : {
      83                 :   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
      84                 :                                   "HTML", aDocument,
      85                 :                                   nsContentUtils::eFORMS_PROPERTIES,
      86                 :                                   aWarningName,
      87               0 :                                   aWarningArgs, aWarningArgsLen);
      88               0 : }
      89                 : 
      90                 : // --------------------------------------------------------------------------
      91                 : 
      92                 : class nsFSURLEncoded : public nsEncodingFormSubmission
      93               0 : {
      94                 : public:
      95                 :   /**
      96                 :    * @param aCharset the charset of the form as a string
      97                 :    * @param aMethod the method of the submit (either NS_FORM_METHOD_GET or
      98                 :    *        NS_FORM_METHOD_POST).
      99                 :    */
     100               0 :   nsFSURLEncoded(const nsACString& aCharset,
     101                 :                  PRInt32 aMethod,
     102                 :                  nsIDocument* aDocument,
     103                 :                  nsIContent* aOriginatingElement)
     104                 :     : nsEncodingFormSubmission(aCharset, aOriginatingElement),
     105                 :       mMethod(aMethod),
     106                 :       mDocument(aDocument),
     107               0 :       mWarnedFileControl(false)
     108                 :   {
     109               0 :   }
     110                 : 
     111                 :   virtual nsresult AddNameValuePair(const nsAString& aName,
     112                 :                                     const nsAString& aValue);
     113                 :   virtual nsresult AddNameFilePair(const nsAString& aName,
     114                 :                                    nsIDOMBlob* aBlob);
     115                 :   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
     116                 :                                         nsIInputStream** aPostDataStream);
     117                 : 
     118               0 :   virtual bool SupportsIsindexSubmission()
     119                 :   {
     120               0 :     return true;
     121                 :   }
     122                 : 
     123                 :   virtual nsresult AddIsindex(const nsAString& aValue);
     124                 : 
     125                 : protected:
     126                 : 
     127                 :   /**
     128                 :    * URL encode a Unicode string by encoding it to bytes, converting linebreaks
     129                 :    * properly, and then escaping many bytes as %xx.
     130                 :    *
     131                 :    * @param aStr the string to encode
     132                 :    * @param aEncoded the encoded string [OUT]
     133                 :    * @throws NS_ERROR_OUT_OF_MEMORY if we run out of memory
     134                 :    */
     135                 :   nsresult URLEncode(const nsAString& aStr, nsCString& aEncoded);
     136                 : 
     137                 : private:
     138                 :   /**
     139                 :    * The method of the submit (either NS_FORM_METHOD_GET or
     140                 :    * NS_FORM_METHOD_POST).
     141                 :    */
     142                 :   PRInt32 mMethod;
     143                 : 
     144                 :   /** The query string so far (the part after the ?) */
     145                 :   nsCString mQueryString;
     146                 : 
     147                 :   /** The document whose URI to use when reporting errors */
     148                 :   nsCOMPtr<nsIDocument> mDocument;
     149                 : 
     150                 :   /** Whether or not we have warned about a file control not being submitted */
     151                 :   bool mWarnedFileControl;
     152                 : };
     153                 : 
     154                 : nsresult
     155               0 : nsFSURLEncoded::AddNameValuePair(const nsAString& aName,
     156                 :                                  const nsAString& aValue)
     157                 : {
     158                 :   // Encode value
     159               0 :   nsCString convValue;
     160               0 :   nsresult rv = URLEncode(aValue, convValue);
     161               0 :   NS_ENSURE_SUCCESS(rv, rv);
     162                 : 
     163                 :   // Encode name
     164               0 :   nsCAutoString convName;
     165               0 :   rv = URLEncode(aName, convName);
     166               0 :   NS_ENSURE_SUCCESS(rv, rv);
     167                 : 
     168                 : 
     169                 :   // Append data to string
     170               0 :   if (mQueryString.IsEmpty()) {
     171               0 :     mQueryString += convName + NS_LITERAL_CSTRING("=") + convValue;
     172                 :   } else {
     173               0 :     mQueryString += NS_LITERAL_CSTRING("&") + convName
     174               0 :                   + NS_LITERAL_CSTRING("=") + convValue;
     175                 :   }
     176                 : 
     177               0 :   return NS_OK;
     178                 : }
     179                 : 
     180                 : nsresult
     181               0 : nsFSURLEncoded::AddIsindex(const nsAString& aValue)
     182                 : {
     183                 :   // Encode value
     184               0 :   nsCString convValue;
     185               0 :   nsresult rv = URLEncode(aValue, convValue);
     186               0 :   NS_ENSURE_SUCCESS(rv, rv);
     187                 : 
     188                 :   // Append data to string
     189               0 :   if (mQueryString.IsEmpty()) {
     190               0 :     mQueryString.Assign(convValue);
     191                 :   } else {
     192               0 :     mQueryString += NS_LITERAL_CSTRING("&isindex=") + convValue;
     193                 :   }
     194                 : 
     195               0 :   return NS_OK;
     196                 : }
     197                 : 
     198                 : nsresult
     199               0 : nsFSURLEncoded::AddNameFilePair(const nsAString& aName,
     200                 :                                 nsIDOMBlob* aBlob)
     201                 : {
     202               0 :   if (!mWarnedFileControl) {
     203               0 :     SendJSWarning(mDocument, "ForgotFileEnctypeWarning", nsnull, 0);
     204               0 :     mWarnedFileControl = true;
     205                 :   }
     206                 : 
     207               0 :   nsAutoString filename;
     208               0 :   nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
     209               0 :   if (file) {
     210               0 :     file->GetName(filename);
     211                 :   }
     212                 : 
     213               0 :   return AddNameValuePair(aName, filename);
     214                 : }
     215                 : 
     216                 : static void
     217               0 : HandleMailtoSubject(nsCString& aPath) {
     218                 : 
     219                 :   // Walk through the string and see if we have a subject already.
     220               0 :   bool hasSubject = false;
     221               0 :   bool hasParams = false;
     222               0 :   PRInt32 paramSep = aPath.FindChar('?');
     223               0 :   while (paramSep != kNotFound && paramSep < (PRInt32)aPath.Length()) {
     224               0 :     hasParams = true;
     225                 : 
     226                 :     // Get the end of the name at the = op.  If it is *after* the next &,
     227                 :     // assume that someone made a parameter without an = in it
     228               0 :     PRInt32 nameEnd = aPath.FindChar('=', paramSep+1);
     229               0 :     PRInt32 nextParamSep = aPath.FindChar('&', paramSep+1);
     230               0 :     if (nextParamSep == kNotFound) {
     231               0 :       nextParamSep = aPath.Length();
     232                 :     }
     233                 : 
     234                 :     // If the = op is after the &, this parameter is a name without value.
     235                 :     // If there is no = op, same thing.
     236               0 :     if (nameEnd == kNotFound || nextParamSep < nameEnd) {
     237               0 :       nameEnd = nextParamSep;
     238                 :     }
     239                 : 
     240               0 :     if (nameEnd != kNotFound) {
     241               0 :       if (Substring(aPath, paramSep+1, nameEnd-(paramSep+1)).
     242               0 :           LowerCaseEqualsLiteral("subject")) {
     243               0 :         hasSubject = true;
     244               0 :         break;
     245                 :       }
     246                 :     }
     247                 : 
     248               0 :     paramSep = nextParamSep;
     249                 :   }
     250                 : 
     251                 :   // If there is no subject, append a preformed subject to the mailto line
     252               0 :   if (!hasSubject) {
     253               0 :     if (hasParams) {
     254               0 :       aPath.Append('&');
     255                 :     } else {
     256               0 :       aPath.Append('?');
     257                 :     }
     258                 : 
     259                 :     // Get the default subject
     260               0 :     nsXPIDLString brandName;
     261                 :     nsresult rv =
     262                 :       nsContentUtils::GetLocalizedString(nsContentUtils::eBRAND_PROPERTIES,
     263               0 :                                          "brandShortName", brandName);
     264               0 :     if (NS_FAILED(rv))
     265                 :       return;
     266               0 :     const PRUnichar *formatStrings[] = { brandName.get() };
     267               0 :     nsXPIDLString subjectStr;
     268                 :     rv = nsContentUtils::FormatLocalizedString(
     269                 :                                            nsContentUtils::eFORMS_PROPERTIES,
     270                 :                                            "DefaultFormSubject",
     271                 :                                            formatStrings,
     272               0 :                                            subjectStr);
     273               0 :     if (NS_FAILED(rv))
     274                 :       return;
     275               0 :     aPath.AppendLiteral("subject=");
     276               0 :     nsCString subjectStrEscaped;
     277               0 :     aPath.Append(NS_EscapeURL(NS_ConvertUTF16toUTF8(subjectStr), esc_Query,
     278               0 :                               subjectStrEscaped));
     279                 :   }
     280                 : }
     281                 : 
     282                 : nsresult
     283               0 : nsFSURLEncoded::GetEncodedSubmission(nsIURI* aURI,
     284                 :                                      nsIInputStream** aPostDataStream)
     285                 : {
     286               0 :   nsresult rv = NS_OK;
     287                 : 
     288               0 :   *aPostDataStream = nsnull;
     289                 : 
     290               0 :   if (mMethod == NS_FORM_METHOD_POST) {
     291                 : 
     292               0 :     bool isMailto = false;
     293               0 :     aURI->SchemeIs("mailto", &isMailto);
     294               0 :     if (isMailto) {
     295                 : 
     296               0 :       nsCAutoString path;
     297               0 :       rv = aURI->GetPath(path);
     298               0 :       NS_ENSURE_SUCCESS(rv, rv);
     299                 : 
     300               0 :       HandleMailtoSubject(path);
     301                 : 
     302                 :       // Append the body to and force-plain-text args to the mailto line
     303               0 :       nsCString escapedBody;
     304               0 :       escapedBody.Adopt(nsEscape(mQueryString.get(), url_XAlphas));
     305                 : 
     306               0 :       path += NS_LITERAL_CSTRING("&force-plain-text=Y&body=") + escapedBody;
     307                 : 
     308               0 :       rv = aURI->SetPath(path);
     309                 : 
     310                 :     } else {
     311                 : 
     312               0 :       nsCOMPtr<nsIInputStream> dataStream;
     313                 :       // XXX We *really* need to either get the string to disown its data (and
     314                 :       // not destroy it), or make a string input stream that owns the CString
     315                 :       // that is passed to it.  Right now this operation does a copy.
     316               0 :       rv = NS_NewCStringInputStream(getter_AddRefs(dataStream), mQueryString);
     317               0 :       NS_ENSURE_SUCCESS(rv, rv);
     318                 : 
     319                 :       nsCOMPtr<nsIMIMEInputStream> mimeStream(
     320               0 :         do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv));
     321               0 :       NS_ENSURE_SUCCESS(rv, rv);
     322                 : 
     323                 : #ifdef SPECIFY_CHARSET_IN_CONTENT_TYPE
     324                 :       mimeStream->AddHeader("Content-Type",
     325                 :                             PromiseFlatString(
     326                 :                               "application/x-www-form-urlencoded; charset="
     327                 :                               + mCharset
     328                 :                             ).get());
     329                 : #else
     330               0 :       mimeStream->AddHeader("Content-Type",
     331               0 :                             "application/x-www-form-urlencoded");
     332                 : #endif
     333               0 :       mimeStream->SetAddContentLength(true);
     334               0 :       mimeStream->SetData(dataStream);
     335                 : 
     336               0 :       *aPostDataStream = mimeStream;
     337               0 :       NS_ADDREF(*aPostDataStream);
     338                 :     }
     339                 : 
     340                 :   } else {
     341                 :     // Get the full query string
     342                 :     bool schemeIsJavaScript;
     343               0 :     rv = aURI->SchemeIs("javascript", &schemeIsJavaScript);
     344               0 :     NS_ENSURE_SUCCESS(rv, rv);
     345               0 :     if (schemeIsJavaScript) {
     346               0 :       return NS_OK;
     347                 :     }
     348                 : 
     349               0 :     nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
     350               0 :     if (url) {
     351               0 :       url->SetQuery(mQueryString);
     352                 :     }
     353                 :     else {
     354               0 :       nsCAutoString path;
     355               0 :       rv = aURI->GetPath(path);
     356               0 :       NS_ENSURE_SUCCESS(rv, rv);
     357                 :       // Bug 42616: Trim off named anchor and save it to add later
     358               0 :       PRInt32 namedAnchorPos = path.FindChar('#');
     359               0 :       nsCAutoString namedAnchor;
     360               0 :       if (kNotFound != namedAnchorPos) {
     361               0 :         path.Right(namedAnchor, (path.Length() - namedAnchorPos));
     362               0 :         path.Truncate(namedAnchorPos);
     363                 :       }
     364                 : 
     365                 :       // Chop off old query string (bug 25330, 57333)
     366                 :       // Only do this for GET not POST (bug 41585)
     367               0 :       PRInt32 queryStart = path.FindChar('?');
     368               0 :       if (kNotFound != queryStart) {
     369               0 :         path.Truncate(queryStart);
     370                 :       }
     371                 : 
     372               0 :       path.Append('?');
     373                 :       // Bug 42616: Add named anchor to end after query string
     374               0 :       path.Append(mQueryString + namedAnchor);
     375                 : 
     376               0 :       aURI->SetPath(path);
     377                 :     }
     378                 :   }
     379                 : 
     380               0 :   return rv;
     381                 : }
     382                 : 
     383                 : // i18n helper routines
     384                 : nsresult
     385               0 : nsFSURLEncoded::URLEncode(const nsAString& aStr, nsCString& aEncoded)
     386                 : {
     387                 :   // convert to CRLF breaks
     388                 :   PRUnichar* convertedBuf =
     389               0 :     nsLinebreakConverter::ConvertUnicharLineBreaks(PromiseFlatString(aStr).get(),
     390                 :                                                    nsLinebreakConverter::eLinebreakAny,
     391               0 :                                                    nsLinebreakConverter::eLinebreakNet);
     392               0 :   NS_ENSURE_TRUE(convertedBuf, NS_ERROR_OUT_OF_MEMORY);
     393                 : 
     394               0 :   nsCAutoString encodedBuf;
     395               0 :   nsresult rv = EncodeVal(nsDependentString(convertedBuf), encodedBuf, false);
     396               0 :   nsMemory::Free(convertedBuf);
     397               0 :   NS_ENSURE_SUCCESS(rv, rv);
     398                 : 
     399               0 :   char* escapedBuf = nsEscape(encodedBuf.get(), url_XPAlphas);
     400               0 :   NS_ENSURE_TRUE(escapedBuf, NS_ERROR_OUT_OF_MEMORY);
     401               0 :   aEncoded.Adopt(escapedBuf);
     402                 : 
     403               0 :   return NS_OK;
     404                 : }
     405                 : 
     406                 : // --------------------------------------------------------------------------
     407                 : 
     408               0 : nsFSMultipartFormData::nsFSMultipartFormData(const nsACString& aCharset,
     409                 :                                              nsIContent* aOriginatingElement)
     410               0 :     : nsEncodingFormSubmission(aCharset, aOriginatingElement)
     411                 : {
     412                 :   mPostDataStream =
     413               0 :     do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
     414                 : 
     415               0 :   mBoundary.AssignLiteral("---------------------------");
     416               0 :   mBoundary.AppendInt(rand());
     417               0 :   mBoundary.AppendInt(rand());
     418               0 :   mBoundary.AppendInt(rand());
     419               0 : }
     420                 : 
     421               0 : nsFSMultipartFormData::~nsFSMultipartFormData()
     422                 : {
     423               0 :   NS_ASSERTION(mPostDataChunk.IsEmpty(), "Left unsubmitted data");
     424               0 : }
     425                 : 
     426                 : nsIInputStream*
     427               0 : nsFSMultipartFormData::GetSubmissionBody()
     428                 : {
     429                 :   // Finish data
     430               0 :   mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
     431               0 :                   + NS_LITERAL_CSTRING("--" CRLF);
     432                 : 
     433                 :   // Add final data input stream
     434               0 :   AddPostDataStream();
     435                 : 
     436               0 :   return mPostDataStream;
     437                 : }
     438                 : 
     439                 : nsresult
     440               0 : nsFSMultipartFormData::AddNameValuePair(const nsAString& aName,
     441                 :                                         const nsAString& aValue)
     442                 : {
     443               0 :   nsCString valueStr;
     444               0 :   nsCAutoString encodedVal;
     445               0 :   nsresult rv = EncodeVal(aValue, encodedVal, false);
     446               0 :   NS_ENSURE_SUCCESS(rv, rv);
     447                 : 
     448                 :   valueStr.Adopt(nsLinebreakConverter::
     449                 :                  ConvertLineBreaks(encodedVal.get(),
     450                 :                                    nsLinebreakConverter::eLinebreakAny,
     451               0 :                                    nsLinebreakConverter::eLinebreakNet));
     452                 : 
     453               0 :   nsCAutoString nameStr;
     454               0 :   rv = EncodeVal(aName, nameStr, true);
     455               0 :   NS_ENSURE_SUCCESS(rv, rv);
     456                 : 
     457                 :   // Make MIME block for name/value pair
     458                 : 
     459                 :   // XXX: name parameter should be encoded per RFC 2231
     460                 :   // RFC 2388 specifies that RFC 2047 be used, but I think it's not 
     461                 :   // consistent with MIME standard.
     462               0 :   mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
     463               0 :                  + NS_LITERAL_CSTRING(CRLF)
     464               0 :                  + NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
     465               0 :                  + nameStr + NS_LITERAL_CSTRING("\"" CRLF CRLF)
     466               0 :                  + valueStr + NS_LITERAL_CSTRING(CRLF);
     467                 : 
     468               0 :   return NS_OK;
     469                 : }
     470                 : 
     471                 : nsresult
     472               0 : nsFSMultipartFormData::AddNameFilePair(const nsAString& aName,
     473                 :                                        nsIDOMBlob* aBlob)
     474                 : {
     475                 :   // Encode the control name
     476               0 :   nsCAutoString nameStr;
     477               0 :   nsresult rv = EncodeVal(aName, nameStr, true);
     478               0 :   NS_ENSURE_SUCCESS(rv, rv);
     479                 : 
     480               0 :   nsCString filename, contentType;
     481               0 :   nsCOMPtr<nsIInputStream> fileStream;
     482               0 :   if (aBlob) {
     483                 :     // Get and encode the filename
     484               0 :     nsAutoString filename16;
     485               0 :     nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
     486               0 :     if (file) {
     487               0 :       rv = file->GetName(filename16);
     488               0 :       NS_ENSURE_SUCCESS(rv, rv);
     489                 :     }
     490                 : 
     491               0 :     if (filename16.IsEmpty()) {
     492               0 :       filename16.AssignLiteral("blob");
     493                 :     }
     494                 : 
     495               0 :     rv = EncodeVal(filename16, filename, true);
     496               0 :     NS_ENSURE_SUCCESS(rv, rv);
     497                 :   
     498                 :     // Get content type
     499               0 :     nsAutoString contentType16;
     500               0 :     rv = aBlob->GetType(contentType16);
     501               0 :     if (NS_FAILED(rv) || contentType16.IsEmpty()) {
     502               0 :       contentType16.AssignLiteral("application/octet-stream");
     503                 :     }
     504                 :     contentType.Adopt(nsLinebreakConverter::
     505               0 :                       ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16).get(),
     506                 :                                         nsLinebreakConverter::eLinebreakAny,
     507               0 :                                         nsLinebreakConverter::eLinebreakSpace));
     508                 :   
     509                 :     // Get input stream
     510               0 :     rv = aBlob->GetInternalStream(getter_AddRefs(fileStream));
     511               0 :     NS_ENSURE_SUCCESS(rv, rv);
     512               0 :     if (fileStream) {
     513                 :       // Create buffered stream (for efficiency)
     514               0 :       nsCOMPtr<nsIInputStream> bufferedStream;
     515               0 :       rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
     516               0 :                                      fileStream, 8192);
     517               0 :       NS_ENSURE_SUCCESS(rv, rv);
     518                 :   
     519               0 :       fileStream = bufferedStream;
     520                 :     }
     521                 :   }
     522                 :   else {
     523               0 :     contentType.AssignLiteral("application/octet-stream");
     524                 :   }
     525                 : 
     526                 :   //
     527                 :   // Make MIME block for name/value pair
     528                 :   //
     529                 :   // more appropriate than always using binary?
     530               0 :   mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
     531               0 :                  + NS_LITERAL_CSTRING(CRLF);
     532                 :   // XXX: name/filename parameter should be encoded per RFC 2231
     533                 :   // RFC 2388 specifies that RFC 2047 be used, but I think it's not 
     534                 :   // consistent with the MIME standard.
     535                 :   mPostDataChunk +=
     536               0 :          NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
     537               0 :        + nameStr + NS_LITERAL_CSTRING("\"; filename=\"")
     538               0 :        + filename + NS_LITERAL_CSTRING("\"" CRLF)
     539               0 :        + NS_LITERAL_CSTRING("Content-Type: ")
     540               0 :        + contentType + NS_LITERAL_CSTRING(CRLF CRLF);
     541                 : 
     542                 :   // Add the file to the stream
     543               0 :   if (fileStream) {
     544                 :     // We need to dump the data up to this point into the POST data stream here,
     545                 :     // since we're about to add the file input stream
     546               0 :     AddPostDataStream();
     547                 : 
     548               0 :     mPostDataStream->AppendStream(fileStream);
     549                 :   }
     550                 : 
     551                 :   // CRLF after file
     552               0 :   mPostDataChunk.AppendLiteral(CRLF);
     553                 : 
     554               0 :   return NS_OK;
     555                 : }
     556                 : 
     557                 : nsresult
     558               0 : nsFSMultipartFormData::GetEncodedSubmission(nsIURI* aURI,
     559                 :                                             nsIInputStream** aPostDataStream)
     560                 : {
     561                 :   nsresult rv;
     562                 : 
     563                 :   // Make header
     564                 :   nsCOMPtr<nsIMIMEInputStream> mimeStream
     565               0 :     = do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv);
     566               0 :   NS_ENSURE_SUCCESS(rv, rv);
     567                 : 
     568               0 :   nsCAutoString contentType;
     569               0 :   GetContentType(contentType);
     570               0 :   mimeStream->AddHeader("Content-Type", contentType.get());
     571               0 :   mimeStream->SetAddContentLength(true);
     572               0 :   mimeStream->SetData(GetSubmissionBody());
     573                 : 
     574               0 :   *aPostDataStream = mimeStream.forget().get();
     575                 : 
     576               0 :   return NS_OK;
     577                 : }
     578                 : 
     579                 : nsresult
     580               0 : nsFSMultipartFormData::AddPostDataStream()
     581                 : {
     582               0 :   nsresult rv = NS_OK;
     583                 :   
     584               0 :   nsCOMPtr<nsIInputStream> postDataChunkStream;
     585               0 :   rv = NS_NewCStringInputStream(getter_AddRefs(postDataChunkStream),
     586               0 :                                 mPostDataChunk);
     587               0 :   NS_ASSERTION(postDataChunkStream, "Could not open a stream for POST!");
     588               0 :   if (postDataChunkStream) {
     589               0 :     mPostDataStream->AppendStream(postDataChunkStream);
     590                 :   }
     591                 : 
     592               0 :   mPostDataChunk.Truncate();
     593                 : 
     594               0 :   return rv;
     595                 : }
     596                 : 
     597                 : // --------------------------------------------------------------------------
     598                 : 
     599                 : class nsFSTextPlain : public nsEncodingFormSubmission
     600               0 : {
     601                 : public:
     602               0 :   nsFSTextPlain(const nsACString& aCharset, nsIContent* aOriginatingElement)
     603               0 :     : nsEncodingFormSubmission(aCharset, aOriginatingElement)
     604                 :   {
     605               0 :   }
     606                 : 
     607                 :   virtual nsresult AddNameValuePair(const nsAString& aName,
     608                 :                                     const nsAString& aValue);
     609                 :   virtual nsresult AddNameFilePair(const nsAString& aName,
     610                 :                                    nsIDOMBlob* aBlob);
     611                 :   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
     612                 :                                         nsIInputStream** aPostDataStream);
     613                 : 
     614                 : private:
     615                 :   nsString mBody;
     616                 : };
     617                 : 
     618                 : nsresult
     619               0 : nsFSTextPlain::AddNameValuePair(const nsAString& aName,
     620                 :                                 const nsAString& aValue)
     621                 : {
     622                 :   // XXX This won't work well with a name like "a=b" or "a\nb" but I suppose
     623                 :   // text/plain doesn't care about that.  Parsers aren't built for escaped
     624                 :   // values so we'll have to live with it.
     625               0 :   mBody.Append(aName + NS_LITERAL_STRING("=") + aValue +
     626               0 :                NS_LITERAL_STRING(CRLF));
     627                 : 
     628               0 :   return NS_OK;
     629                 : }
     630                 : 
     631                 : nsresult
     632               0 : nsFSTextPlain::AddNameFilePair(const nsAString& aName,
     633                 :                                nsIDOMBlob* aBlob)
     634                 : {
     635               0 :   nsAutoString filename;
     636               0 :   nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
     637               0 :   if (file) {
     638               0 :     file->GetName(filename);
     639                 :   }
     640                 :     
     641               0 :   AddNameValuePair(aName, filename);
     642               0 :   return NS_OK;
     643                 : }
     644                 : 
     645                 : nsresult
     646               0 : nsFSTextPlain::GetEncodedSubmission(nsIURI* aURI,
     647                 :                                     nsIInputStream** aPostDataStream)
     648                 : {
     649               0 :   nsresult rv = NS_OK;
     650                 : 
     651                 :   // XXX HACK We are using the standard URL mechanism to give the body to the
     652                 :   // mailer instead of passing the post data stream to it, since that sounds
     653                 :   // hard.
     654               0 :   bool isMailto = false;
     655               0 :   aURI->SchemeIs("mailto", &isMailto);
     656               0 :   if (isMailto) {
     657               0 :     nsCAutoString path;
     658               0 :     rv = aURI->GetPath(path);
     659               0 :     NS_ENSURE_SUCCESS(rv, rv);
     660                 : 
     661               0 :     HandleMailtoSubject(path);
     662                 : 
     663                 :     // Append the body to and force-plain-text args to the mailto line
     664               0 :     char* escapedBuf = nsEscape(NS_ConvertUTF16toUTF8(mBody).get(),
     665               0 :                                 url_XAlphas);
     666               0 :     NS_ENSURE_TRUE(escapedBuf, NS_ERROR_OUT_OF_MEMORY);
     667               0 :     nsCString escapedBody;
     668               0 :     escapedBody.Adopt(escapedBuf);
     669                 : 
     670               0 :     path += NS_LITERAL_CSTRING("&force-plain-text=Y&body=") + escapedBody;
     671                 : 
     672               0 :     rv = aURI->SetPath(path);
     673                 : 
     674                 :   } else {
     675                 :     // Create data stream.
     676                 :     // We do want to send the data through the charset encoder and we want to
     677                 :     // normalize linebreaks to use the "standard net" format (\r\n), but we
     678                 :     // don't want to perform any other encoding. This means that names and
     679                 :     // values which contains '=' or newlines are potentially ambigiously
     680                 :     // encoded, but that how text/plain is specced.
     681               0 :     nsCString cbody;
     682               0 :     EncodeVal(mBody, cbody, false);
     683                 :     cbody.Adopt(nsLinebreakConverter::
     684                 :                 ConvertLineBreaks(cbody.get(),
     685                 :                                   nsLinebreakConverter::eLinebreakAny,
     686               0 :                                   nsLinebreakConverter::eLinebreakNet));
     687               0 :     nsCOMPtr<nsIInputStream> bodyStream;
     688               0 :     rv = NS_NewCStringInputStream(getter_AddRefs(bodyStream), cbody);
     689               0 :     if (!bodyStream) {
     690               0 :       return NS_ERROR_OUT_OF_MEMORY;
     691                 :     }
     692                 : 
     693                 :     // Create mime stream with headers and such
     694                 :     nsCOMPtr<nsIMIMEInputStream> mimeStream
     695               0 :         = do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv);
     696               0 :     NS_ENSURE_SUCCESS(rv, rv);
     697                 : 
     698               0 :     mimeStream->AddHeader("Content-Type", "text/plain");
     699               0 :     mimeStream->SetAddContentLength(true);
     700               0 :     mimeStream->SetData(bodyStream);
     701               0 :     CallQueryInterface(mimeStream, aPostDataStream);
     702                 :   }
     703                 : 
     704               0 :   return rv;
     705                 : }
     706                 : 
     707                 : // --------------------------------------------------------------------------
     708                 : 
     709               0 : nsEncodingFormSubmission::nsEncodingFormSubmission(const nsACString& aCharset,
     710                 :                                                    nsIContent* aOriginatingElement)
     711               0 :   : nsFormSubmission(aCharset, aOriginatingElement)
     712                 : {
     713               0 :   nsCAutoString charset(aCharset);
     714                 :   // canonical name is passed so that we just have to check against
     715                 :   // *our* canonical names listed in charsetaliases.properties
     716               0 :   if (charset.EqualsLiteral("ISO-8859-1")) {
     717               0 :     charset.AssignLiteral("windows-1252");
     718                 :   }
     719                 : 
     720               0 :   if (!(charset.EqualsLiteral("UTF-8") || charset.EqualsLiteral("gb18030"))) {
     721               0 :     NS_ConvertUTF8toUTF16 charsetUtf16(charset);
     722               0 :     const PRUnichar* charsetPtr = charsetUtf16.get();
     723               0 :     SendJSWarning(aOriginatingElement ? aOriginatingElement->GetOwnerDocument()
     724                 :                                       : nsnull,
     725                 :                   "CannotEncodeAllUnicode",
     726                 :                   &charsetPtr,
     727               0 :                   1);
     728                 :   }
     729                 : 
     730               0 :   mEncoder = do_CreateInstance(NS_SAVEASCHARSET_CONTRACTID);
     731               0 :   if (mEncoder) {
     732                 :     nsresult rv =
     733               0 :       mEncoder->Init(charset.get(),
     734                 :                      (nsISaveAsCharset::attr_EntityAfterCharsetConv + 
     735                 :                       nsISaveAsCharset::attr_FallbackDecimalNCR),
     736               0 :                      0);
     737               0 :     if (NS_FAILED(rv)) {
     738               0 :       mEncoder = nsnull;
     739                 :     }
     740                 :   }
     741               0 : }
     742                 : 
     743               0 : nsEncodingFormSubmission::~nsEncodingFormSubmission()
     744                 : {
     745               0 : }
     746                 : 
     747                 : // i18n helper routines
     748                 : nsresult
     749               0 : nsEncodingFormSubmission::EncodeVal(const nsAString& aStr, nsCString& aOut,
     750                 :                                     bool aHeaderEncode)
     751                 : {
     752               0 :   if (mEncoder && !aStr.IsEmpty()) {
     753               0 :     aOut.Truncate();
     754               0 :     nsresult rv = mEncoder->Convert(PromiseFlatString(aStr).get(),
     755               0 :                                     getter_Copies(aOut));
     756               0 :     NS_ENSURE_SUCCESS(rv, rv);
     757                 :   }
     758                 :   else {
     759                 :     // fall back to UTF-8
     760               0 :     CopyUTF16toUTF8(aStr, aOut);
     761                 :   }
     762                 : 
     763               0 :   if (aHeaderEncode) {
     764                 :     aOut.Adopt(nsLinebreakConverter::
     765                 :                ConvertLineBreaks(aOut.get(),
     766                 :                                  nsLinebreakConverter::eLinebreakAny,
     767               0 :                                  nsLinebreakConverter::eLinebreakSpace));
     768               0 :     aOut.ReplaceSubstring(NS_LITERAL_CSTRING("\""),
     769               0 :                           NS_LITERAL_CSTRING("\\\""));
     770                 :   }
     771                 : 
     772                 : 
     773               0 :   return NS_OK;
     774                 : }
     775                 : 
     776                 : // --------------------------------------------------------------------------
     777                 : 
     778                 : static void
     779               0 : GetSubmitCharset(nsGenericHTMLElement* aForm,
     780                 :                  nsACString& oCharset)
     781                 : {
     782               0 :   oCharset.AssignLiteral("UTF-8"); // default to utf-8
     783                 : 
     784               0 :   nsAutoString acceptCharsetValue;
     785                 :   aForm->GetAttr(kNameSpaceID_None, nsGkAtoms::acceptcharset,
     786               0 :                  acceptCharsetValue);
     787                 : 
     788               0 :   PRInt32 charsetLen = acceptCharsetValue.Length();
     789               0 :   if (charsetLen > 0) {
     790               0 :     PRInt32 offset=0;
     791               0 :     PRInt32 spPos=0;
     792                 :     // get charset from charsets one by one
     793               0 :     do {
     794               0 :       spPos = acceptCharsetValue.FindChar(PRUnichar(' '), offset);
     795               0 :       PRInt32 cnt = ((-1==spPos)?(charsetLen-offset):(spPos-offset));
     796               0 :       if (cnt > 0) {
     797               0 :         nsAutoString uCharset;
     798               0 :         acceptCharsetValue.Mid(uCharset, offset, cnt);
     799                 : 
     800               0 :         if (NS_SUCCEEDED(nsCharsetAlias::GetPreferred(NS_LossyConvertUTF16toASCII(uCharset),
     801                 :                                                       oCharset)))
     802                 :           return;
     803                 :       }
     804               0 :       offset = spPos + 1;
     805                 :     } while (spPos != -1);
     806                 :   }
     807                 :   // if there are no accept-charset or all the charset are not supported
     808                 :   // Get the charset from document
     809               0 :   nsIDocument* doc = aForm->GetDocument();
     810               0 :   if (doc) {
     811               0 :     oCharset = doc->GetDocumentCharacterSet();
     812                 :   }
     813                 : }
     814                 : 
     815                 : static void
     816               0 : GetEnumAttr(nsGenericHTMLElement* aContent,
     817                 :             nsIAtom* atom, PRInt32* aValue)
     818                 : {
     819               0 :   const nsAttrValue* value = aContent->GetParsedAttr(atom);
     820               0 :   if (value && value->Type() == nsAttrValue::eEnum) {
     821               0 :     *aValue = value->GetEnumValue();
     822                 :   }
     823               0 : }
     824                 : 
     825                 : nsresult
     826               0 : GetSubmissionFromForm(nsGenericHTMLElement* aForm,
     827                 :                       nsGenericHTMLElement* aOriginatingElement,
     828                 :                       nsFormSubmission** aFormSubmission)
     829                 : {
     830                 :   // Get all the information necessary to encode the form data
     831               0 :   NS_ASSERTION(aForm->GetCurrentDoc(),
     832                 :                "Should have doc if we're building submission!");
     833                 : 
     834                 :   // Get encoding type (default: urlencoded)
     835               0 :   PRInt32 enctype = NS_FORM_ENCTYPE_URLENCODED;
     836               0 :   if (aOriginatingElement &&
     837               0 :       aOriginatingElement->HasAttr(kNameSpaceID_None, nsGkAtoms::formenctype)) {
     838               0 :     GetEnumAttr(aOriginatingElement, nsGkAtoms::formenctype, &enctype);
     839                 :   } else {
     840               0 :     GetEnumAttr(aForm, nsGkAtoms::enctype, &enctype);
     841                 :   }
     842                 : 
     843                 :   // Get method (default: GET)
     844               0 :   PRInt32 method = NS_FORM_METHOD_GET;
     845               0 :   if (aOriginatingElement &&
     846               0 :       aOriginatingElement->HasAttr(kNameSpaceID_None, nsGkAtoms::formmethod)) {
     847               0 :     GetEnumAttr(aOriginatingElement, nsGkAtoms::formmethod, &method);
     848                 :   } else {
     849               0 :     GetEnumAttr(aForm, nsGkAtoms::method, &method);
     850                 :   }
     851                 : 
     852                 :   // Get charset
     853               0 :   nsCAutoString charset;
     854               0 :   GetSubmitCharset(aForm, charset);
     855                 : 
     856                 :   // We now have a canonical charset name, so we only have to check it
     857                 :   // against canonical names.
     858                 : 
     859                 :   // use UTF-8 for UTF-16* (per WHATWG and existing practice of
     860                 :   // MS IE/Opera).
     861               0 :   if (StringBeginsWith(charset, NS_LITERAL_CSTRING("UTF-16"))) {
     862               0 :     charset.AssignLiteral("UTF-8");
     863                 :   }
     864                 : 
     865                 :   // Choose encoder
     866               0 :   if (method == NS_FORM_METHOD_POST &&
     867                 :       enctype == NS_FORM_ENCTYPE_MULTIPART) {
     868               0 :     *aFormSubmission = new nsFSMultipartFormData(charset, aOriginatingElement);
     869               0 :   } else if (method == NS_FORM_METHOD_POST &&
     870                 :              enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
     871               0 :     *aFormSubmission = new nsFSTextPlain(charset, aOriginatingElement);
     872                 :   } else {
     873               0 :     nsIDocument* doc = aForm->OwnerDoc();
     874               0 :     if (enctype == NS_FORM_ENCTYPE_MULTIPART ||
     875                 :         enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
     876               0 :       nsAutoString enctypeStr;
     877               0 :       if (aOriginatingElement &&
     878                 :           aOriginatingElement->HasAttr(kNameSpaceID_None,
     879               0 :                                        nsGkAtoms::formenctype)) {
     880                 :         aOriginatingElement->GetAttr(kNameSpaceID_None, nsGkAtoms::formenctype,
     881               0 :                                      enctypeStr);
     882                 :       } else {
     883               0 :         aForm->GetAttr(kNameSpaceID_None, nsGkAtoms::enctype, enctypeStr);
     884                 :       }
     885               0 :       const PRUnichar* enctypeStrPtr = enctypeStr.get();
     886                 :       SendJSWarning(doc, "ForgotPostWarning",
     887               0 :                     &enctypeStrPtr, 1);
     888                 :     }
     889                 :     *aFormSubmission = new nsFSURLEncoded(charset, method, doc,
     890               0 :                                           aOriginatingElement);
     891                 :   }
     892               0 :   NS_ENSURE_TRUE(*aFormSubmission, NS_ERROR_OUT_OF_MEMORY);
     893                 : 
     894               0 :   return NS_OK;
     895                 : }

Generated by: LCOV version 1.7