Skip to content

Instantly share code, notes, and snippets.

@getify
Created July 24, 2012 02:02
Show Gist options
  • Save getify/3167492 to your computer and use it in GitHub Desktop.
Save getify/3167492 to your computer and use it in GitHub Desktop.
var xhr, form_data = new FormData();
xhr = new XMLHttpRequest();
xhr.open("POST","http://barfoo.com/upload");
xhr.setRequestHeader("Content-Type","multipart/form-data");
xhr.setRequestHeader("File-Name",file.name);
xhr.setRequestHeader("File-Size",(file.size || file.fileSize));
xhr.setRequestHeader("File-Type",file.type);
xhr.setRequestHeader("Session-ID",12345);
xhr.onreadystatechange = function __xhr_onreadystatechange__(){
if (xhr.readyState == 4) {
xhr.onreadystatechange = null;
if (xhr.status != 200 || xhr.responseText != "OK") {
alert("Sorry, upload failed for: " + (file.name || "[unknown file]"));
}
xhr = null;
}
};
form_data.append(file.name,file);
xhr.send(form_data);
events.js:66
throw arguments[1]; // Unhandled 'error' event
^
Error: bad content-type header, no multipart boundary
at IncomingForm._parseContentType (/path/to/node_modules/formidable/lib/incoming_form.js:233:19)
at IncomingForm.writeHeaders (/path/to/node_modules/formidable/lib/incoming_form.js:131:8)
at IncomingForm.parse (/path/to/node_modules/formidable/lib/incoming_form.js:84:8)
Content-Type:multipart/form-data
File-Name:blah.jpg
File-Size:29080
File-Type:image/jpeg
Origin:http://foobar.com
Referer:http://foobar.com/blah/
Session-ID:12345
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1215.0 Safari/537.2
Request Payload
------WebKitFormBoundary3KzOjhaAGvJbm65r
Content-Disposition: form-data; name="blah.jpg"; filename="blah.jpg"
Content-Type: image/jpeg
------WebKitFormBoundary3KzOjhaAGvJbm65r--
// handle the HTTP routing
function handleHTTP(req, res) {
// handle file uploads
if (req.url == "/upload") {
// handle the CORS preflight request for the upload
if (req.method.toLowerCase() == "options" && req.headers["access-control-request-method"].toLowerCase() == "post") {
res.writeHead(200,CORS_POST_HEADERS);
res.end();
return;
}
// are we doing a POST upload?
else if (req.method.toLowerCase() == "post") {
// add the CORS POST headers
for (header in CORS_POST_HEADERS) {
res.setHeader(header,CORS_POST_HEADERS[header]);
}
// parse a file upload
var form = new formidable.IncomingForm();
form.parse(req,function __form_parse_cb__(err,fields,files) {
if (err) {
res.writeHead(500, {"Content-Type": "text/plain"});
res.end();
console.log("upload err: " + JSON.stringify(err));
}
else {
console.log(JSON.stringify(files));
res.writeHead(200, {"Content-Type": "text/plain"});
res.write("OK");
res.end();
}
});
return;
}
// otherwise, bail because we won't handle this kind of request!
else {
// add the CORS POST headers
for (header in CORS_POST_HEADERS) {
res.setHeader(header,CORS_POST_HEADERS[header]);
}
res.writeHead(403,{"Content-Type": "text/plain"});
res.end();
return;
}
}
return false;
}
require("http").createServer(handleHTTP).listen(80);
@polotek
Copy link

polotek commented Jul 24, 2012

Ah, that makes sense. I guess the browser generates a random boundary value and appends it to the content-type. @getify have you tried leaving the content-type off to see if the xhr does the right thing? If not, you'll have to find a way to get the generated boundary and append it to the content-type. Or you'll have to generate your own boundary value and have the body use that value. I'd be interested to know how you got this working.

@getify
Copy link
Author

getify commented Jul 24, 2012

I took out the setting of the the content-type on the XHR object, and sure enough the browser automatically sets the content-type, including the boundary, and all works fine. Thanks for the hint, @polotek and @alFReD-NSH!

Side note: apparently you have to return CORS headers on every single response, not just in response to the preflight OPTIONS request. Had to fix that too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment