Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fix] File upload #850

Merged
merged 15 commits into from
Aug 29, 2024
Merged
11 changes: 6 additions & 5 deletions packages/waku/src/lib/renderers/rsc-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import type {
} from '../../server.js';
import type { ResolvedConfig } from '../config.js';
import { filePathToFileURL } from '../utils/path.js';
import { parseFormData } from '../utils/form.js';
import { streamToString } from '../utils/stream.js';
import { streamToArrayBuffer } from '../utils/stream.js';
import { decodeActionId } from '../renderers/utils.js';
import { bufferToString, parseFormData } from '../utils/buffer.js';

cjpais marked this conversation as resolved.
Show resolved Hide resolved
export const SERVER_MODULE_MAP = {
'rsdw-server': 'react-server-dom-webpack/server.edge',
Expand Down Expand Up @@ -194,15 +194,16 @@ export async function renderRsc(

let decodedBody: unknown | undefined = args.decodedBody;
if (body) {
const bodyStr = await streamToString(body);
const bodyBuf = await streamToArrayBuffer(body);
if (
typeof contentType === 'string' &&
contentType.startsWith('multipart/form-data')
) {
// XXX This doesn't support streaming unlike busboy
const formData = parseFormData(bodyStr, contentType);
const formData = await parseFormData(bodyBuf, contentType);
decodedBody = await decodeReply(formData, serverBundlerConfig);
} else if (bodyStr) {
} else if (bodyBuf.byteLength > 0) {
const bodyStr = bufferToString(bodyBuf);
decodedBody = await decodeReply(bodyStr, serverBundlerConfig);
}
}
Expand Down
16 changes: 16 additions & 0 deletions packages/waku/src/lib/utils/buffer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const parseFormData = async (
buffer: ArrayBuffer,
contentType: string,
): Promise<FormData> => {
const response = new Response(buffer, {
headers: {
'content-type': contentType,
},
});
return response.formData();
};

export const bufferToString = (buffer: ArrayBuffer): string => {
const enc = new TextDecoder();
return enc.decode(buffer);
};
33 changes: 0 additions & 33 deletions packages/waku/src/lib/utils/form.ts
cjpais marked this conversation as resolved.
Show resolved Hide resolved

This file was deleted.

26 changes: 26 additions & 0 deletions packages/waku/src/lib/utils/stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,32 @@ export const concatUint8Arrays = (arrs: Uint8Array[]): Uint8Array => {
return array;
};

// FIXME remove the two loops if possible, if it is more efficient
export const streamToArrayBuffer = async (stream: ReadableStream) => {
const reader = stream.getReader();
const chunks = [];
let totalSize = 0;
let done = false;
let value: Uint8Array | undefined;

do {
({ done, value } = await reader.read());
if (!done && value) {
chunks.push(value);
totalSize += value.length;
}
} while (!done);

const result = new Uint8Array(totalSize);
cjpais marked this conversation as resolved.
Show resolved Hide resolved
let offset = 0;
for (const chunk of chunks) {
result.set(chunk, offset);
offset += chunk.length;
}

return result.buffer;
};

export const streamToString = async (
stream: ReadableStream,
): Promise<string> => {
Expand Down
Loading
Loading