@sap/xsodata
Version:
Expose data from a HANA database as OData V2 service with help of .xsodata files.
131 lines (109 loc) • 4.23 kB
JavaScript
'use strict';
var async = require("async");
var NotSupportedError = require("./../../utils/errors/http/notSupported");
var contentTypeTools = require("./../../utils/checkContentType");
var api = module.exports = {
validate: validate,
_validateHttpHeader: _validateHttpHeader,
_validateAcceptHeader: _validateAcceptHeader
};
/**
* Validates the http request. Validation is done by validate http accept header.
*
*@param {Object} context The xsodata context
*@param {Function} done Callback called on finish. Expect following signature:
* function(error, context){}
*/
function validate(context, done) {
var validationStrategy = getValidationStrategy(context);
context.logger.silly("httpRequestValidator", "validate");
async.waterfall(validationStrategy, function (err, result) {
done(err, result);
});
}
/**
* Validates the http request header in general. I.e. if headers exists.
*
*@param {Object} context The xsodata context
*@param {Function} done Callback called on finish. Expect following signature:
* function(error, context){}
*/
function _validateHttpHeader(context, done) {
context.logger.silly("httpRequestValidator", "validateHttpHeader");
if (!context.request || !context.request.headers) {
return done(new NotSupportedError("A valid http Accept header must be provided"));
}
done(null, context);
}
/**
* Validates the http request accept header. This method validates if the current provided
* http accept header is available and is supported.
*
*@param {Object} context The xsodata context
*@param {Function} done Callback called on finish. Expect following signature:
* function(error, context){}
*/
function _validateAcceptHeader(context, done) {
var acceptHeader = context.request.headers["accept"] || context.request.headers["Accept"];
context.logger.silly("httpRequestValidator", "validateAcceptHeader");
if (!acceptHeader) {
return done(new NotSupportedError("A valid http Accept header must be provided"));
}
var contentType;
try {
contentType = contentTypeTools.checkEntry(context.request, getCustomFormat(context));
} catch (ex) {
return done(new NotSupportedError("Provided http Accept header '" + acceptHeader + "' is not supported", context, ex));
}
if (contentType === contentTypeTools.cTypes.ctJson) {
return done(null, context);
}
return done(new NotSupportedError("Provided http Accept header '" + acceptHeader + "' is not supported"));
}
/**
* Returns true if the current request is a batch request. A request is a batch request if
* the request url ends with $batch.
*
*@param {Object} context The xsodata context
*@returns {Boolean} True if current request url endwith $batch else false
*/
function isBatchRequest(context) {
if (!context.uriTree.segments.decoded ||
context.uriTree.segments.decoded.length === 0) {
return false; // call to service document
}
return context.uriTree.segments.decoded[0].toLowerCase() === "$batch";
}
/**
* Returns the current validation strategy. The validation strategy which will be used for
* validation depends on the kind of request sent.
*
*@param {Object} context The xsodata context
*/
function getValidationStrategy(context) {
var initialStrategy;
context.logger.silly("httpRequestValidator", "getValidationStrategy");
// Initial strategy is needed to inject context into async.waterfall()
initialStrategy = [
function (callback) {
callback(null, context);
}
];
if (context.request.method === "POST" && !isBatchRequest(context)) {
// Adding validation strategies if http method is POST and request is not a batch req.
return initialStrategy.concat([
api._validateHttpHeader,
api._validateAcceptHeader
]);
}
return initialStrategy;
}
/**
* Returns value of the custom 'format' URL parameter.
*/
function getCustomFormat(context) {
var queryParameters = context.uriTree.queryParameters;
if (queryParameters) {
return queryParameters['format'];
}
}