2015-05-03 22:32:37 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
2012-05-21 15:12:37 +04:00
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2016-06-16 10:24:16 +03:00
|
|
|
#include "HTMLFormSubmission.h"
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2020-05-04 17:29:02 +03:00
|
|
|
#include "HTMLFormElement.h"
|
2002-02-16 04:19:24 +03:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsIForm.h"
|
2019-01-02 16:05:23 +03:00
|
|
|
#include "mozilla/dom/Document.h"
|
2006-12-26 20:47:52 +03:00
|
|
|
#include "nsGkAtoms.h"
|
2002-02-16 04:19:24 +03:00
|
|
|
#include "nsIFormControl.h"
|
2012-07-27 18:03:27 +04:00
|
|
|
#include "nsError.h"
|
2005-01-12 22:45:38 +03:00
|
|
|
#include "nsGenericHTMLElement.h"
|
2012-09-30 20:40:24 +04:00
|
|
|
#include "nsAttrValueInlines.h"
|
2002-02-16 04:19:24 +03:00
|
|
|
#include "nsDirectoryServiceDefs.h"
|
2006-01-02 05:30:32 +03:00
|
|
|
#include "nsStringStream.h"
|
2002-02-16 04:19:24 +03:00
|
|
|
#include "nsIURI.h"
|
2018-02-26 22:43:45 +03:00
|
|
|
#include "nsIURIMutator.h"
|
2007-09-06 08:29:17 +04:00
|
|
|
#include "nsIURL.h"
|
2002-02-16 04:19:24 +03:00
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsLinebreakConverter.h"
|
|
|
|
#include "nsEscape.h"
|
|
|
|
#include "nsUnicharUtils.h"
|
|
|
|
#include "nsIMultiplexInputStream.h"
|
|
|
|
#include "nsIMIMEInputStream.h"
|
2002-08-06 08:26:35 +04:00
|
|
|
#include "nsIScriptError.h"
|
2010-02-25 08:58:16 +03:00
|
|
|
#include "nsCExternalHandlerService.h"
|
2011-08-11 17:29:50 +04:00
|
|
|
#include "nsContentUtils.h"
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2016-05-13 14:11:38 +03:00
|
|
|
#include "mozilla/dom/Directory.h"
|
2015-01-29 04:04:28 +03:00
|
|
|
#include "mozilla/dom/File.h"
|
2019-07-26 04:10:23 +03:00
|
|
|
#include "mozilla/StaticPrefs_dom.h"
|
2020-01-13 23:41:14 +03:00
|
|
|
#include "mozilla/RandomNum.h"
|
2012-11-08 03:04:22 +04:00
|
|
|
|
2016-06-16 10:24:16 +03:00
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
2011-10-11 09:50:08 +04:00
|
|
|
|
2016-06-16 10:25:12 +03:00
|
|
|
namespace {
|
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
void SendJSWarning(Document* aDocument, const char* aWarningName,
|
2019-06-09 00:26:12 +03:00
|
|
|
const nsTArray<nsString>& aWarningArgs) {
|
|
|
|
nsContentUtils::ReportToConsole(
|
|
|
|
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("HTML"), aDocument,
|
|
|
|
nsContentUtils::eFORMS_PROPERTIES, aWarningName, aWarningArgs);
|
2010-02-25 08:58:17 +03:00
|
|
|
}
|
2002-08-06 08:26:35 +04:00
|
|
|
|
2016-01-20 20:25:03 +03:00
|
|
|
void RetrieveFileName(Blob* aBlob, nsAString& aFilename) {
|
2016-02-24 02:01:01 +03:00
|
|
|
if (!aBlob) {
|
|
|
|
return;
|
|
|
|
}
|
2016-01-20 20:25:03 +03:00
|
|
|
|
|
|
|
RefPtr<File> file = aBlob->ToFile();
|
|
|
|
if (file) {
|
|
|
|
file->GetName(aFilename);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-14 10:01:58 +03:00
|
|
|
void RetrieveDirectoryName(Directory* aDirectory, nsAString& aDirname) {
|
|
|
|
MOZ_ASSERT(aDirectory);
|
|
|
|
|
|
|
|
ErrorResult rv;
|
|
|
|
aDirectory->GetName(aDirname, rv);
|
|
|
|
if (NS_WARN_IF(rv.Failed())) {
|
|
|
|
rv.SuppressException();
|
|
|
|
aDirname.Truncate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-25 08:58:17 +03:00
|
|
|
// --------------------------------------------------------------------------
|
2002-08-06 08:26:35 +04:00
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
class FSURLEncoded : public EncodingFormSubmission {
|
2002-02-16 04:19:24 +03:00
|
|
|
public:
|
2002-06-12 11:39:08 +04:00
|
|
|
/**
|
2017-04-27 13:27:03 +03:00
|
|
|
* @param aEncoding the character encoding of the form
|
2002-06-12 11:39:08 +04:00
|
|
|
* @param aMethod the method of the submit (either NS_FORM_METHOD_GET or
|
|
|
|
* NS_FORM_METHOD_POST).
|
|
|
|
*/
|
2018-07-22 12:11:27 +03:00
|
|
|
FSURLEncoded(nsIURI* aActionURL, const nsAString& aTarget,
|
|
|
|
NotNull<const Encoding*> aEncoding, int32_t aMethod,
|
2020-02-11 15:46:57 +03:00
|
|
|
Document* aDocument, Element* aSubmitter)
|
|
|
|
: EncodingFormSubmission(aActionURL, aTarget, aEncoding, aSubmitter),
|
2017-04-27 13:27:03 +03:00
|
|
|
mMethod(aMethod),
|
|
|
|
mDocument(aDocument),
|
|
|
|
mWarnedFileControl(false) {}
|
2016-06-16 10:26:34 +03:00
|
|
|
|
|
|
|
virtual nsresult AddNameValuePair(const nsAString& aName,
|
|
|
|
const nsAString& aValue) override;
|
|
|
|
|
2016-07-14 10:01:31 +03:00
|
|
|
virtual nsresult AddNameBlobOrNullPair(const nsAString& aName,
|
|
|
|
Blob* aBlob) override;
|
|
|
|
|
2017-09-22 09:12:03 +03:00
|
|
|
virtual nsresult AddNameDirectoryPair(const nsAString& aName,
|
2018-05-23 08:12:36 +03:00
|
|
|
Directory* aDirectory) override;
|
2002-02-16 04:19:24 +03:00
|
|
|
|
|
|
|
virtual nsresult GetEncodedSubmission(nsIURI* aURI,
|
2017-09-22 09:12:03 +03:00
|
|
|
nsIInputStream** aPostDataStream,
|
2018-05-23 08:12:36 +03:00
|
|
|
nsCOMPtr<nsIURI>& aOutURI) override;
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2018-11-30 13:46:48 +03:00
|
|
|
protected:
|
2002-06-12 11:39:08 +04:00
|
|
|
/**
|
|
|
|
* URL encode a Unicode string by encoding it to bytes, converting linebreaks
|
|
|
|
* properly, and then escaping many bytes as %xx.
|
|
|
|
*
|
|
|
|
* @param aStr the string to encode
|
|
|
|
* @param aEncoded the encoded string [OUT]
|
2002-07-18 04:23:09 +04:00
|
|
|
* @throws NS_ERROR_OUT_OF_MEMORY if we run out of memory
|
2002-06-12 11:39:08 +04:00
|
|
|
*/
|
2016-05-13 23:48:03 +03:00
|
|
|
nsresult URLEncode(const nsAString& aStr, nsACString& aEncoded);
|
2002-02-16 04:19:24 +03:00
|
|
|
|
|
|
|
private:
|
2002-06-12 11:39:08 +04:00
|
|
|
/**
|
|
|
|
* The method of the submit (either NS_FORM_METHOD_GET or
|
|
|
|
* NS_FORM_METHOD_POST).
|
|
|
|
*/
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t mMethod;
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2002-06-12 11:39:08 +04:00
|
|
|
/** The query string so far (the part after the ?) */
|
2002-02-16 04:19:24 +03:00
|
|
|
nsCString mQueryString;
|
2002-08-06 08:26:35 +04:00
|
|
|
|
2010-02-25 08:58:16 +03:00
|
|
|
/** The document whose URI to use when reporting errors */
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> mDocument;
|
2010-02-25 08:58:16 +03:00
|
|
|
|
2002-08-06 08:26:35 +04:00
|
|
|
/** Whether or not we have warned about a file control not being submitted */
|
2011-09-29 10:19:26 +04:00
|
|
|
bool mWarnedFileControl;
|
2002-02-16 04:19:24 +03:00
|
|
|
};
|
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
nsresult FSURLEncoded::AddNameValuePair(const nsAString& aName,
|
|
|
|
const nsAString& aValue) {
|
2002-02-16 04:19:24 +03:00
|
|
|
// Encode value
|
|
|
|
nsCString convValue;
|
2010-02-25 08:58:16 +03:00
|
|
|
nsresult rv = URLEncode(aValue, convValue);
|
2002-07-18 04:23:09 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2005-07-13 20:55:59 +04:00
|
|
|
// Encode name
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString convName;
|
2005-07-13 20:55:59 +04:00
|
|
|
rv = URLEncode(aName, convName);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2002-02-16 04:19:24 +03:00
|
|
|
// Append data to string
|
2002-06-12 11:39:08 +04:00
|
|
|
if (mQueryString.IsEmpty()) {
|
2002-02-16 04:19:24 +03:00
|
|
|
mQueryString += convName + NS_LITERAL_CSTRING("=") + convValue;
|
|
|
|
} else {
|
|
|
|
mQueryString += NS_LITERAL_CSTRING("&") + convName +
|
|
|
|
NS_LITERAL_CSTRING("=") + convValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
nsresult FSURLEncoded::AddNameBlobOrNullPair(const nsAString& aName,
|
|
|
|
Blob* aBlob) {
|
2010-02-25 08:58:16 +03:00
|
|
|
if (!mWarnedFileControl) {
|
2019-06-09 00:26:12 +03:00
|
|
|
SendJSWarning(mDocument, "ForgotFileEnctypeWarning", nsTArray<nsString>());
|
2011-10-17 18:59:28 +04:00
|
|
|
mWarnedFileControl = true;
|
2010-02-25 08:58:16 +03:00
|
|
|
}
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2010-02-25 08:58:16 +03:00
|
|
|
nsAutoString filename;
|
2016-01-20 20:25:03 +03:00
|
|
|
RetrieveFileName(aBlob, filename);
|
2010-02-25 08:58:16 +03:00
|
|
|
return AddNameValuePair(aName, filename);
|
2002-02-16 04:19:24 +03:00
|
|
|
}
|
|
|
|
|
2016-07-14 10:01:31 +03:00
|
|
|
nsresult FSURLEncoded::AddNameDirectoryPair(const nsAString& aName,
|
|
|
|
Directory* aDirectory) {
|
2016-07-14 10:01:58 +03:00
|
|
|
// No warning about because Directory objects are never sent via form.
|
|
|
|
|
|
|
|
nsAutoString dirname;
|
|
|
|
RetrieveDirectoryName(aDirectory, dirname);
|
|
|
|
return AddNameValuePair(aName, dirname);
|
2016-07-14 10:01:31 +03:00
|
|
|
}
|
|
|
|
|
2016-06-16 10:25:12 +03:00
|
|
|
void HandleMailtoSubject(nsCString& aPath) {
|
2002-08-04 09:03:30 +04:00
|
|
|
// Walk through the string and see if we have a subject already.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool hasSubject = false;
|
|
|
|
bool hasParams = false;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t paramSep = aPath.FindChar('?');
|
|
|
|
while (paramSep != kNotFound && paramSep < (int32_t)aPath.Length()) {
|
2011-10-17 18:59:28 +04:00
|
|
|
hasParams = true;
|
2002-08-04 09:03:30 +04:00
|
|
|
|
|
|
|
// Get the end of the name at the = op. If it is *after* the next &,
|
|
|
|
// assume that someone made a parameter without an = in it
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t nameEnd = aPath.FindChar('=', paramSep + 1);
|
|
|
|
int32_t nextParamSep = aPath.FindChar('&', paramSep + 1);
|
2002-08-04 09:03:30 +04:00
|
|
|
if (nextParamSep == kNotFound) {
|
|
|
|
nextParamSep = aPath.Length();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the = op is after the &, this parameter is a name without value.
|
|
|
|
// If there is no = op, same thing.
|
|
|
|
if (nameEnd == kNotFound || nextParamSep < nameEnd) {
|
|
|
|
nameEnd = nextParamSep;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nameEnd != kNotFound) {
|
2007-02-28 07:57:13 +03:00
|
|
|
if (Substring(aPath, paramSep + 1, nameEnd - (paramSep + 1))
|
|
|
|
.LowerCaseEqualsLiteral("subject")) {
|
2011-10-17 18:59:28 +04:00
|
|
|
hasSubject = true;
|
2002-08-04 09:03:30 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
paramSep = nextParamSep;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there is no subject, append a preformed subject to the mailto line
|
|
|
|
if (!hasSubject) {
|
|
|
|
if (hasParams) {
|
|
|
|
aPath.Append('&');
|
|
|
|
} else {
|
|
|
|
aPath.Append('?');
|
|
|
|
}
|
|
|
|
|
2004-12-21 19:17:32 +03:00
|
|
|
// Get the default subject
|
2017-08-04 07:40:52 +03:00
|
|
|
nsAutoString brandName;
|
2005-04-03 21:16:28 +04:00
|
|
|
nsresult rv = nsContentUtils::GetLocalizedString(
|
|
|
|
nsContentUtils::eBRAND_PROPERTIES, "brandShortName", brandName);
|
|
|
|
if (NS_FAILED(rv)) return;
|
2017-08-04 07:40:52 +03:00
|
|
|
nsAutoString subjectStr;
|
2005-04-03 21:16:28 +04:00
|
|
|
rv = nsContentUtils::FormatLocalizedString(
|
2019-06-09 00:26:12 +03:00
|
|
|
subjectStr, nsContentUtils::eFORMS_PROPERTIES, "DefaultFormSubject",
|
|
|
|
brandName);
|
2005-04-03 21:16:28 +04:00
|
|
|
if (NS_FAILED(rv)) return;
|
2004-12-21 19:17:32 +03:00
|
|
|
aPath.AppendLiteral("subject=");
|
|
|
|
nsCString subjectStrEscaped;
|
2017-01-24 22:11:44 +03:00
|
|
|
rv = NS_EscapeURL(NS_ConvertUTF16toUTF8(subjectStr), esc_Query,
|
|
|
|
subjectStrEscaped, mozilla::fallible);
|
|
|
|
if (NS_FAILED(rv)) return;
|
|
|
|
|
|
|
|
aPath.Append(subjectStrEscaped);
|
2002-08-04 09:03:30 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
nsresult FSURLEncoded::GetEncodedSubmission(nsIURI* aURI,
|
2017-09-22 09:12:03 +03:00
|
|
|
nsIInputStream** aPostDataStream,
|
2018-02-26 22:43:45 +03:00
|
|
|
nsCOMPtr<nsIURI>& aOutURI) {
|
2002-02-16 04:19:24 +03:00
|
|
|
nsresult rv = NS_OK;
|
2018-02-26 22:43:45 +03:00
|
|
|
aOutURI = aURI;
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
*aPostDataStream = nullptr;
|
2002-02-16 04:19:24 +03:00
|
|
|
|
|
|
|
if (mMethod == NS_FORM_METHOD_POST) {
|
2019-08-02 11:54:18 +03:00
|
|
|
if (aURI->SchemeIs("mailto")) {
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString path;
|
2017-07-29 14:50:21 +03:00
|
|
|
rv = aURI->GetPathQueryRef(path);
|
2002-08-04 09:03:30 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
HandleMailtoSubject(path);
|
|
|
|
|
|
|
|
// Append the body to and force-plain-text args to the mailto line
|
2016-05-18 19:21:56 +03:00
|
|
|
nsAutoCString escapedBody;
|
|
|
|
if (NS_WARN_IF(!NS_Escape(mQueryString, escapedBody, url_XAlphas))) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2002-08-04 09:03:30 +04:00
|
|
|
|
|
|
|
path += NS_LITERAL_CSTRING("&force-plain-text=Y&body=") + escapedBody;
|
|
|
|
|
2018-02-26 22:43:45 +03:00
|
|
|
return NS_MutateURI(aURI).SetPathQueryRef(path).Finalize(aOutURI);
|
2002-08-04 09:03:30 +04:00
|
|
|
} else {
|
|
|
|
nsCOMPtr<nsIInputStream> dataStream;
|
2018-05-30 22:15:35 +03:00
|
|
|
rv = NS_NewCStringInputStream(getter_AddRefs(dataStream),
|
|
|
|
std::move(mQueryString));
|
2002-08-04 09:03:30 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2018-04-11 17:06:17 +03:00
|
|
|
mQueryString.Truncate();
|
2002-08-04 09:03:30 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsIMIMEInputStream> mimeStream(
|
|
|
|
do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2002-08-04 09:03:30 +04:00
|
|
|
mimeStream->AddHeader("Content-Type",
|
|
|
|
"application/x-www-form-urlencoded");
|
|
|
|
mimeStream->SetData(dataStream);
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2018-04-11 17:06:17 +03:00
|
|
|
mimeStream.forget(aPostDataStream);
|
2002-08-04 09:03:30 +04:00
|
|
|
}
|
2002-02-16 04:19:24 +03:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// Get the full query string
|
2019-08-02 11:54:18 +03:00
|
|
|
if (aURI->SchemeIs("javascript")) {
|
2002-02-16 04:19:24 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-09-06 08:29:17 +04:00
|
|
|
nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
|
|
|
|
if (url) {
|
2020-03-13 14:46:26 +03:00
|
|
|
// Make sure that we end up with a query component in the URL. If
|
|
|
|
// mQueryString is empty, nsIURI::SetQuery() will remove the query
|
|
|
|
// component, which is not what we want.
|
|
|
|
rv = NS_MutateURI(aURI)
|
|
|
|
.SetQuery(mQueryString.IsEmpty() ? NS_LITERAL_CSTRING("?")
|
|
|
|
: mQueryString)
|
|
|
|
.Finalize(aOutURI);
|
2007-09-06 08:29:17 +04:00
|
|
|
} else {
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString path;
|
2017-07-29 14:50:21 +03:00
|
|
|
rv = aURI->GetPathQueryRef(path);
|
2007-09-06 08:29:17 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// Bug 42616: Trim off named anchor and save it to add later
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t namedAnchorPos = path.FindChar('#');
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString namedAnchor;
|
2007-09-06 08:29:17 +04:00
|
|
|
if (kNotFound != namedAnchorPos) {
|
|
|
|
path.Right(namedAnchor, (path.Length() - namedAnchorPos));
|
|
|
|
path.Truncate(namedAnchorPos);
|
|
|
|
}
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2007-09-06 08:29:17 +04:00
|
|
|
// Chop off old query string (bug 25330, 57333)
|
|
|
|
// Only do this for GET not POST (bug 41585)
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t queryStart = path.FindChar('?');
|
2007-09-06 08:29:17 +04:00
|
|
|
if (kNotFound != queryStart) {
|
|
|
|
path.Truncate(queryStart);
|
|
|
|
}
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2007-09-06 08:29:17 +04:00
|
|
|
path.Append('?');
|
|
|
|
// Bug 42616: Add named anchor to end after query string
|
|
|
|
path.Append(mQueryString + namedAnchor);
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2018-02-26 22:43:45 +03:00
|
|
|
rv = NS_MutateURI(aURI).SetPathQueryRef(path).Finalize(aOutURI);
|
2007-09-06 08:29:17 +04:00
|
|
|
}
|
2002-02-16 04:19:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// i18n helper routines
|
2016-06-16 10:26:34 +03:00
|
|
|
nsresult FSURLEncoded::URLEncode(const nsAString& aStr, nsACString& aEncoded) {
|
2002-02-16 04:19:24 +03:00
|
|
|
// convert to CRLF breaks
|
2016-05-13 23:48:03 +03:00
|
|
|
int32_t convertedBufLength = 0;
|
|
|
|
char16_t* convertedBuf = nsLinebreakConverter::ConvertUnicharLineBreaks(
|
2005-07-13 20:55:59 +04:00
|
|
|
aStr.BeginReading(), nsLinebreakConverter::eLinebreakAny,
|
2016-05-13 23:48:03 +03:00
|
|
|
nsLinebreakConverter::eLinebreakNet, aStr.Length(), &convertedBufLength);
|
2005-07-13 20:55:59 +04:00
|
|
|
NS_ENSURE_TRUE(convertedBuf, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
2016-05-13 23:48:03 +03:00
|
|
|
nsAutoString convertedString;
|
|
|
|
convertedString.Adopt(convertedBuf, convertedBufLength);
|
|
|
|
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString encodedBuf;
|
2016-05-13 23:48:03 +03:00
|
|
|
nsresult rv = EncodeVal(convertedString, encodedBuf, false);
|
2005-07-13 20:55:59 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2016-05-13 23:48:03 +03:00
|
|
|
if (NS_WARN_IF(!NS_Escape(encodedBuf, aEncoded, url_XPAlphas))) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2002-07-18 04:23:09 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
2002-02-16 04:19:24 +03:00
|
|
|
}
|
|
|
|
|
2016-06-16 10:25:12 +03:00
|
|
|
} // anonymous namespace
|
|
|
|
|
2010-02-25 08:58:17 +03:00
|
|
|
// --------------------------------------------------------------------------
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2018-07-22 12:11:27 +03:00
|
|
|
FSMultipartFormData::FSMultipartFormData(nsIURI* aActionURL,
|
|
|
|
const nsAString& aTarget,
|
|
|
|
NotNull<const Encoding*> aEncoding,
|
2020-02-11 15:46:57 +03:00
|
|
|
Element* aSubmitter)
|
|
|
|
: EncodingFormSubmission(aActionURL, aTarget, aEncoding, aSubmitter) {
|
2010-02-25 08:58:16 +03:00
|
|
|
mPostData = do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
|
2017-09-19 17:26:21 +03:00
|
|
|
|
|
|
|
nsCOMPtr<nsIInputStream> inputStream = do_QueryInterface(mPostData);
|
|
|
|
MOZ_ASSERT(SameCOMIdentity(mPostData, inputStream));
|
|
|
|
mPostDataStream = inputStream;
|
|
|
|
|
2012-09-20 02:15:32 +04:00
|
|
|
mTotalLength = 0;
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2010-02-25 08:58:16 +03:00
|
|
|
mBoundary.AssignLiteral("---------------------------");
|
2020-01-13 23:41:14 +03:00
|
|
|
mBoundary.AppendInt(static_cast<uint32_t>(mozilla::RandomUint64OrDie()));
|
|
|
|
mBoundary.AppendInt(static_cast<uint32_t>(mozilla::RandomUint64OrDie()));
|
|
|
|
mBoundary.AppendInt(static_cast<uint32_t>(mozilla::RandomUint64OrDie()));
|
2002-07-18 04:23:09 +04:00
|
|
|
}
|
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
FSMultipartFormData::~FSMultipartFormData() {
|
2010-02-25 08:58:18 +03:00
|
|
|
NS_ASSERTION(mPostDataChunk.IsEmpty(), "Left unsubmitted data");
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
nsIInputStream* FSMultipartFormData::GetSubmissionBody(
|
|
|
|
uint64_t* aContentLength) {
|
2010-02-25 08:58:18 +03:00
|
|
|
// Finish data
|
|
|
|
mPostDataChunk +=
|
|
|
|
NS_LITERAL_CSTRING("--") + mBoundary + NS_LITERAL_CSTRING("--" CRLF);
|
|
|
|
|
|
|
|
// Add final data input stream
|
|
|
|
AddPostDataStream();
|
|
|
|
|
2012-09-20 02:15:32 +04:00
|
|
|
*aContentLength = mTotalLength;
|
2010-02-25 08:58:18 +03:00
|
|
|
return mPostDataStream;
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
nsresult FSMultipartFormData::AddNameValuePair(const nsAString& aName,
|
|
|
|
const nsAString& aValue) {
|
2002-07-18 04:23:09 +04:00
|
|
|
nsCString valueStr;
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString encodedVal;
|
2010-11-23 11:50:55 +03:00
|
|
|
nsresult rv = EncodeVal(aValue, encodedVal, false);
|
2010-02-25 08:58:16 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
valueStr.Adopt(nsLinebreakConverter::ConvertLineBreaks(
|
|
|
|
encodedVal.get(), nsLinebreakConverter::eLinebreakAny,
|
|
|
|
nsLinebreakConverter::eLinebreakNet));
|
|
|
|
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString nameStr;
|
2010-11-23 11:50:55 +03:00
|
|
|
rv = EncodeVal(aName, nameStr, true);
|
2002-07-18 04:23:09 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-02-16 04:19:24 +03:00
|
|
|
|
|
|
|
// Make MIME block for name/value pair
|
2010-02-25 08:58:17 +03:00
|
|
|
|
2005-07-13 20:55:59 +04:00
|
|
|
// XXX: name parameter should be encoded per RFC 2231
|
2016-02-24 02:01:01 +03:00
|
|
|
// RFC 2388 specifies that RFC 2047 be used, but I think it's not
|
2005-07-13 20:55:59 +04:00
|
|
|
// consistent with MIME standard.
|
2002-02-16 04:19:24 +03:00
|
|
|
mPostDataChunk +=
|
|
|
|
NS_LITERAL_CSTRING("--") + mBoundary + NS_LITERAL_CSTRING(CRLF) +
|
2007-10-25 02:21:01 +04:00
|
|
|
NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"") + nameStr +
|
|
|
|
NS_LITERAL_CSTRING("\"" CRLF CRLF) + valueStr + NS_LITERAL_CSTRING(CRLF);
|
2002-02-16 04:19:24 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
nsresult FSMultipartFormData::AddNameBlobOrNullPair(const nsAString& aName,
|
|
|
|
Blob* aBlob) {
|
2010-02-25 08:58:16 +03:00
|
|
|
// Encode the control name
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString nameStr;
|
2010-11-23 11:50:55 +03:00
|
|
|
nsresult rv = EncodeVal(aName, nameStr, true);
|
2002-07-18 04:23:09 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2016-07-14 10:01:58 +03:00
|
|
|
ErrorResult error;
|
|
|
|
|
|
|
|
uint64_t size = 0;
|
2016-02-24 02:01:01 +03:00
|
|
|
nsAutoCString filename;
|
|
|
|
nsAutoCString contentType;
|
|
|
|
nsCOMPtr<nsIInputStream> fileStream;
|
2016-02-23 20:38:16 +03:00
|
|
|
|
2016-02-24 02:01:01 +03:00
|
|
|
if (aBlob) {
|
|
|
|
nsAutoString filename16;
|
|
|
|
|
|
|
|
RefPtr<File> file = aBlob->ToFile();
|
|
|
|
if (file) {
|
2017-02-06 13:07:54 +03:00
|
|
|
nsAutoString relativePath;
|
|
|
|
file->GetRelativePath(relativePath);
|
2018-09-10 21:36:16 +03:00
|
|
|
if (StaticPrefs::dom_webkitBlink_dirPicker_enabled() &&
|
2017-02-06 13:07:54 +03:00
|
|
|
!relativePath.IsEmpty()) {
|
|
|
|
filename16 = relativePath;
|
2016-02-24 02:01:01 +03:00
|
|
|
}
|
2013-03-03 22:30:13 +04:00
|
|
|
|
2016-05-13 14:11:38 +03:00
|
|
|
if (filename16.IsEmpty()) {
|
|
|
|
RetrieveFileName(aBlob, filename16);
|
|
|
|
}
|
2016-02-24 02:01:01 +03:00
|
|
|
}
|
2011-06-29 22:03:36 +04:00
|
|
|
|
2016-02-24 02:01:01 +03:00
|
|
|
rv = EncodeVal(filename16, filename, true);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
Bug 1127150 - Use File's name instead of explicit file name in form submission related classes. r=baku
Our nsFormSubmission and subclasses accepted a third filename argument to
explicitly specify the filename. Since switching from nsIDOMBlob to File in Bug
1085283, we can read out the filename directly from the File. This simplifies
the code, but introduces a change in the way Firefox submits form data to
servers.
Consider the code:
var fd = new FormData();
fd.append("blob1", new Blob(["hi"]), ""); // explicit empty filename as third arg
fd.append("file1", new File(["hi"], "")); // File's name is empty, no third arg.
xhr.send(fd);
Previously, the request body had filename="" in the first case, and filename="blob" in the second.
This patch will change it to both cases result in filename=""
This behaviour isn't exactly specced anywhere, nor in the HTML spec [1], nor in
RFC 2388. In addition Blink (at least Chromium v40) has the same behaviour
introduced by this patch. So shipping it seems ok to me.
[1]: http://www.w3.org/html/wg/drafts/html/master/semantics.html#multipart/form-data-encoding-algorithm
--HG--
extra : rebase_source : 6631e6900fe1a9b991c397b76e5be6b913715c5a
2015-02-21 22:54:44 +03:00
|
|
|
|
2016-02-24 02:01:01 +03:00
|
|
|
// Get content type
|
|
|
|
nsAutoString contentType16;
|
|
|
|
aBlob->GetType(contentType16);
|
|
|
|
if (contentType16.IsEmpty()) {
|
|
|
|
contentType16.AssignLiteral("application/octet-stream");
|
|
|
|
}
|
2015-05-19 17:36:37 +03:00
|
|
|
|
2016-02-24 02:01:01 +03:00
|
|
|
contentType.Adopt(nsLinebreakConverter::ConvertLineBreaks(
|
|
|
|
NS_ConvertUTF16toUTF8(contentType16).get(),
|
|
|
|
nsLinebreakConverter::eLinebreakAny,
|
|
|
|
nsLinebreakConverter::eLinebreakSpace));
|
2013-03-03 22:30:13 +04:00
|
|
|
|
2016-02-24 02:01:01 +03:00
|
|
|
// Get input stream
|
2017-10-02 14:53:12 +03:00
|
|
|
aBlob->CreateInputStream(getter_AddRefs(fileStream), error);
|
2016-02-24 02:01:01 +03:00
|
|
|
if (NS_WARN_IF(error.Failed())) {
|
|
|
|
return error.StealNSResult();
|
|
|
|
}
|
2016-01-08 11:35:30 +03:00
|
|
|
|
2016-07-14 10:01:58 +03:00
|
|
|
// Get size
|
|
|
|
size = aBlob->GetSize(error);
|
|
|
|
if (error.Failed()) {
|
|
|
|
error.SuppressException();
|
|
|
|
fileStream = nullptr;
|
|
|
|
}
|
|
|
|
|
2016-02-24 02:01:01 +03:00
|
|
|
if (fileStream) {
|
|
|
|
// Create buffered stream (for efficiency)
|
|
|
|
nsCOMPtr<nsIInputStream> bufferedStream;
|
|
|
|
rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
|
2017-10-19 12:39:30 +03:00
|
|
|
fileStream.forget(), 8192);
|
2016-02-24 02:01:01 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2016-01-08 11:35:30 +03:00
|
|
|
|
2016-02-24 02:01:01 +03:00
|
|
|
fileStream = bufferedStream;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
contentType.AssignLiteral("application/octet-stream");
|
2010-02-25 08:58:16 +03:00
|
|
|
}
|
|
|
|
|
2016-07-14 10:01:58 +03:00
|
|
|
AddDataChunk(nameStr, filename, contentType, fileStream, size);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult FSMultipartFormData::AddNameDirectoryPair(const nsAString& aName,
|
|
|
|
Directory* aDirectory) {
|
2018-09-10 21:36:16 +03:00
|
|
|
if (!StaticPrefs::dom_webkitBlink_dirPicker_enabled()) {
|
2016-07-14 10:01:58 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Encode the control name
|
|
|
|
nsAutoCString nameStr;
|
|
|
|
nsresult rv = EncodeVal(aName, nameStr, true);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsAutoCString dirname;
|
|
|
|
nsAutoString dirname16;
|
|
|
|
|
|
|
|
ErrorResult error;
|
|
|
|
nsAutoString path;
|
|
|
|
aDirectory->GetPath(path, error);
|
|
|
|
if (NS_WARN_IF(error.Failed())) {
|
|
|
|
error.SuppressException();
|
|
|
|
} else {
|
|
|
|
dirname16 = path;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dirname16.IsEmpty()) {
|
|
|
|
RetrieveDirectoryName(aDirectory, dirname16);
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = EncodeVal(dirname16, dirname, true);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
AddDataChunk(nameStr, dirname, NS_LITERAL_CSTRING("application/octet-stream"),
|
|
|
|
nullptr, 0);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSMultipartFormData::AddDataChunk(const nsACString& aName,
|
|
|
|
const nsACString& aFilename,
|
|
|
|
const nsACString& aContentType,
|
|
|
|
nsIInputStream* aInputStream,
|
|
|
|
uint64_t aInputStreamSize) {
|
2002-02-16 04:19:24 +03:00
|
|
|
//
|
|
|
|
// Make MIME block for name/value pair
|
|
|
|
//
|
|
|
|
// more appropriate than always using binary?
|
|
|
|
mPostDataChunk +=
|
|
|
|
NS_LITERAL_CSTRING("--") + mBoundary + NS_LITERAL_CSTRING(CRLF);
|
2005-07-13 20:55:59 +04:00
|
|
|
// XXX: name/filename parameter should be encoded per RFC 2231
|
2016-02-24 02:01:01 +03:00
|
|
|
// RFC 2388 specifies that RFC 2047 be used, but I think it's not
|
2005-07-13 20:55:59 +04:00
|
|
|
// consistent with the MIME standard.
|
2002-02-16 04:19:24 +03:00
|
|
|
mPostDataChunk +=
|
|
|
|
NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"") + aName +
|
2016-07-14 10:01:58 +03:00
|
|
|
NS_LITERAL_CSTRING("\"; filename=\"") + aFilename +
|
2010-11-23 11:50:55 +03:00
|
|
|
NS_LITERAL_CSTRING("\"" CRLF) + NS_LITERAL_CSTRING("Content-Type: ") +
|
2016-07-14 10:01:58 +03:00
|
|
|
aContentType + NS_LITERAL_CSTRING(CRLF CRLF);
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2013-03-16 01:57:35 +04:00
|
|
|
// We should not try to append an invalid stream. That will happen for example
|
|
|
|
// if we try to update a file that actually do not exist.
|
2016-07-14 10:01:58 +03:00
|
|
|
if (aInputStream) {
|
|
|
|
// 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();
|
2015-05-19 17:36:37 +03:00
|
|
|
|
2017-09-19 17:26:21 +03:00
|
|
|
mPostData->AppendStream(aInputStream);
|
2016-07-14 10:01:58 +03:00
|
|
|
mTotalLength += aInputStreamSize;
|
2002-04-07 04:17:56 +04:00
|
|
|
}
|
2002-02-16 04:19:24 +03:00
|
|
|
|
|
|
|
// CRLF after file
|
2004-06-17 04:13:25 +04:00
|
|
|
mPostDataChunk.AppendLiteral(CRLF);
|
2016-07-14 10:01:31 +03:00
|
|
|
}
|
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
nsresult FSMultipartFormData::GetEncodedSubmission(
|
2017-09-22 09:12:03 +03:00
|
|
|
nsIURI* aURI, nsIInputStream** aPostDataStream, nsCOMPtr<nsIURI>& aOutURI) {
|
2002-02-16 04:19:24 +03:00
|
|
|
nsresult rv;
|
2018-02-26 22:43:45 +03:00
|
|
|
aOutURI = aURI;
|
2002-02-16 04:19:24 +03:00
|
|
|
|
|
|
|
// Make header
|
|
|
|
nsCOMPtr<nsIMIMEInputStream> mimeStream =
|
|
|
|
do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString contentType;
|
2010-02-25 08:58:18 +03:00
|
|
|
GetContentType(contentType);
|
|
|
|
mimeStream->AddHeader("Content-Type", contentType.get());
|
2017-09-22 09:12:03 +03:00
|
|
|
|
|
|
|
uint64_t bodySize;
|
|
|
|
mimeStream->SetData(GetSubmissionBody(&bodySize));
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2014-03-15 23:00:15 +04:00
|
|
|
mimeStream.forget(aPostDataStream);
|
2002-02-16 04:19:24 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
nsresult FSMultipartFormData::AddPostDataStream() {
|
2002-02-16 04:19:24 +03:00
|
|
|
nsresult rv = NS_OK;
|
2016-02-24 02:01:01 +03:00
|
|
|
|
2002-02-16 04:19:24 +03:00
|
|
|
nsCOMPtr<nsIInputStream> postDataChunkStream;
|
|
|
|
rv = NS_NewCStringInputStream(getter_AddRefs(postDataChunkStream),
|
|
|
|
mPostDataChunk);
|
|
|
|
NS_ASSERTION(postDataChunkStream, "Could not open a stream for POST!");
|
|
|
|
if (postDataChunkStream) {
|
2017-09-19 17:26:21 +03:00
|
|
|
mPostData->AppendStream(postDataChunkStream);
|
2012-09-20 02:15:32 +04:00
|
|
|
mTotalLength += mPostDataChunk.Length();
|
2002-02-16 04:19:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
mPostDataChunk.Truncate();
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2010-02-25 08:58:17 +03:00
|
|
|
// --------------------------------------------------------------------------
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2016-06-16 10:25:12 +03:00
|
|
|
namespace {
|
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
class FSTextPlain : public EncodingFormSubmission {
|
2002-07-12 03:32:13 +04:00
|
|
|
public:
|
2018-07-22 12:11:27 +03:00
|
|
|
FSTextPlain(nsIURI* aActionURL, const nsAString& aTarget,
|
2020-02-11 15:46:57 +03:00
|
|
|
NotNull<const Encoding*> aEncoding, Element* aSubmitter)
|
|
|
|
: EncodingFormSubmission(aActionURL, aTarget, aEncoding, aSubmitter) {}
|
2004-01-10 02:54:21 +03:00
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
virtual nsresult AddNameValuePair(const nsAString& aName,
|
|
|
|
const nsAString& aValue) override;
|
|
|
|
|
|
|
|
virtual nsresult AddNameBlobOrNullPair(const nsAString& aName,
|
|
|
|
Blob* aBlob) override;
|
|
|
|
|
2016-07-14 10:01:31 +03:00
|
|
|
virtual nsresult AddNameDirectoryPair(const nsAString& aName,
|
|
|
|
Directory* aDirectory) override;
|
|
|
|
|
2017-09-22 09:12:03 +03:00
|
|
|
virtual nsresult GetEncodedSubmission(nsIURI* aURI,
|
|
|
|
nsIInputStream** aPostDataStream,
|
2018-05-23 08:12:36 +03:00
|
|
|
nsCOMPtr<nsIURI>& aOutURI) override;
|
2002-07-12 03:32:13 +04:00
|
|
|
|
|
|
|
private:
|
|
|
|
nsString mBody;
|
|
|
|
};
|
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
nsresult FSTextPlain::AddNameValuePair(const nsAString& aName,
|
|
|
|
const nsAString& aValue) {
|
2002-07-12 03:32:13 +04:00
|
|
|
// XXX This won't work well with a name like "a=b" or "a\nb" but I suppose
|
|
|
|
// text/plain doesn't care about that. Parsers aren't built for escaped
|
|
|
|
// values so we'll have to live with it.
|
2010-02-25 08:58:16 +03:00
|
|
|
mBody.Append(aName + NS_LITERAL_STRING("=") + aValue +
|
|
|
|
NS_LITERAL_STRING(CRLF));
|
2002-07-12 03:32:13 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
nsresult FSTextPlain::AddNameBlobOrNullPair(const nsAString& aName,
|
|
|
|
Blob* aBlob) {
|
2016-01-20 20:25:03 +03:00
|
|
|
nsAutoString filename;
|
|
|
|
RetrieveFileName(aBlob, filename);
|
2010-02-25 08:58:16 +03:00
|
|
|
AddNameValuePair(aName, filename);
|
2002-07-12 03:32:13 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-07-14 10:01:31 +03:00
|
|
|
nsresult FSTextPlain::AddNameDirectoryPair(const nsAString& aName,
|
|
|
|
Directory* aDirectory) {
|
2016-07-14 10:01:58 +03:00
|
|
|
nsAutoString dirname;
|
|
|
|
RetrieveDirectoryName(aDirectory, dirname);
|
|
|
|
AddNameValuePair(aName, dirname);
|
2016-07-14 10:01:31 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:26:34 +03:00
|
|
|
nsresult FSTextPlain::GetEncodedSubmission(nsIURI* aURI,
|
2017-09-22 09:12:03 +03:00
|
|
|
nsIInputStream** aPostDataStream,
|
2018-02-26 22:43:45 +03:00
|
|
|
nsCOMPtr<nsIURI>& aOutURI) {
|
2002-07-12 03:32:13 +04:00
|
|
|
nsresult rv = NS_OK;
|
2018-02-26 22:43:45 +03:00
|
|
|
aOutURI = aURI;
|
2002-07-12 03:32:13 +04:00
|
|
|
|
2017-09-22 09:12:03 +03:00
|
|
|
*aPostDataStream = nullptr;
|
|
|
|
|
2002-07-12 03:32:13 +04:00
|
|
|
// XXX HACK We are using the standard URL mechanism to give the body to the
|
|
|
|
// mailer instead of passing the post data stream to it, since that sounds
|
|
|
|
// hard.
|
2019-08-02 11:54:18 +03:00
|
|
|
if (aURI->SchemeIs("mailto")) {
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString path;
|
2017-07-29 14:50:21 +03:00
|
|
|
rv = aURI->GetPathQueryRef(path);
|
2002-07-12 03:32:13 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2002-08-04 09:03:30 +04:00
|
|
|
HandleMailtoSubject(path);
|
2002-07-12 03:32:13 +04:00
|
|
|
|
|
|
|
// Append the body to and force-plain-text args to the mailto line
|
2016-05-18 19:21:56 +03:00
|
|
|
nsAutoCString escapedBody;
|
|
|
|
if (NS_WARN_IF(!NS_Escape(NS_ConvertUTF16toUTF8(mBody), escapedBody,
|
|
|
|
url_XAlphas))) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2002-07-12 03:32:13 +04:00
|
|
|
|
|
|
|
path += NS_LITERAL_CSTRING("&force-plain-text=Y&body=") + escapedBody;
|
|
|
|
|
2018-02-26 22:43:45 +03:00
|
|
|
rv = NS_MutateURI(aURI).SetPathQueryRef(path).Finalize(aOutURI);
|
2002-07-12 03:32:13 +04:00
|
|
|
} else {
|
2010-11-23 11:50:55 +03:00
|
|
|
// Create data stream.
|
|
|
|
// We do want to send the data through the charset encoder and we want to
|
|
|
|
// normalize linebreaks to use the "standard net" format (\r\n), but we
|
|
|
|
// don't want to perform any other encoding. This means that names and
|
|
|
|
// values which contains '=' or newlines are potentially ambigiously
|
|
|
|
// encoded, but that how text/plain is specced.
|
|
|
|
nsCString cbody;
|
|
|
|
EncodeVal(mBody, cbody, false);
|
|
|
|
cbody.Adopt(nsLinebreakConverter::ConvertLineBreaks(
|
|
|
|
cbody.get(), nsLinebreakConverter::eLinebreakAny,
|
|
|
|
nsLinebreakConverter::eLinebreakNet));
|
2002-07-12 03:32:13 +04:00
|
|
|
nsCOMPtr<nsIInputStream> bodyStream;
|
2018-05-30 22:15:35 +03:00
|
|
|
rv = NS_NewCStringInputStream(getter_AddRefs(bodyStream), std::move(cbody));
|
2002-07-12 03:32:13 +04:00
|
|
|
if (!bodyStream) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create mime stream with headers and such
|
|
|
|
nsCOMPtr<nsIMIMEInputStream> mimeStream =
|
|
|
|
do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
mimeStream->AddHeader("Content-Type", "text/plain");
|
|
|
|
mimeStream->SetData(bodyStream);
|
2018-09-27 17:59:55 +03:00
|
|
|
mimeStream.forget(aPostDataStream);
|
2002-07-12 03:32:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:25:12 +03:00
|
|
|
} // anonymous namespace
|
|
|
|
|
2010-02-25 08:58:17 +03:00
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
2017-04-27 13:27:03 +03:00
|
|
|
EncodingFormSubmission::EncodingFormSubmission(
|
2018-07-22 12:11:27 +03:00
|
|
|
nsIURI* aActionURL, const nsAString& aTarget,
|
2020-02-11 15:46:57 +03:00
|
|
|
NotNull<const Encoding*> aEncoding, Element* aSubmitter)
|
|
|
|
: HTMLFormSubmission(aActionURL, aTarget, aEncoding, aSubmitter) {
|
2017-04-27 13:27:03 +03:00
|
|
|
if (!aEncoding->CanEncodeEverything()) {
|
|
|
|
nsAutoCString name;
|
|
|
|
aEncoding->Name(name);
|
2019-06-09 00:26:12 +03:00
|
|
|
AutoTArray<nsString, 1> args;
|
|
|
|
CopyUTF8toUTF16(name, *args.AppendElement());
|
2020-02-11 15:46:57 +03:00
|
|
|
SendJSWarning(aSubmitter ? aSubmitter->GetOwnerDocument() : nullptr,
|
|
|
|
"CannotEncodeAllUnicode", args);
|
2012-01-02 18:18:30 +04:00
|
|
|
}
|
2010-02-25 08:58:16 +03:00
|
|
|
}
|
2002-07-12 03:32:13 +04:00
|
|
|
|
2020-02-20 19:19:15 +03:00
|
|
|
EncodingFormSubmission::~EncodingFormSubmission() = default;
|
2002-08-06 08:26:35 +04:00
|
|
|
|
2010-02-25 08:58:17 +03:00
|
|
|
// i18n helper routines
|
2016-06-16 10:26:34 +03:00
|
|
|
nsresult EncodingFormSubmission::EncodeVal(const nsAString& aStr,
|
|
|
|
nsCString& aOut,
|
|
|
|
bool aHeaderEncode) {
|
2017-04-27 13:27:03 +03:00
|
|
|
nsresult rv;
|
|
|
|
const Encoding* ignored;
|
|
|
|
Tie(rv, ignored) = mEncoding->Encode(aStr, aOut);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
2010-11-23 11:50:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aHeaderEncode) {
|
|
|
|
aOut.Adopt(nsLinebreakConverter::ConvertLineBreaks(
|
|
|
|
aOut.get(), nsLinebreakConverter::eLinebreakAny,
|
|
|
|
nsLinebreakConverter::eLinebreakSpace));
|
|
|
|
aOut.ReplaceSubstring(NS_LITERAL_CSTRING("\""), NS_LITERAL_CSTRING("\\\""));
|
|
|
|
}
|
|
|
|
|
2010-02-25 08:58:17 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
|
2016-06-16 10:25:12 +03:00
|
|
|
namespace {
|
|
|
|
|
2010-02-25 08:58:16 +03:00
|
|
|
void GetEnumAttr(nsGenericHTMLElement* aContent, nsAtom* atom,
|
2017-10-03 01:05:19 +03:00
|
|
|
int32_t* aValue) {
|
2005-01-25 03:02:58 +03:00
|
|
|
const nsAttrValue* value = aContent->GetParsedAttr(atom);
|
|
|
|
if (value && value->Type() == nsAttrValue::eEnum) {
|
|
|
|
*aValue = value->GetEnumValue();
|
2002-02-16 04:19:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:25:12 +03:00
|
|
|
} // anonymous namespace
|
|
|
|
|
2019-02-26 01:05:29 +03:00
|
|
|
/* static */
|
2020-02-11 15:46:57 +03:00
|
|
|
nsresult HTMLFormSubmission::GetFromForm(HTMLFormElement* aForm,
|
|
|
|
nsGenericHTMLElement* aSubmitter,
|
|
|
|
NotNull<const Encoding*>& aEncoding,
|
|
|
|
HTMLFormSubmission** aFormSubmission) {
|
2010-02-25 08:58:17 +03:00
|
|
|
// Get all the information necessary to encode the form data
|
2014-10-02 23:07:24 +04:00
|
|
|
NS_ASSERTION(aForm->GetComposedDoc(),
|
2010-03-29 12:59:00 +04:00
|
|
|
"Should have doc if we're building submission!");
|
2010-02-25 08:58:17 +03:00
|
|
|
|
2018-07-22 12:11:27 +03:00
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
// Get action
|
|
|
|
nsCOMPtr<nsIURI> actionURL;
|
2020-02-11 15:46:57 +03:00
|
|
|
rv = aForm->GetActionURL(getter_AddRefs(actionURL), aSubmitter);
|
2018-07-22 12:11:27 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2019-01-09 18:42:04 +03:00
|
|
|
// Check if CSP allows this form-action
|
2019-05-22 02:14:27 +03:00
|
|
|
nsCOMPtr<nsIContentSecurityPolicy> csp = aForm->GetCsp();
|
2019-01-09 18:42:04 +03:00
|
|
|
if (csp) {
|
|
|
|
bool permitsFormAction = true;
|
2019-01-16 11:50:07 +03:00
|
|
|
|
2019-01-09 18:42:04 +03:00
|
|
|
// form-action is only enforced if explicitly defined in the
|
|
|
|
// policy - do *not* consult default-src, see:
|
|
|
|
// http://www.w3.org/TR/CSP2/#directive-default-src
|
|
|
|
rv = csp->Permits(aForm, nullptr /* nsICSPEventListener */, actionURL,
|
|
|
|
nsIContentSecurityPolicy::FORM_ACTION_DIRECTIVE, true,
|
|
|
|
&permitsFormAction);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (!permitsFormAction) {
|
|
|
|
return NS_ERROR_CSP_FORM_ACTION_VIOLATION;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-22 12:11:27 +03:00
|
|
|
// Get target
|
2020-02-11 15:46:57 +03:00
|
|
|
// The target is the submitter element formtarget attribute if the element
|
2018-07-22 12:11:27 +03:00
|
|
|
// is a submit control and has such an attribute.
|
|
|
|
// Otherwise, the target is the form owner's target attribute,
|
|
|
|
// if it has such an attribute.
|
|
|
|
// Finally, if one of the child nodes of the head element is a base element
|
|
|
|
// with a target attribute, then the value of the target attribute of the
|
|
|
|
// first such base element; or, if there is no such element, the empty string.
|
|
|
|
nsAutoString target;
|
2020-02-11 15:46:57 +03:00
|
|
|
if (!(aSubmitter && aSubmitter->GetAttr(kNameSpaceID_None,
|
|
|
|
nsGkAtoms::formtarget, target)) &&
|
2018-07-22 12:11:27 +03:00
|
|
|
!aForm->GetAttr(kNameSpaceID_None, nsGkAtoms::target, target)) {
|
|
|
|
aForm->GetBaseTarget(target);
|
|
|
|
}
|
|
|
|
|
2010-02-25 08:58:17 +03:00
|
|
|
// Get encoding type (default: urlencoded)
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t enctype = NS_FORM_ENCTYPE_URLENCODED;
|
2020-02-11 15:46:57 +03:00
|
|
|
if (aSubmitter &&
|
|
|
|
aSubmitter->HasAttr(kNameSpaceID_None, nsGkAtoms::formenctype)) {
|
|
|
|
GetEnumAttr(aSubmitter, nsGkAtoms::formenctype, &enctype);
|
2010-08-20 21:47:30 +04:00
|
|
|
} else {
|
|
|
|
GetEnumAttr(aForm, nsGkAtoms::enctype, &enctype);
|
|
|
|
}
|
2010-02-25 08:58:17 +03:00
|
|
|
|
|
|
|
// Get method (default: GET)
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t method = NS_FORM_METHOD_GET;
|
2020-02-11 15:46:57 +03:00
|
|
|
if (aSubmitter &&
|
|
|
|
aSubmitter->HasAttr(kNameSpaceID_None, nsGkAtoms::formmethod)) {
|
|
|
|
GetEnumAttr(aSubmitter, nsGkAtoms::formmethod, &method);
|
2010-08-20 21:47:30 +04:00
|
|
|
} else {
|
|
|
|
GetEnumAttr(aForm, nsGkAtoms::method, &method);
|
|
|
|
}
|
2010-02-25 08:58:17 +03:00
|
|
|
|
2020-05-12 01:56:13 +03:00
|
|
|
if (method == NS_FORM_METHOD_DIALOG) {
|
|
|
|
HTMLDialogElement* dialog = nullptr;
|
|
|
|
for (nsIContent* parent = aForm->GetParent(); parent;
|
|
|
|
parent = parent->GetParent()) {
|
|
|
|
dialog = HTMLDialogElement::FromNodeOrNull(parent);
|
|
|
|
if (dialog) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there isn't one, or if it does not have an open attribute, do
|
|
|
|
// nothing.
|
|
|
|
if (!dialog || !dialog->Open()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString result;
|
|
|
|
if (aSubmitter) {
|
|
|
|
aSubmitter->ResultForDialogSubmit(result);
|
|
|
|
}
|
|
|
|
*aFormSubmission = new DialogFormSubmission(result, actionURL, target,
|
|
|
|
aEncoding, aSubmitter, dialog);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(method != NS_FORM_METHOD_DIALOG);
|
|
|
|
|
2010-02-25 08:58:17 +03:00
|
|
|
// Choose encoder
|
|
|
|
if (method == NS_FORM_METHOD_POST && enctype == NS_FORM_ENCTYPE_MULTIPART) {
|
2020-02-11 15:46:57 +03:00
|
|
|
*aFormSubmission =
|
|
|
|
new FSMultipartFormData(actionURL, target, aEncoding, aSubmitter);
|
2010-02-25 08:58:17 +03:00
|
|
|
} else if (method == NS_FORM_METHOD_POST &&
|
|
|
|
enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
|
2018-07-22 12:11:27 +03:00
|
|
|
*aFormSubmission =
|
2020-02-11 15:46:57 +03:00
|
|
|
new FSTextPlain(actionURL, target, aEncoding, aSubmitter);
|
2010-02-25 08:58:17 +03:00
|
|
|
} else {
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* doc = aForm->OwnerDoc();
|
2010-02-25 08:58:17 +03:00
|
|
|
if (enctype == NS_FORM_ENCTYPE_MULTIPART ||
|
|
|
|
enctype == NS_FORM_ENCTYPE_TEXTPLAIN) {
|
2019-06-09 00:26:12 +03:00
|
|
|
AutoTArray<nsString, 1> args;
|
|
|
|
nsString& enctypeStr = *args.AppendElement();
|
2020-02-11 15:46:57 +03:00
|
|
|
if (aSubmitter &&
|
|
|
|
aSubmitter->HasAttr(kNameSpaceID_None, nsGkAtoms::formenctype)) {
|
|
|
|
aSubmitter->GetAttr(kNameSpaceID_None, nsGkAtoms::formenctype,
|
|
|
|
enctypeStr);
|
2010-08-20 21:47:30 +04:00
|
|
|
} else {
|
|
|
|
aForm->GetAttr(kNameSpaceID_None, nsGkAtoms::enctype, enctypeStr);
|
|
|
|
}
|
2019-06-09 00:26:12 +03:00
|
|
|
|
|
|
|
SendJSWarning(doc, "ForgotPostWarning", args);
|
2010-02-25 08:58:17 +03:00
|
|
|
}
|
2020-02-11 15:46:57 +03:00
|
|
|
*aFormSubmission =
|
|
|
|
new FSURLEncoded(actionURL, target, aEncoding, method, doc, aSubmitter);
|
2010-02-25 08:58:17 +03:00
|
|
|
}
|
2002-02-16 04:19:24 +03:00
|
|
|
|
2005-07-13 20:55:59 +04:00
|
|
|
return NS_OK;
|
2002-02-16 04:19:24 +03:00
|
|
|
}
|
2016-06-16 10:24:16 +03:00
|
|
|
|
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|