Skip to content

Commit 8be6717

Browse files
committed
Fix issue with potential stream corruption
1 parent 85bd012 commit 8be6717

File tree

2 files changed

+14
-20
lines changed

2 files changed

+14
-20
lines changed

mod.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import {
44
} from "https://deno.land/std@0.95.0/mime/multipart.ts";
55
import {
66
readableStreamFromIterable,
7-
readableStreamFromReader,
8-
readerFromStreamReader,
97
} from "https://deno.land/std@0.95.0/io/streams.ts";
108

119
interface BytesMessage {
@@ -45,7 +43,9 @@ export function streamFromMultipart(
4543
// ReadableStream.
4644
const multipartWriter = new MultipartWriter({
4745
write(buffer: Uint8Array): Promise<number> {
48-
channel.push({ type: "bytes", buffer });
46+
// It is VERY important we close the buffer, there is no guarentee that the writer won't
47+
// re-use this buffer for subsequent writes.
48+
channel.push({ type: "bytes", buffer: new Uint8Array(buffer) });
4949
return Promise.resolve(buffer.length);
5050
},
5151
});
@@ -54,7 +54,8 @@ export function streamFromMultipart(
5454
writerFunction(multipartWriter)
5555
.then(() => {
5656
try {
57-
multipartWriter.close();
57+
// Close is an async function that still writes, so we must wait for it to complete.
58+
return multipartWriter.close();
5859
} catch (_ignored) {
5960
// We'll try to close the writer incase the user hasn't, if they have the close function
6061
// will throw an error we'll just ignore.
@@ -77,12 +78,5 @@ export function streamFromMultipart(
7778
}
7879
}
7980

80-
// Yes I know this looks REALLY stupid, but I was having issues where if we used the potentially
81-
// broken stream we would send the data out of order. This fixes it but I have no idea why. It
82-
// doesn't allocate the entire stream on the heap, so I think this is going to stay for now.
83-
const potentiallyBrokenStream = readableStreamFromIterable(generator());
84-
const reader = readerFromStreamReader(potentiallyBrokenStream.getReader());
85-
const stream = readableStreamFromReader(reader);
86-
87-
return [stream, multipartWriter.boundary];
81+
return [readableStreamFromIterable(generator()), multipartWriter.boundary];
8882
}

test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,29 @@ import {
77
assertEquals,
88
} from "https://deno.land/std@0.95.0/testing/asserts.ts";
99
import { Buffer } from "https://deno.land/std@0.95.0/io/buffer.ts";
10-
import { readerFromStreamReader } from "https://deno.land/std@0.95.0/io/streams.ts";
10+
import { readerFromIterable } from "https://deno.land/std@0.95.0/io/streams.ts";
1111
import { streamFromMultipart } from "./mod.ts";
1212

13-
const textEncoder = new TextEncoder();
14-
const textBytes = textEncoder.encode("denoland".repeat(1024));
15-
const textBytesReader = new Buffer(textBytes) as Deno.Reader;
13+
const testBytes = new Uint8Array(2 << 16).map(() =>
14+
Math.round(Math.random() * 255)
15+
);
16+
const testBytesReader = new Buffer(testBytes) as Deno.Reader;
1617

1718
Deno.test({
1819
name: "parse",
1920
fn: async () => {
2021
const [stream, boundary] = streamFromMultipart(async (writer) => {
21-
await writer.writeFile("test", "test.bin", textBytesReader);
22+
await writer.writeFile("test", "test.bin", testBytesReader);
2223
await writer.writeField("deno", "land");
2324
});
24-
25-
const reader = readerFromStreamReader(stream.getReader());
25+
const reader = readerFromIterable(stream);
2626
const multipartReader = new MultipartReader(reader, boundary);
2727
const form = await multipartReader.readForm();
2828

2929
// Ensure the file was serialized correctly.
3030
const formFile = form.file("test");
3131
assert(isFormFile(formFile), "form file is invalid");
32-
assertEquals(formFile.content, textBytes);
32+
assertEquals(formFile.content, testBytes);
3333

3434
// Ensure the field was serialized correctly.
3535
assertEquals(form.value("deno"), "land");

0 commit comments

Comments
 (0)