http-proxy
Version:
A full-featured http reverse proxy for node.js
109 lines (98 loc) • 2.91 kB
JavaScript
/**
* Simple connect middleware providing JSONP support.
*
* Config:
* - filter: should stip the callback param from the req.url
* for downstream processing. defaults to false.
*
* @return {Function}
* @api public
*/
module.exports = function jsonp(config) {
if ('boolean' == typeof config) {
config = {filter: config};
} else {
config = config || {};
}
var APP_JS_CONTENT_TYPE = 'application/javascript';
var BAD_REQUEST_BODY = '(' +
JSON.stringify({
error: 'method not allowed',
description: 'with callback only GET allowed'
}) +
')';
/**
* Write out a 400 error, passing it to the callback.
*/
function badRequest(res, callback) {
var body = callback + BAD_REQUEST_BODY;
res.writeHead(400, {
'Content-Type': APP_JS_CONTENT_TYPE,
'Content-Length': body.length
});
res.end(body);
};
/**
* Unwind.
*/
function previous(code, headers, res, context, body, encoding) {
res.writeHead = context.writeHead;
res.writeHead(code, headers);
if (body) {
res.write = context.write;
res.end = context.end;
res.end(body, encoding);
}
};
/**
* Filter the callback querystring param. Abstracts the JSONP nature
* of the request from downstream modules or application logic.
*/
function filter(req, url) {
var callback = new String(url.query.callback);
delete url.query.callback;
var querystring = require('querystring').parse(url.query);
querystring = querystring.length > 0 ? '?' + querystring : '';
req.url = url.pathname + querystring;
return callback;
};
/**
* Response decorator that pads a (json) response with a callback
* if requested do to so.
*/
return function jsonp(req, res, next) {
var url = require('url').parse(req.url, true);
if (!(url.query && url.query.callback)) {
next();
return;
} else if (req.method != 'GET') {
badRequest(res, url.query.callback);
return;
}
var context = {
originalUrl: req.url,
callback: config.filter ? filter(req, url) : url.query.callback,
writeHead: res.writeHead,
write: res.write,
end: res.end
};
// proxy
res.writeHead = function(code, headers) {
req.url = context.originalUrl;
if (code === 200) {
var body = '';
res.write = function(chunk, encoding) { body += chunk; }
res.end = function(data, encoding) {
if (data) body += data;
body = context.callback + '(' + body + ')';
headers['Content-Type'] = APP_JS_CONTENT_TYPE;
headers['Content-Length'] = Buffer.byteLength(body, encoding || "utf8");
previous(code, headers, res, context, body, encoding);
};
} else {
previous(code, headers, res, context);
}
};
next();
};
};