@sap/xsodata
Version:
Expose data from a HANA database as OData V2 service with help of .xsodata files.
147 lines (122 loc) • 4.08 kB
JavaScript
;
/**
* Add <uriTree> attribute to <context>
* <uriTree> = {
* rawUrl : "->original url"
* rawUrlParts : "->splitted rawUrl"
* xsoFile : "->file of adressed xsoFile (usually the first segment)
* segments : [
* {
* raw : "->segment encoded"
* decoded : "->segment decoded"
* }
* }
* Uses <context.request.url>
* @type {exports}
*/
//Includes
const url = require('url');
const Http404_NotFound = require('./../utils/errors/http/notFound');
const _ = require('lodash');
const Measurement = require('./../utils/measurement');
function extractSegments(pathname) {
let i,
s = pathname.split('/'),
segments = {};
segments.raw = [];
// remove first empty string from "/<service_name>/..."
if (s[0].length === 0) {
s.shift();
}
// remove the last element if URI ends with "/"
if (s[s.length - 1] === '') {
s.pop();
}
//remove empty segments
for (i = 0; i < s.length; i++) {
segments.raw.push(s[i]);
}
//decode segments
segments.decoded = [];
for (i = 0; i < segments.raw.length; i++) {
segments.decoded.push(decodeURIComponent(segments.raw[i]));
}
return segments;
}
exports.prepareUri = function (context, asyncDone) {
//TODO check for multiple service segments
///E.g. ///url
context.logger.silly('http', 'prepareUri');
const uriTree = (context.uriTree = {});
uriTree.rawUrl = context.request.url; //may contain a xsodata file in first segment or not
uriTree.rawUrlParts = Measurement.measureSync(
url.parse,
uriTree.rawUrl,
true,
'url.parse'
);
uriTree.queryParameters = uriTree.rawUrlParts.query;
//read segments
uriTree.segments = Measurement.measureSync(
extractSegments,
uriTree.rawUrlParts.pathname,
'extractSegments'
);
if (uriTree.segments.length === 0) {
return asyncDone(
new Http404_NotFound('Service definition missing'),
context
);
}
if (context.batchContext) {
uriTree.xsoFile =
context.batchContext.parentContext.uriTree.xsoFile || '';
uriTree.baseUrl = context.batchContext.parentContext.uriTree.baseUrl;
return asyncDone(null, context);
}
if (context.servingDirectory) {
//first segment MUST BE xsodata filename
//remove the .xsodata from the segments
uriTree.xsoFile = uriTree.segments.decoded[0] || '';
uriTree.segments.decoded.shift();
uriTree.segments.raw.shift();
//build baseUrl
const urlData = {
protocol: context.request.urlData.proto,
host: context.request.urlData.host,
pathname: determineBasePath(
context.request.baseUrl + '/' + uriTree.xsoFile,
uriTree.segments.decoded,
context.request.urlData
),
};
uriTree.baseUrl = Measurement.measureSync(
url.format,
urlData,
'url.format'
);
return asyncDone(null, context);
}
//USE Case this instance of the xsodata handler only processes a single xsodata file
//so the name of this odata file MUST NOT inside the url
const tmp2 = {
protocol: context.request.urlData.proto,
host: context.request.urlData.host,
pathname: determineBasePath(
context.request.baseUrl,
uriTree.segments.decoded,
context.request.urlData
),
};
uriTree.baseUrl = Measurement.measureSync(url.format, tmp2, 'url.format');
return asyncDone(null, context);
};
//For unit testing
exports._getSegments = extractSegments;
function determineBasePath(uriPrefix, urlSegmentsNoXso, urlData) {
if (urlData.forwarded) {
const fSegs = extractSegments(urlData.path).decoded;
return _.dropRight(fSegs, urlSegmentsNoXso.length).join('/') + '/';
}
return uriPrefix + '/';
}