1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsFormSubmission.h"
11 #include "nsILinkHandler.h"
12 #include "nsIDocument.h"
13 #include "nsGkAtoms.h"
14 #include "nsIFormControl.h"
15 #include "nsIDOMHTMLFormElement.h"
17 #include "nsGenericHTMLElement.h"
18 #include "nsAttrValueInlines.h"
19 #include "nsISaveAsCharset.h"
21 #include "nsIDOMFile.h"
22 #include "nsDirectoryServiceDefs.h"
23 #include "nsStringStream.h"
26 #include "nsNetUtil.h"
27 #include "nsLinebreakConverter.h"
29 #include "nsUnicharUtils.h"
30 #include "nsIMultiplexInputStream.h"
31 #include "nsIMIMEInputStream.h"
32 #include "nsIMIMEService.h"
33 #include "nsIConsoleService.h"
34 #include "nsIScriptError.h"
35 #include "nsIStringBundle.h"
36 #include "nsCExternalHandlerService.h"
37 #include "nsIFileStreams.h"
38 #include "nsContentUtils.h"
40 #include "mozilla/dom/EncodingUtils.h"
42 using namespace mozilla
;
43 using mozilla::dom::EncodingUtils
;
46 SendJSWarning(nsIDocument
* aDocument
,
47 const char* aWarningName
,
48 const char16_t
** aWarningArgs
, uint32_t aWarningArgsLen
)
50 nsContentUtils::ReportToConsole(nsIScriptError::warningFlag
,
51 NS_LITERAL_CSTRING("HTML"), aDocument
,
52 nsContentUtils::eFORMS_PROPERTIES
,
54 aWarningArgs
, aWarningArgsLen
);
57 // --------------------------------------------------------------------------
59 class nsFSURLEncoded
: public nsEncodingFormSubmission
63 * @param aCharset the charset of the form as a string
64 * @param aMethod the method of the submit (either NS_FORM_METHOD_GET or
65 * NS_FORM_METHOD_POST).
67 nsFSURLEncoded(const nsACString
& aCharset
,
69 nsIDocument
* aDocument
,
70 nsIContent
* aOriginatingElement
)
71 : nsEncodingFormSubmission(aCharset
, aOriginatingElement
),
74 mWarnedFileControl(false)
78 virtual nsresult
AddNameValuePair(const nsAString
& aName
,
79 const nsAString
& aValue
);
80 virtual nsresult
AddNameFilePair(const nsAString
& aName
,
82 const nsString
& aFilename
);
83 virtual nsresult
GetEncodedSubmission(nsIURI
* aURI
,
84 nsIInputStream
** aPostDataStream
);
86 virtual bool SupportsIsindexSubmission()
91 virtual nsresult
AddIsindex(const nsAString
& aValue
);
96 * URL encode a Unicode string by encoding it to bytes, converting linebreaks
97 * properly, and then escaping many bytes as %xx.
99 * @param aStr the string to encode
100 * @param aEncoded the encoded string [OUT]
101 * @throws NS_ERROR_OUT_OF_MEMORY if we run out of memory
103 nsresult
URLEncode(const nsAString
& aStr
, nsCString
& aEncoded
);
107 * The method of the submit (either NS_FORM_METHOD_GET or
108 * NS_FORM_METHOD_POST).
112 /** The query string so far (the part after the ?) */
113 nsCString mQueryString
;
115 /** The document whose URI to use when reporting errors */
116 nsCOMPtr
<nsIDocument
> mDocument
;
118 /** Whether or not we have warned about a file control not being submitted */
119 bool mWarnedFileControl
;
123 nsFSURLEncoded::AddNameValuePair(const nsAString
& aName
,
124 const nsAString
& aValue
)
128 nsresult rv
= URLEncode(aValue
, convValue
);
129 NS_ENSURE_SUCCESS(rv
, rv
);
132 nsAutoCString convName
;
133 rv
= URLEncode(aName
, convName
);
134 NS_ENSURE_SUCCESS(rv
, rv
);
137 // Append data to string
138 if (mQueryString
.IsEmpty()) {
139 mQueryString
+= convName
+ NS_LITERAL_CSTRING("=") + convValue
;
141 mQueryString
+= NS_LITERAL_CSTRING("&") + convName
142 + NS_LITERAL_CSTRING("=") + convValue
;
149 nsFSURLEncoded::AddIsindex(const nsAString
& aValue
)
153 nsresult rv
= URLEncode(aValue
, convValue
);
154 NS_ENSURE_SUCCESS(rv
, rv
);
156 // Append data to string
157 if (mQueryString
.IsEmpty()) {
158 mQueryString
.Assign(convValue
);
160 mQueryString
+= NS_LITERAL_CSTRING("&isindex=") + convValue
;
167 nsFSURLEncoded::AddNameFilePair(const nsAString
& aName
,
169 const nsString
& aFilename
)
171 if (!mWarnedFileControl
) {
172 SendJSWarning(mDocument
, "ForgotFileEnctypeWarning", nullptr, 0);
173 mWarnedFileControl
= true;
176 nsAutoString filename
;
177 nsCOMPtr
<nsIDOMFile
> file
= do_QueryInterface(aBlob
);
179 file
->GetName(filename
);
182 return AddNameValuePair(aName
, filename
);
186 HandleMailtoSubject(nsCString
& aPath
) {
188 // Walk through the string and see if we have a subject already.
189 bool hasSubject
= false;
190 bool hasParams
= false;
191 int32_t paramSep
= aPath
.FindChar('?');
192 while (paramSep
!= kNotFound
&& paramSep
< (int32_t)aPath
.Length()) {
195 // Get the end of the name at the = op. If it is *after* the next &,
196 // assume that someone made a parameter without an = in it
197 int32_t nameEnd
= aPath
.FindChar('=', paramSep
+1);
198 int32_t nextParamSep
= aPath
.FindChar('&', paramSep
+1);
199 if (nextParamSep
== kNotFound
) {
200 nextParamSep
= aPath
.Length();
203 // If the = op is after the &, this parameter is a name without value.
204 // If there is no = op, same thing.
205 if (nameEnd
== kNotFound
|| nextParamSep
< nameEnd
) {
206 nameEnd
= nextParamSep
;
209 if (nameEnd
!= kNotFound
) {
210 if (Substring(aPath
, paramSep
+1, nameEnd
-(paramSep
+1)).
211 LowerCaseEqualsLiteral("subject")) {
217 paramSep
= nextParamSep
;
220 // If there is no subject, append a preformed subject to the mailto line
228 // Get the default subject
229 nsXPIDLString brandName
;
231 nsContentUtils::GetLocalizedString(nsContentUtils::eBRAND_PROPERTIES
,
232 "brandShortName", brandName
);
235 const char16_t
*formatStrings
[] = { brandName
.get() };
236 nsXPIDLString subjectStr
;
237 rv
= nsContentUtils::FormatLocalizedString(
238 nsContentUtils::eFORMS_PROPERTIES
,
239 "DefaultFormSubject",
244 aPath
.AppendLiteral("subject=");
245 nsCString subjectStrEscaped
;
246 aPath
.Append(NS_EscapeURL(NS_ConvertUTF16toUTF8(subjectStr
), esc_Query
,
252 nsFSURLEncoded::GetEncodedSubmission(nsIURI
* aURI
,
253 nsIInputStream
** aPostDataStream
)
257 *aPostDataStream
= nullptr;
259 if (mMethod
== NS_FORM_METHOD_POST
) {
261 bool isMailto
= false;
262 aURI
->SchemeIs("mailto", &isMailto
);
266 rv
= aURI
->GetPath(path
);
267 NS_ENSURE_SUCCESS(rv
, rv
);
269 HandleMailtoSubject(path
);
271 // Append the body to and force-plain-text args to the mailto line
272 nsCString escapedBody
;
273 escapedBody
.Adopt(nsEscape(mQueryString
.get(), url_XAlphas
));
275 path
+= NS_LITERAL_CSTRING("&force-plain-text=Y&body=") + escapedBody
;
277 rv
= aURI
->SetPath(path
);
281 nsCOMPtr
<nsIInputStream
> dataStream
;
282 // XXX We *really* need to either get the string to disown its data (and
283 // not destroy it), or make a string input stream that owns the CString
284 // that is passed to it. Right now this operation does a copy.
285 rv
= NS_NewCStringInputStream(getter_AddRefs(dataStream
), mQueryString
);
286 NS_ENSURE_SUCCESS(rv
, rv
);
288 nsCOMPtr
<nsIMIMEInputStream
> mimeStream(
289 do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv
));
290 NS_ENSURE_SUCCESS(rv
, rv
);
292 #ifdef SPECIFY_CHARSET_IN_CONTENT_TYPE
293 mimeStream
->AddHeader("Content-Type",
295 "application/x-www-form-urlencoded; charset="
299 mimeStream
->AddHeader("Content-Type",
300 "application/x-www-form-urlencoded");
302 mimeStream
->SetAddContentLength(true);
303 mimeStream
->SetData(dataStream
);
305 *aPostDataStream
= mimeStream
;
306 NS_ADDREF(*aPostDataStream
);
310 // Get the full query string
311 bool schemeIsJavaScript
;
312 rv
= aURI
->SchemeIs("javascript", &schemeIsJavaScript
);
313 NS_ENSURE_SUCCESS(rv
, rv
);
314 if (schemeIsJavaScript
) {
318 nsCOMPtr
<nsIURL
> url
= do_QueryInterface(aURI
);
320 url
->SetQuery(mQueryString
);
324 rv
= aURI
->GetPath(path
);
325 NS_ENSURE_SUCCESS(rv
, rv
);
326 // Bug 42616: Trim off named anchor and save it to add later
327 int32_t namedAnchorPos
= path
.FindChar('#');
328 nsAutoCString namedAnchor
;
329 if (kNotFound
!= namedAnchorPos
) {
330 path
.Right(namedAnchor
, (path
.Length() - namedAnchorPos
));
331 path
.Truncate(namedAnchorPos
);
334 // Chop off old query string (bug 25330, 57333)
335 // Only do this for GET not POST (bug 41585)
336 int32_t queryStart
= path
.FindChar('?');
337 if (kNotFound
!= queryStart
) {
338 path
.Truncate(queryStart
);
342 // Bug 42616: Add named anchor to end after query string
343 path
.Append(mQueryString
+ namedAnchor
);
352 // i18n helper routines
354 nsFSURLEncoded::URLEncode(const nsAString
& aStr
, nsCString
& aEncoded
)
356 // convert to CRLF breaks
357 char16_t
* convertedBuf
=
358 nsLinebreakConverter::ConvertUnicharLineBreaks(PromiseFlatString(aStr
).get(),
359 nsLinebreakConverter::eLinebreakAny
,
360 nsLinebreakConverter::eLinebreakNet
);
361 NS_ENSURE_TRUE(convertedBuf
, NS_ERROR_OUT_OF_MEMORY
);
363 nsAutoCString encodedBuf
;
364 nsresult rv
= EncodeVal(nsDependentString(convertedBuf
), encodedBuf
, false);
365 nsMemory::Free(convertedBuf
);
366 NS_ENSURE_SUCCESS(rv
, rv
);
368 char* escapedBuf
= nsEscape(encodedBuf
.get(), url_XPAlphas
);
369 NS_ENSURE_TRUE(escapedBuf
, NS_ERROR_OUT_OF_MEMORY
);
370 aEncoded
.Adopt(escapedBuf
);
375 // --------------------------------------------------------------------------
377 nsFSMultipartFormData::nsFSMultipartFormData(const nsACString
& aCharset
,
378 nsIContent
* aOriginatingElement
)
379 : nsEncodingFormSubmission(aCharset
, aOriginatingElement
)
382 do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
385 mBoundary
.AssignLiteral("---------------------------");
386 mBoundary
.AppendInt(rand());
387 mBoundary
.AppendInt(rand());
388 mBoundary
.AppendInt(rand());
391 nsFSMultipartFormData::~nsFSMultipartFormData()
393 NS_ASSERTION(mPostDataChunk
.IsEmpty(), "Left unsubmitted data");
397 nsFSMultipartFormData::GetSubmissionBody(uint64_t* aContentLength
)
400 mPostDataChunk
+= NS_LITERAL_CSTRING("--") + mBoundary
401 + NS_LITERAL_CSTRING("--" CRLF
);
403 // Add final data input stream
406 *aContentLength
= mTotalLength
;
407 return mPostDataStream
;
411 nsFSMultipartFormData::AddNameValuePair(const nsAString
& aName
,
412 const nsAString
& aValue
)
415 nsAutoCString encodedVal
;
416 nsresult rv
= EncodeVal(aValue
, encodedVal
, false);
417 NS_ENSURE_SUCCESS(rv
, rv
);
419 valueStr
.Adopt(nsLinebreakConverter::
420 ConvertLineBreaks(encodedVal
.get(),
421 nsLinebreakConverter::eLinebreakAny
,
422 nsLinebreakConverter::eLinebreakNet
));
424 nsAutoCString nameStr
;
425 rv
= EncodeVal(aName
, nameStr
, true);
426 NS_ENSURE_SUCCESS(rv
, rv
);
428 // Make MIME block for name/value pair
430 // XXX: name parameter should be encoded per RFC 2231
431 // RFC 2388 specifies that RFC 2047 be used, but I think it's not
432 // consistent with MIME standard.
433 mPostDataChunk
+= NS_LITERAL_CSTRING("--") + mBoundary
434 + NS_LITERAL_CSTRING(CRLF
)
435 + NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
436 + nameStr
+ NS_LITERAL_CSTRING("\"" CRLF CRLF
)
437 + valueStr
+ NS_LITERAL_CSTRING(CRLF
);
443 nsFSMultipartFormData::AddNameFilePair(const nsAString
& aName
,
445 const nsString
& aFilename
)
447 // Encode the control name
448 nsAutoCString nameStr
;
449 nsresult rv
= EncodeVal(aName
, nameStr
, true);
450 NS_ENSURE_SUCCESS(rv
, rv
);
452 nsCString filename
, contentType
;
453 nsCOMPtr
<nsIInputStream
> fileStream
;
455 // We prefer the explicitly passed filename
456 if (!aFilename
.IsVoid()) {
457 rv
= EncodeVal(aFilename
, filename
, true);
458 NS_ENSURE_SUCCESS(rv
, rv
);
460 // Get and encode the filename
461 nsAutoString filename16
;
462 nsCOMPtr
<nsIDOMFile
> file
= do_QueryInterface(aBlob
);
464 rv
= file
->GetName(filename16
);
465 NS_ENSURE_SUCCESS(rv
, rv
);
468 if (filename16
.IsEmpty()) {
469 filename16
.AssignLiteral("blob");
471 nsAutoString filepath16
;
472 rv
= file
->GetPath(filepath16
);
473 NS_ENSURE_SUCCESS(rv
, rv
);
474 if (!filepath16
.IsEmpty()) {
475 // File.path includes trailing "/"
476 filename16
= filepath16
+ filename16
;
480 rv
= EncodeVal(filename16
, filename
, true);
481 NS_ENSURE_SUCCESS(rv
, rv
);
485 nsAutoString contentType16
;
486 rv
= aBlob
->GetType(contentType16
);
487 if (NS_FAILED(rv
) || contentType16
.IsEmpty()) {
488 contentType16
.AssignLiteral("application/octet-stream");
490 contentType
.Adopt(nsLinebreakConverter::
491 ConvertLineBreaks(NS_ConvertUTF16toUTF8(contentType16
).get(),
492 nsLinebreakConverter::eLinebreakAny
,
493 nsLinebreakConverter::eLinebreakSpace
));
496 rv
= aBlob
->GetInternalStream(getter_AddRefs(fileStream
));
497 NS_ENSURE_SUCCESS(rv
, rv
);
499 // Create buffered stream (for efficiency)
500 nsCOMPtr
<nsIInputStream
> bufferedStream
;
501 rv
= NS_NewBufferedInputStream(getter_AddRefs(bufferedStream
),
503 NS_ENSURE_SUCCESS(rv
, rv
);
505 fileStream
= bufferedStream
;
509 contentType
.AssignLiteral("application/octet-stream");
513 // Make MIME block for name/value pair
515 // more appropriate than always using binary?
516 mPostDataChunk
+= NS_LITERAL_CSTRING("--") + mBoundary
517 + NS_LITERAL_CSTRING(CRLF
);
518 // XXX: name/filename parameter should be encoded per RFC 2231
519 // RFC 2388 specifies that RFC 2047 be used, but I think it's not
520 // consistent with the MIME standard.
522 NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
523 + nameStr
+ NS_LITERAL_CSTRING("\"; filename=\"")
524 + filename
+ NS_LITERAL_CSTRING("\"" CRLF
)
525 + NS_LITERAL_CSTRING("Content-Type: ")
526 + contentType
+ NS_LITERAL_CSTRING(CRLF CRLF
);
528 // We should not try to append an invalid stream. That will happen for example
529 // if we try to update a file that actually do not exist.
531 if (fileStream
&& NS_SUCCEEDED(aBlob
->GetSize(&size
))) {
532 // We need to dump the data up to this point into the POST data stream here,
533 // since we're about to add the file input stream
536 mPostDataStream
->AppendStream(fileStream
);
537 mTotalLength
+= size
;
541 mPostDataChunk
.AppendLiteral(CRLF
);
547 nsFSMultipartFormData::GetEncodedSubmission(nsIURI
* aURI
,
548 nsIInputStream
** aPostDataStream
)
553 nsCOMPtr
<nsIMIMEInputStream
> mimeStream
554 = do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv
);
555 NS_ENSURE_SUCCESS(rv
, rv
);
557 nsAutoCString contentType
;
558 GetContentType(contentType
);
559 mimeStream
->AddHeader("Content-Type", contentType
.get());
560 mimeStream
->SetAddContentLength(true);
562 mimeStream
->SetData(GetSubmissionBody(&unused
));
564 mimeStream
.forget(aPostDataStream
);
570 nsFSMultipartFormData::AddPostDataStream()
574 nsCOMPtr
<nsIInputStream
> postDataChunkStream
;
575 rv
= NS_NewCStringInputStream(getter_AddRefs(postDataChunkStream
),
577 NS_ASSERTION(postDataChunkStream
, "Could not open a stream for POST!");
578 if (postDataChunkStream
) {
579 mPostDataStream
->AppendStream(postDataChunkStream
);
580 mTotalLength
+= mPostDataChunk
.Length();
583 mPostDataChunk
.Truncate();
588 // --------------------------------------------------------------------------
590 class nsFSTextPlain
: public nsEncodingFormSubmission
593 nsFSTextPlain(const nsACString
& aCharset
, nsIContent
* aOriginatingElement
)
594 : nsEncodingFormSubmission(aCharset
, aOriginatingElement
)
598 virtual nsresult
AddNameValuePair(const nsAString
& aName
,
599 const nsAString
& aValue
);
600 virtual nsresult
AddNameFilePair(const nsAString
& aName
,
602 const nsString
& aFilename
);
603 virtual nsresult
GetEncodedSubmission(nsIURI
* aURI
,
604 nsIInputStream
** aPostDataStream
);
611 nsFSTextPlain::AddNameValuePair(const nsAString
& aName
,
612 const nsAString
& aValue
)
614 // XXX This won't work well with a name like "a=b" or "a\nb" but I suppose
615 // text/plain doesn't care about that. Parsers aren't built for escaped
616 // values so we'll have to live with it.
617 mBody
.Append(aName
+ NS_LITERAL_STRING("=") + aValue
+
618 NS_LITERAL_STRING(CRLF
));
624 nsFSTextPlain::AddNameFilePair(const nsAString
& aName
,
626 const nsString
& aFilename
)
628 nsAutoString filename
;
629 nsCOMPtr
<nsIDOMFile
> file
= do_QueryInterface(aBlob
);
631 file
->GetName(filename
);
634 AddNameValuePair(aName
, filename
);
639 nsFSTextPlain::GetEncodedSubmission(nsIURI
* aURI
,
640 nsIInputStream
** aPostDataStream
)
644 // XXX HACK We are using the standard URL mechanism to give the body to the
645 // mailer instead of passing the post data stream to it, since that sounds
647 bool isMailto
= false;
648 aURI
->SchemeIs("mailto", &isMailto
);
651 rv
= aURI
->GetPath(path
);
652 NS_ENSURE_SUCCESS(rv
, rv
);
654 HandleMailtoSubject(path
);
656 // Append the body to and force-plain-text args to the mailto line
657 char* escapedBuf
= nsEscape(NS_ConvertUTF16toUTF8(mBody
).get(),
659 NS_ENSURE_TRUE(escapedBuf
, NS_ERROR_OUT_OF_MEMORY
);
660 nsCString escapedBody
;
661 escapedBody
.Adopt(escapedBuf
);
663 path
+= NS_LITERAL_CSTRING("&force-plain-text=Y&body=") + escapedBody
;
665 rv
= aURI
->SetPath(path
);
668 // Create data stream.
669 // We do want to send the data through the charset encoder and we want to
670 // normalize linebreaks to use the "standard net" format (\r\n), but we
671 // don't want to perform any other encoding. This means that names and
672 // values which contains '=' or newlines are potentially ambigiously
673 // encoded, but that how text/plain is specced.
675 EncodeVal(mBody
, cbody
, false);
676 cbody
.Adopt(nsLinebreakConverter::
677 ConvertLineBreaks(cbody
.get(),
678 nsLinebreakConverter::eLinebreakAny
,
679 nsLinebreakConverter::eLinebreakNet
));
680 nsCOMPtr
<nsIInputStream
> bodyStream
;
681 rv
= NS_NewCStringInputStream(getter_AddRefs(bodyStream
), cbody
);
683 return NS_ERROR_OUT_OF_MEMORY
;
686 // Create mime stream with headers and such
687 nsCOMPtr
<nsIMIMEInputStream
> mimeStream
688 = do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv
);
689 NS_ENSURE_SUCCESS(rv
, rv
);
691 mimeStream
->AddHeader("Content-Type", "text/plain");
692 mimeStream
->SetAddContentLength(true);
693 mimeStream
->SetData(bodyStream
);
694 CallQueryInterface(mimeStream
, aPostDataStream
);
700 // --------------------------------------------------------------------------
702 nsEncodingFormSubmission::nsEncodingFormSubmission(const nsACString
& aCharset
,
703 nsIContent
* aOriginatingElement
)
704 : nsFormSubmission(aCharset
, aOriginatingElement
)
706 nsAutoCString
charset(aCharset
);
707 // canonical name is passed so that we just have to check against
708 // *our* canonical names listed in charsetaliases.properties
709 if (charset
.EqualsLiteral("ISO-8859-1")) {
710 charset
.AssignLiteral("windows-1252");
713 if (!(charset
.EqualsLiteral("UTF-8") || charset
.EqualsLiteral("gb18030"))) {
714 NS_ConvertUTF8toUTF16
charsetUtf16(charset
);
715 const char16_t
* charsetPtr
= charsetUtf16
.get();
716 SendJSWarning(aOriginatingElement
? aOriginatingElement
->GetOwnerDocument()
718 "CannotEncodeAllUnicode",
723 mEncoder
= do_CreateInstance(NS_SAVEASCHARSET_CONTRACTID
);
726 mEncoder
->Init(charset
.get(),
727 (nsISaveAsCharset::attr_EntityAfterCharsetConv
+
728 nsISaveAsCharset::attr_FallbackDecimalNCR
),
736 nsEncodingFormSubmission::~nsEncodingFormSubmission()
740 // i18n helper routines
742 nsEncodingFormSubmission::EncodeVal(const nsAString
& aStr
, nsCString
& aOut
,
745 if (mEncoder
&& !aStr
.IsEmpty()) {
747 nsresult rv
= mEncoder
->Convert(PromiseFlatString(aStr
).get(),
748 getter_Copies(aOut
));
749 NS_ENSURE_SUCCESS(rv
, rv
);
752 // fall back to UTF-8
753 CopyUTF16toUTF8(aStr
, aOut
);
757 aOut
.Adopt(nsLinebreakConverter::
758 ConvertLineBreaks(aOut
.get(),
759 nsLinebreakConverter::eLinebreakAny
,
760 nsLinebreakConverter::eLinebreakSpace
));
761 aOut
.ReplaceSubstring(NS_LITERAL_CSTRING("\""),
762 NS_LITERAL_CSTRING("\\\""));
769 // --------------------------------------------------------------------------
772 GetSubmitCharset(nsGenericHTMLElement
* aForm
,
773 nsACString
& oCharset
)
775 oCharset
.AssignLiteral("UTF-8"); // default to utf-8
777 nsAutoString acceptCharsetValue
;
778 aForm
->GetAttr(kNameSpaceID_None
, nsGkAtoms::acceptcharset
,
781 int32_t charsetLen
= acceptCharsetValue
.Length();
782 if (charsetLen
> 0) {
785 // get charset from charsets one by one
787 spPos
= acceptCharsetValue
.FindChar(char16_t(' '), offset
);
788 int32_t cnt
= ((-1==spPos
)?(charsetLen
-offset
):(spPos
-offset
));
790 nsAutoString uCharset
;
791 acceptCharsetValue
.Mid(uCharset
, offset
, cnt
);
793 if (EncodingUtils::FindEncodingForLabel(uCharset
, oCharset
))
797 } while (spPos
!= -1);
799 // if there are no accept-charset or all the charset are not supported
800 // Get the charset from document
801 nsIDocument
* doc
= aForm
->GetComposedDoc();
803 oCharset
= doc
->GetDocumentCharacterSet();
808 GetEnumAttr(nsGenericHTMLElement
* aContent
,
809 nsIAtom
* atom
, int32_t* aValue
)
811 const nsAttrValue
* value
= aContent
->GetParsedAttr(atom
);
812 if (value
&& value
->Type() == nsAttrValue::eEnum
) {
813 *aValue
= value
->GetEnumValue();
818 GetSubmissionFromForm(nsGenericHTMLElement
* aForm
,
819 nsGenericHTMLElement
* aOriginatingElement
,
820 nsFormSubmission
** aFormSubmission
)
822 // Get all the information necessary to encode the form data
823 NS_ASSERTION(aForm
->GetComposedDoc(),
824 "Should have doc if we're building submission!");
826 // Get encoding type (default: urlencoded)
827 int32_t enctype
= NS_FORM_ENCTYPE_URLENCODED
;
828 if (aOriginatingElement
&&
829 aOriginatingElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::formenctype
)) {
830 GetEnumAttr(aOriginatingElement
, nsGkAtoms::formenctype
, &enctype
);
832 GetEnumAttr(aForm
, nsGkAtoms::enctype
, &enctype
);
835 // Get method (default: GET)
836 int32_t method
= NS_FORM_METHOD_GET
;
837 if (aOriginatingElement
&&
838 aOriginatingElement
->HasAttr(kNameSpaceID_None
, nsGkAtoms::formmethod
)) {
839 GetEnumAttr(aOriginatingElement
, nsGkAtoms::formmethod
, &method
);
841 GetEnumAttr(aForm
, nsGkAtoms::method
, &method
);
845 nsAutoCString charset
;
846 GetSubmitCharset(aForm
, charset
);
848 // We now have a canonical charset name, so we only have to check it
849 // against canonical names.
851 // use UTF-8 for UTF-16* (per WHATWG and existing practice of
853 if (StringBeginsWith(charset
, NS_LITERAL_CSTRING("UTF-16"))) {
854 charset
.AssignLiteral("UTF-8");
858 if (method
== NS_FORM_METHOD_POST
&&
859 enctype
== NS_FORM_ENCTYPE_MULTIPART
) {
860 *aFormSubmission
= new nsFSMultipartFormData(charset
, aOriginatingElement
);
861 } else if (method
== NS_FORM_METHOD_POST
&&
862 enctype
== NS_FORM_ENCTYPE_TEXTPLAIN
) {
863 *aFormSubmission
= new nsFSTextPlain(charset
, aOriginatingElement
);
865 nsIDocument
* doc
= aForm
->OwnerDoc();
866 if (enctype
== NS_FORM_ENCTYPE_MULTIPART
||
867 enctype
== NS_FORM_ENCTYPE_TEXTPLAIN
) {
868 nsAutoString enctypeStr
;
869 if (aOriginatingElement
&&
870 aOriginatingElement
->HasAttr(kNameSpaceID_None
,
871 nsGkAtoms::formenctype
)) {
872 aOriginatingElement
->GetAttr(kNameSpaceID_None
, nsGkAtoms::formenctype
,
875 aForm
->GetAttr(kNameSpaceID_None
, nsGkAtoms::enctype
, enctypeStr
);
877 const char16_t
* enctypeStrPtr
= enctypeStr
.get();
878 SendJSWarning(doc
, "ForgotPostWarning",
881 *aFormSubmission
= new nsFSURLEncoded(charset
, method
, doc
,
882 aOriginatingElement
);
884 NS_ENSURE_TRUE(*aFormSubmission
, NS_ERROR_OUT_OF_MEMORY
);