oak
oak copied to clipboard
multipart/form-data response is missing boundary parameter
Discovered while answering multipart - Use FormData in an HTTP Response in Deno/Oak - Stack Overflow:
It appears Oak's automatic response body handling does not correctly handle FormData
like I originally thought. The Content-Type
response header is correctly inferred to be multipart/form-data
but provides no boundary
parameter. From RFC 7578, Appendix A:
"boundary" is now a required parameter in Content-Type
Clients receive the response fine without the boundary
parameter but some have issues using it. e.g Insomnia's "Visual Preview" shows "Failed to parse multipart response: content-type missing boundary" (its "Source Code" and "Raw Data" views correctly show the response body though).
Here is an example using Oak which reproduces the issue:
import { Application } from "https://deno.land/x/[email protected]/mod.ts";
const app = new Application();
app.use((ctx) => {
const data = new FormData();
data.append("string1", "Hi");
data.append("string2", "Bye");
data.append("blob1", new Blob(['<a id="a">Hi</a>'], { type: "text/xml" }));
data.append("blob2", new Blob(['<b id="b">Bye</b>'], { type: "text/xml" }));
ctx.response.body = data;
});
await app.listen({ port: 8000 });
% curl --head localhost:8000
HTTP/1.1 200 OK
content-type: multipart/form-data
date: Sat, 11 Sep 2021 12:40:37 GMT
Here is an example using native Deno HTTP serving where it correctly sets the boundary
parameter in the Content-Type
response header when responding with FormData
:
const server = Deno.listen({ port: 8000 });
for await (const conn of server) serveHttp(conn);
async function serveHttp(conn: Deno.Conn) {
const httpConn = Deno.serveHttp(conn);
for await (const requestEvent of httpConn) {
const data = new FormData();
data.append("string1", "Hi");
data.append("string2", "Bye");
data.append("blob1", new Blob(['<a id="a">Hi</a>'], { type: "text/xml" }));
data.append("blob2", new Blob(['<b id="b">Bye</b>'], { type: "text/xml" }));
requestEvent.respondWith(new Response(data));
}
}
% curl --head localhost:8000
HTTP/1.1 200 OK
content-type: multipart/form-data; boundary=----9980216681407476676035360426
date: Sat, 11 Sep 2021 12:43:54 GMT
A client browser couldn't use the fetch API to get the response of a FormData() from the Oak server, as it returns a TypeError: Could not parse content as FormData.
fetch('myRoute/getFormData', {
method: 'POST',
})
.then(response => response.formData()) // TypeError
.then(res => { console.log(res); });
It seems that browsers are incapable of parsing the response as a FormData because of the the missing boundary.
In the Oak server I have added the Content-Type header for multipart:
context.response.headers.set('Content-Type', 'multipart/form-data');
But the result is the same. Maybe the boundary parameter can be added manually? Something like this, I don't know:
context.response.headers.set('Content-Type', 'multipart/form-data; boundary=--something');
It looks like fetch
is able to successfully parse content as FormData
from the Deno.serveHttp
example I included above so it seems that Oak not sending the boundary
parameter causes issues for more than just Insomnia but web browsers too. Great catch @SathoriStudio.
Thanks for the investigation. I will look into fixing this.
Hi, is it possible to send the FormData from Deno/Oak to the web client?
In Firefox I receive the error: TypeError: Could not parse content as FormData
and in Chrome it says: TypeError: Invalid MIME type
when I try to receive the response using response.formData()
.
It seems that sending the FormData from the server to the client is complicated, but not the other way around.
I have created a little repo that contains the code examples provided here: https://github.com/M3cubo/Oak-Form-Data
Hi all. Are there any plans to fix this soon? Thanks!
The error when parsing in the client the formData still appears when I use the oak version, but the basic Deno version works fine: https://github.com/M3cubo/Oak-Form-Data (I have tried with oak 13.0.0)
It still shows the error "Uncaught (in promise) TypeError: Could not parse content as FormData. " in Firefox, and "Uncaught (in promise) TypeError: Invalid MIME type" in Chrome.
This hasn't been published yet in a release.