Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
c109011
Moving to separated file and add execution time
Gormartsen Mar 16, 2019
7bf1b06
Spliting into minimal modules to make it eathier to test functionality
Gormartsen Mar 18, 2019
962ff9e
move findAllTargets to module
Gormartsen Mar 18, 2019
619e163
Code style cleanup
Gormartsen Mar 18, 2019
f839de9
findHookTarget in separated function
Gormartsen Mar 18, 2019
9fa0c23
Move decodeData, fix typos and styles
Gormartsen Mar 18, 2019
e8e3d57
move sendBroadcastMessage to separated file
Gormartsen Mar 18, 2019
069f69a
Separate getHeaders function
Gormartsen Mar 18, 2019
234c238
reprototyping request and hooks
Gormartsen Mar 18, 2019
bb01254
decouple broadcast
Gormartsen Mar 18, 2019
7db6083
Fix typo
Gormartsen Mar 18, 2019
0eed8ad
Move code to sendHookNotify
Gormartsen Mar 18, 2019
7961736
Fix typos and move sendHookAdapter to module
Gormartsen Mar 18, 2019
4c62f4b
Codestyle fix
Gormartsen Mar 18, 2019
eef5b36
Replace getHookHeaders by get Headers
Gormartsen Mar 19, 2019
1ec47f6
Implement metrics send
Gormartsen Mar 19, 2019
419aab1
cleanup codestyle
Gormartsen Mar 19, 2019
1b8e5bd
Implement BuildURI to properly connect URI
Gormartsen Mar 19, 2019
a0d723a
Validate that endpointUrl is a string
Gormartsen Mar 19, 2019
6e35628
test cover buildURI
Gormartsen Mar 19, 2019
12f410e
test cover checkConditions
Gormartsen Mar 19, 2019
e73085c
Prototyping tests for different condition classes
Gormartsen Mar 19, 2019
0835fd0
test cover on checkPath
Gormartsen Mar 19, 2019
b11d939
test cover on decodeData
Gormartsen Mar 19, 2019
a947ef2
Codestyle
Gormartsen Mar 19, 2019
f08bc5b
Add proper support for tests
Gormartsen Mar 19, 2019
800e6aa
test cover findAllTargets
Gormartsen Mar 19, 2019
8b1caee
test cover for findHookTarget
Gormartsen Mar 19, 2019
17d7b7b
test cover for getHeaders
Gormartsen Mar 19, 2019
2520e8e
report it by header
Gormartsen Mar 19, 2019
1a947e9
codestyle fix
Gormartsen Mar 19, 2019
f62b668
Make more visually acceptable getHeader tests
Gormartsen Mar 19, 2019
4d888b2
test cover on getProperty
Gormartsen Mar 19, 2019
4c37b9b
fix checkPatj and add checkMatchRoute
Gormartsen Mar 19, 2019
83d8978
Rename test suites to match includes
Gormartsen Mar 19, 2019
1323cf9
general sendRequest test
Gormartsen Mar 19, 2019
dcbe9be
test cover on sendBroadcastMessage
Gormartsen Mar 20, 2019
01a58f6
First prototype
Gormartsen Mar 20, 2019
e4a7b68
Prepared for test cover sendHookAdapter
Gormartsen Mar 20, 2019
c631815
test cover on sendHook Adapter
Gormartsen Mar 20, 2019
43df40d
Update sendHookAdapter.js
Gormartsen Mar 20, 2019
b5a3bff
Code style
Gormartsen Mar 20, 2019
84b405b
test cover on sendHookBroadcast
Gormartsen Mar 20, 2019
5ed3297
test cover on SendHookNotify
Gormartsen Mar 20, 2019
57e4c45
Improve test coverage
Gormartsen Mar 20, 2019
b5d6576
cover test for metrics
Gormartsen Mar 20, 2019
637ec11
Code style fix
Gormartsen Mar 20, 2019
f111917
Improve test coverage
Gormartsen Mar 20, 2019
9d63234
Never true
Gormartsen Mar 20, 2019
ebfa82b
better test coverage
Gormartsen Mar 20, 2019
226cfbf
improve request test coverage
Gormartsen Mar 21, 2019
0f94f28
detect if adapter return broken json
Gormartsen Mar 21, 2019
91e4887
implement eslint rules "eol-last" "no-trailing-spaces"
Gormartsen Mar 21, 2019
9a4aea4
Performance improvement
Gormartsen Mar 21, 2019
dc8094b
Cleanup
Gormartsen Mar 21, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
{
"extends": [
"eslint:recommended"
],
"env": {
"node": true
},
"plugins": [
"mocha"
],
"parserOptions": {
"ecmaVersion": 6
},
"rules": {
"eol-last": [2],
"no-trailing-spaces" : [2],
"keyword-spacing": [
2,
{}
Expand All @@ -16,6 +27,23 @@
"max-len": [
2,
100
],
"comma-spacing": [
2,
{ "before": false, "after": true }
],
"space-infix-ops": [
2,
{"int32Hint": true}
]
},
"overrides": [
{
"files": [ "test/**/*.js" ],
"env": { "mocha": true },
"rules": {
"max-nested-callbacks": [ "error", 8 ]
}
}
]
}
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ node_modules
datastore
.env
pidfile
nocommit
.nyc_output
coverage
31 changes: 31 additions & 0 deletions includes/buildURI.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Build URI from routeItem.endpointUrl and targetRequest.path
*
* @param String endpointUrl
* @param String endpointUrl
*
* @return String URI
*/
'use strict';

module.exports = function(endpointUrl, path){
let URI = ''
if (endpointUrl && endpointUrl.length) {
URI += endpointUrl
if (endpointUrl[endpointUrl.length - 1] !== '/') {
URI += '/'
}
} else {
URI += '/'
}
if (path && path.length) {
for ( let i = 0; i < path.length; i++ ) {
if (path[i] !== '/') {
URI += path.substring(i)
break
}
}
}

return URI
}
76 changes: 76 additions & 0 deletions includes/checkConditions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* Check Conditions for request.
*
* @param Object conditions object with headers, payload and methods properties
* @param Object requestDetails http request details
* @param Object requestDetails http request json body.
*
* @return Boolean true if conditions are met
*/
'use strict';
const debug = require('debug')('proxy:check-conditions');
const getProperty = require('./getProperty.js')

module.exports = function(conditions, requestDetails, jsonData) {
debug('checkConditions %O requestDetails: %O json: %O', conditions, requestDetails, jsonData)
if (conditions.headers && conditions.headers.length) {
for (let header of conditions.headers ) {
if (!requestDetails.headers[header.name]) {
return false
}
let receivedHeaderValue = requestDetails.headers[header.name]
if (header.isRegex) {
let pattern = new RegExp(header.value, "i")
if (!pattern.test(receivedHeaderValue)) {
return false
}
} else {
if (receivedHeaderValue !== header.value) {
return false
}
}
}
}
// check methods
if (conditions.methods && conditions.methods.length) {
if (conditions.methods.toUpperCase) {
if (requestDetails.method != conditions.methods.toUpperCase()) {
return false
}
} else {
for (let i in conditions.methods) {
conditions.methods[i] = conditions.methods[i].toUpperCase()
}
if (conditions.methods.indexOf(requestDetails.method) === -1) {
return false;
}
}

}
// check payload
if (conditions.payload && conditions.payload.length && jsonData) {
if (typeof jsonData != "object") {
return false
}
for (let payload of conditions.payload ) {
debug('Checking for payload conditions %O', payload)
let receivedPayloadValue = getProperty(payload.name, jsonData)
debug('receivedPayloadValue %O', receivedPayloadValue)
if (receivedPayloadValue instanceof Error) {
return false
}
if (payload.isRegex) {
let pattern = new RegExp(payload.value, "i")
debug('pattern.test %O', pattern.test(receivedPayloadValue))
if (!pattern.test(receivedPayloadValue)) {
return false
}
} else {
if (receivedPayloadValue !== payload.value) {
return false
}
}
}
}
return true
}
49 changes: 49 additions & 0 deletions includes/checkConditionsMingo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Check Conditions for request.
*
* @param Object conditions object with headers, payload and methods properties
* @param Object requestDetails http request details
* @param Object requestDetails http request json body.
*
* @return Boolean true if conditions are met
*/
'use strict';
const debug = require('debug')('proxy:check-conditions');
const mingo = require('mingo')

module.exports = function(conditions, requestDetails, jsonData) {
debug('checkConditions %O requestDetails: %O json: %O', conditions, requestDetails, jsonData)
if (conditions.headers ) {
let query = new mingo.Query(conditions.headers);
if (!query.test(requestDetails.headers)){
return false
}
//return mingo.find([requestDetails.headers], conditions.headers).count()

}
// check methods
if (conditions.methods && conditions.methods.length) {
if (conditions.methods instanceof Array) {
for (let i in conditions.methods) {
conditions.methods[i] = conditions.methods[i].toUpperCase()
}
} else if (conditions.methods.toUpperCase){
conditions.methods = conditions.methods.toUpperCase()
}
if (conditions.methods.indexOf(requestDetails.method) === -1) {
return false;
}
}
// check payload
if (conditions.payload) {
if (typeof jsonData != "object") {
return false
}
//return mingo.find([jsonData], conditions.payload).count()
let query = new mingo.Query(conditions.payload);
if (!query.test(jsonData)) {
return false
}
}
return true
}
47 changes: 47 additions & 0 deletions includes/checkConditionsMongo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Check Conditions for request.
*
* @param Object conditions object with headers, payload and methods properties
* @param Object requestDetails http request details
* @param Object requestDetails http request json body.
*
* @return Boolean true if conditions are met
*/
'use strict';
const debug = require('debug')('proxy:check-conditions');
const sift = require('sift').default

module.exports = function(conditions, requestDetails, jsonData) {
debug('checkConditions %O requestDetails: %O json: %O', conditions, requestDetails, jsonData)
if (conditions.headers ) {
let result = sift(conditions.headers, [requestDetails.headers])
if (!result.length){
return false
}

}
// check methods
if (conditions.methods && conditions.methods.length) {
if (conditions.methods instanceof Array) {
for (let i in conditions.methods) {
conditions.methods[i] = conditions.methods[i].toUpperCase()
}
} else if (conditions.methods.toUpperCase){
conditions.methods = conditions.methods.toUpperCase()
}
if (conditions.methods.indexOf(requestDetails.method) === -1) {
return false;
}
}
// check payload
if (conditions.payload) {
if (typeof jsonData != "object") {
return false
}
let result = sift(conditions.payload, [jsonData])
if (!result.length){
return false
}
}
return true
}
44 changes: 44 additions & 0 deletions includes/checkPath.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Check if path match route path.
*
* @param Object targetRequest request details
* @param Object routeItem ob route table
*
* @return Boolean true if conditions are met
*/
'use strict';

module.exports = function(targetRequest, routeItem) {
let targetRoutePathItems = targetRequest.route.split('/');

// routeItem is array of supporthed path (endpoints like /foo /bar/:test/foo)
for (let path of routeItem.path) {
// If route qual saved path
if (path == targetRequest.route) {
return true;
}

// If targetRoutePathItems.length == 1, and did not match
if (targetRoutePathItems.length == 1) {
continue;
}

let pathItems = path.split('/');
if (pathItems.length != targetRoutePathItems.length) {
continue;
}

routeItem.matchVariables = {}
for (var i = 0; i < targetRoutePathItems.length; i++) {
if (pathItems[i].charAt(0) == ':') {
routeItem.matchVariables[pathItems[i].substring(1)] = targetRoutePathItems[i];
} else {
if (targetRoutePathItems[i] != pathItems[i]) {
//if not matching items
return false
}
}
}
return true;
}
}
25 changes: 25 additions & 0 deletions includes/decodeData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Decode buffer to specidied by content-type format.
*
* @param String phase(optional) hook phase: before, after, metric
* @param Buffer type(optional) hook type: adapter, notify, broadcast
*
* @return return buffer or object
*/
'use strict';

module.exports = function(contentType, buffer){
let data = false
switch (contentType) {
case undefined: // version 1.x compatibility. If no content-type provided, assume json.
case 'application/json': {
data = JSON.parse(buffer);
break;
}
// Todo support more decoders here?
default: {
data = buffer
}
}
return data
}
50 changes: 50 additions & 0 deletions includes/findAllTargets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Find all targets function
*
* @param Object targetRequest request details
* @param String routeType(optional) of router: hook, handler, metric
* @param Object object all available routes
*
* @return array of objects with available routes
*/
'use strict';

const debug = require('debug')('proxy:find-all-targets');
const matchRoute = require('./matchRoute.js')

module.exports = function(targetRequest, routeType, allRegisteredRoutes) {
debug('Find all routes %s', targetRequest.route);

var availableRoutes = [];
for (let i in allRegisteredRoutes) {
if (routeType) {
if (!allRegisteredRoutes[i].type) {
// Version 1.x compatibility
allRegisteredRoutes[i].type = "handler"
}
if (allRegisteredRoutes[i].type.toLowerCase() !== routeType) {
continue
}
}
// For easy deployment when service need to stop receiving new requests.
// Version 1.x compatibility
if (allRegisteredRoutes[i].online !== undefined) {
if (allRegisteredRoutes[i].online === false) {
continue
}
}
// Making copy of the router.
let routeItem = JSON.parse(JSON.stringify(allRegisteredRoutes[i]));
routeItem.matchVariables = {};
if (matchRoute(targetRequest, routeItem)) {
availableRoutes.push(routeItem);
}
}
debug('Available routes type: %s route: %s availableRoutes: %s', routeType,
targetRequest.route, JSON.stringify(availableRoutes, null, 2));
if (availableRoutes.length == 0) {
debug('Not found for %s', targetRequest.route);
return new Error('Endpoint not found');
}
return availableRoutes;
}
Loading