Why does FormData
insert carriage returns before line feed characters?
When I send post request with FormData
, it uses CRLF line endings, even though the value of textarea has no carriage returns at all. This makes my character length validation fail unexpectedly.
The sample code below shows the difference between the textarea string value, the data in FormData
and the encoded data that will get submitted. JSON.stringify()
is used to escape the control characters.
document.getElementById('HistoryValue').textContent = JSON.stringify(document.forms.CRLFSample.history.value);
const fd = new FormData(document.forms.CRLFSample);
document.getElementById('FormData').textContent = JSON.stringify(fd.get('history'));
new Response(fd).text().then(text =>
document.getElementById('POSTData').textContent = JSON.stringify(text));
#CRLFSample {
width: 90%;
}
<form id="CRLFSample" method="POST">
<textarea name="history">
line 1
line 2
</textarea>
</form>
<dl>
<dt>Textarea</dt><dd id="HistoryValue"></dd>
<dt>FormData</dt><dd id="FormData"></dd>
<dt>POST data</dt><dd id="POSTData"></dd>
</dl>
The above has been tested in Firefox 92-94 and Chrome 95 on macOS 10.14 & 12 and Android 10. Note "Textarea" shows "\n" for newlines, but "POSTData" has "\r\n". "FormData" shows different results depending mostly on the browser, with most versions of FireFox showing just "\n" and most versions of Chrome showing "\r\n".
Didn't think I had this many comments. Thank you for your interests, and allow me to apologize for not observing site guide lines. I'll try to elaborate more to best help you to reproduce the error and understand what's going on.
I tested this on my mac Catalina 10.15.7 and my browser is chrome Version 95.0.4638.69 (Official Build) (x86_64).
Below is my attempt to validate char length with formdata and just grabbing value of textarea respectively.
let formData = new FormData(document.getElementById('form'));
let historyEl = document.getElementById('id_history');
console.log(formData.get('history').length, formData.get('history').includes('\r\n'));
console.log(historyEl.value.length, historyEl.value.includes('r\n'));
<form id="form" method="POST">
<textarea class="materialize-textarea" cols="40" name="history" id="id_history" rows="10"> Lorem Ipsum is simply dummy text of the printing and typesetting
industry.
Lorem Ipsum has been the industry's standard dummy text ever since
the 1500s,
when an unknown printer took a galley of type and scrambled it to
make a type
specimen book. It has survived not only five centuries, but also
the leap into electronic
typesetting, remaining essentially unchanged. It was popularised in
the 190
.</textarea>
</form>
As you can see by running code snippet, formdata length of history
shows different length than that of textarea element value.
Originally I received the textarea value from Window user, and I thought it was only the matter of OS. But when I inspected it, that even happens in my OS, especially when submitting with form data.
One might ask that I can inspect length of textarea value, but I try to avoid that because checking with formdata is the whole point of frontend validation.
I'm not native English speaker, and my char length validation was on other non latin language, but something prevents me from posting non-latin language in code snippet. But Since console yields different lengths respectively, I believe you'll get the idea with other chars anyway.
According to MDN, FormData
uses the "multipart/form-data" format, specified by RFC 2388, section 3 of which states:
The media-type multipart/form-data follows the rules of all multipart MIME data streams as outlined in RFC 2046.
RFC § 4.1.1, the section on line endings, states:
The canonical form of any MIME "text" subtype MUST always represent a line break as a CRLF sequence.
Which is why line endings get encoded as CRLF when posted. What is not clear from this is whether line endings should be encoded as CRLF in FormData
's entries (such as shown by the result of formData.get('history')
).
The spec for FormData
makes no mention of encoding line endings when adding an entry or value. The only processing of a value when being added is for Blob (i.e. binary) and File objects. No processing of the value by FormData.get()
is mentioned. A strict reading of this would be that Chrome's behavior (encoding values stored in FormData
) is non-standard. However, storing a value directly would mean that the browser's internal (likely the platform's) line ending encoding would be used, which might vary.
The Fetch standard designates Response
as being responsible for handling the multipart/form-data encoding; specifically, extracting FormData
is supposed to use the "multipart/form-data" encoding algorithm.