@balderdash/sails-edge
Version:
API-driven framework for building realtime apps, using MVC conventions (based on Express and Socket.io)
125 lines (106 loc) • 3.6 kB
JavaScript
/**
* Module dependencies
*/
var _ = require('lodash');
var defaultsDeep = require('merge-defaults');
var MockReq = require('mock-req');
/**
* Factory which builds generic Sails request object (i.e. `req`).
*
* This generic implementation of `req` forms the basis for
* Sails' transport-agnostic support of Connect/Express
* middleware. Used by hooks (i.e. sockets) but also for
* tests-- both at the app-level and in Sails core.
*
* @return {Request} simulated HTTP request object
* @idempotent
*/
module.exports = function buildRequest (_req) {
_req = _req||{};
var req;
// If `_req` appears to be a stream (duck-typing), then don't try
// and turn it into a mock stream again.
if (typeof _req === 'object' && _req.read) {
req = _req;
}
else {
// TODO: send a PR to mock-req with a fix for this
if (_req.headers && typeof _req.headers === 'object') {
// Strip undefined headers
_.each(_req.headers, function (headerVal, headerKey) {
if (_.isUndefined(headerVal)){
delete _req.headers[headerKey];
}
});
// Make sure all remaining headers are strings
_req.headers = _.mapValues(_req.headers, function (headerVal, headerKey) { // :TODO 'headerKey' is defined but never used
if (typeof headerVal !== 'string') {
headerVal = ''+headerVal+'';
}
return headerVal;
});
}
// Create a mock IncomingMessage stream.
req = new MockReq({
method: _req && (_.isString(_req.method) ? _req.method.toUpperCase() : 'GET'),
headers: _req && _req.headers || {},
url: _req && _req.url
});
// Add .get() and .header() methods to match express 3
req.get = req.header = function (name) {
switch (name = name.toLowerCase()) {
case 'referer':
case 'referrer':
return this.headers.referrer
|| this.headers.referer;
default:
return this.headers[name];
}
};
// Now pump client request body to the mock IncomingMessage stream (req)
// Req stream ends automatically if this is a GET or HEAD or DELETE request
// (since there is no request body in that case) so no need to do it again.
if (req.method !== 'GET' && req.method !== 'HEAD' && req.method !== 'DELETE') {
// Only write the body if there IS a body.
if (req.body) {
req.write(req.body);
}
req.end();
}
}
// Track request start time
req._startTime = new Date();
// TODO: add all the other methods in core
// Provide defaults for other request state and methods
req = defaultsDeep(req, {
params: [],
query: (_req && _req.query) || {},
body: (_req && _req.body) || {},
param: function(paramName, defaultValue) {
var key, params = {};
for (key in (req.params || {}) ) {
params[key] = params[key] || req.params[key];
}
for (key in (req.query || {}) ) {
params[key] = params[key] || req.query[key];
}
for (key in (req.body || {}) ) {
params[key] = params[key] || req.body[key];
}
// Grab the value of the parameter from the appropriate place
// and return it
if (typeof params[paramName] !== 'undefined') {
return params[paramName];
} else {
return defaultValue;
}
},
file: function (){
return res.send(500, 'Streaming file uploads via `req.file()` are only available over HTTP with Skipper.');
},
wantsJSON: (_req && _req.wantsJSON) || true,
method: 'GET',
path: _req.url
}, _req||{});
return req;
};