Skip to content

Commit 7feb928

Browse files
committed
Add normalizeValue helper that replaces all CR and LF in non-File field's value following the spec.
1 parent d4b5655 commit 7feb928

File tree

4 files changed

+45
-3
lines changed

4 files changed

+45
-3
lines changed

lib/Encoder.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import createBoundary from "./util/createBoundary"
2-
import escape from "./util/escapeName"
2+
import normalize from "./util/normalizeValue"
33
import isFormData from "./util/isFormData"
4+
import escape from "./util/escapeName"
45
import isFile from "./util/isFile"
56

67
import {FormDataLike} from "./FormDataLike"
@@ -119,7 +120,7 @@ export class FormDataEncoder {
119120

120121
length += isFile(value)
121122
? value.size
122-
: this.#encoder.encode(String(value)).byteLength
123+
: this.#encoder.encode(normalize(value)).byteLength
123124

124125
length += this.#CRLF_BYTES_LENGTH
125126
}
@@ -167,7 +168,7 @@ export class FormDataEncoder {
167168
for (const [name, value] of this.#form.entries()) {
168169
yield this.#getFieldHeader(name, value)
169170

170-
yield isFile(value) ? value : this.#encoder.encode(String(value))
171+
yield isFile(value) ? value : this.#encoder.encode(normalize(value))
171172

172173
yield this.#CRLF_BYTES
173174
}

lib/util/escapeName.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
/**
2+
* Escape fieldname following the spec requirements.
3+
*
4+
* See: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data
5+
*
6+
* @param name A fieldname to escape
7+
*/
18
const escapeName = (name: unknown) => String(name)
29
.replace(/\r/g, "%0D") // CR
310
.replace(/\n/g, "%0A") // LF

lib/util/normalizeValue.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import test from "ava"
2+
3+
import normalize from "./normalizeValue"
4+
5+
const expected = "First line.\r\nSecond line.\r\nThird line."
6+
7+
test("Replaces all CR not followed by LF with CRLF", t => {
8+
const actual = normalize("First line.\rSecond line.\rThird line.")
9+
10+
t.is(actual, expected)
11+
})
12+
13+
test("Replaces all LF not predicessed by CR with CRLF", t => {
14+
const actual = normalize("First line.\nSecond line.\nThird line.")
15+
16+
t.is(actual, expected)
17+
})
18+
19+
test("Keeps all CRLF without changes", t => {
20+
const actual = normalize(expected)
21+
22+
t.is(actual, expected)
23+
})

lib/util/normalizeValue.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Normalize non-File value following the spec requirements.
3+
*
4+
* See: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data
5+
*
6+
* @param value A value to normalize
7+
*/
8+
const normalizeValue = (value: unknown): string => String(value)
9+
.replace(/\r(?!\n)|(?<!\r)\n/g, "\r\n")
10+
11+
export default normalizeValue

0 commit comments

Comments
 (0)