Merge branch 'master' of https://github.com/srinandan/microgateway-plugins
diff --git a/.gitignore b/.gitignore index 3c0ac2f..23d4050 100644 --- a/.gitignore +++ b/.gitignore
@@ -34,4 +34,5 @@ .vscode .idea -.DS_Store \ No newline at end of file +.DS_Store +env.sh
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..e49a3ea --- /dev/null +++ b/.travis.yml
@@ -0,0 +1,4 @@ +language: node_js +node_js: +- '6.3.1' +
diff --git a/README.md b/README.md index 9311c2f..36f5d8b 100644 --- a/README.md +++ b/README.md
@@ -1,5 +1,7 @@ #Plugins +Build Status [](https://travis-ci.org/apigee/microgateway-plugins) + ##Overview This repo contains plugins for the [microgateway-core project](https://github.com/apigee/microgateway-core). @@ -55,4 +57,4 @@ ```javascript next([err]) -``` \ No newline at end of file +```
diff --git a/accumulate-request/index.js b/accumulate-request/index.js index b1e7643..d162087 100644 --- a/accumulate-request/index.js +++ b/accumulate-request/index.js
@@ -14,7 +14,6 @@ * should only be used when it is known that request/response bodies are small. */ module.exports.init = function(config, logger, stats) { - function accumulate(req, data) { if (!req._chunks) req._chunks = []; req._chunks.push(data); @@ -29,11 +28,13 @@ onend_request: function(req, res, data, next) { if (data && data.length > 0) accumulate(req, data); - var content = Buffer.concat(req._chunks); + var content = null; + if (req._chunks && req._chunks.length) { + content = Buffer.concat(req._chunks); + } delete req._chunks; next(null, content); } - }; }
diff --git a/accumulate-response/index.js b/accumulate-response/index.js index 8be60af..1ff26a2 100644 --- a/accumulate-response/index.js +++ b/accumulate-response/index.js
@@ -29,7 +29,10 @@ onend_response: function(req, res, data, next) { if (data && data.length > 0) accumulate(res, data); - var content = Buffer.concat(res._chunks); + var content = null; + if(res._chunks && res._chunks.length) { + content = Buffer.concat(res._chunks); + } delete res._chunks; next(null, content); }
diff --git a/analytics/index.js b/analytics/index.js index 23c57c7..175ca09 100644 --- a/analytics/index.js +++ b/analytics/index.js
@@ -9,6 +9,15 @@ record.apiproxy = res.proxy.name; record.apiproxy_revision = res.proxy.revision; } + + if(config.mask_request_uri) { + record.request_uri = config.mask_request_uri; + } + + if(config.mask_request_path) { + record.request_path = config.mask_request_path; + } + cb(null, record); };
diff --git a/cache/index.js b/cache/index.js deleted file mode 100644 index e7c08b0..0000000 --- a/cache/index.js +++ /dev/null
@@ -1,67 +0,0 @@ -'use strict'; - -var cache = require('volos-cache-memory'); -var async = require('async'); -var debug = require('debug')('gateway:cache'); - -var getKey = function (req) { - return req.token.application_name; -} -var caches = []; - -var middleware = function (req, res, next) { - if (!req.token - || !req.token.api_product_list - || !req.token.api_product_list.length - ) { - return next(); - } - - debug('cache checking products', req.token.api_product_list); - - req.originalUrl = req.originalUrl || req.url; // emulate connect - - var found = false; - // this is arbitrary, but not sure there's a better way? - async.eachSeries(req.token.api_product_list, - function (productName, cb) { - if(!found) { - var cache = caches[productName]; - executeDefaultCache(cache, req, res, cb); - found = true; - }else{ - cb(); - } - }, - function (err) { - next(err); - } - ); -} - -var executeDefaultCache = function (cache, req, res, cb) { - cb(); -}; - -module.exports.init = function (config, logger, stats) { - var options = { - key: getKey - }; - Object.keys(config).forEach(function (productName) { - var product = config[productName]; - if (!product.ttl) { - debug('could not load cache for ' + productName + ' because ttl is missing', product) - return; // skip non-cache config - } - var cacheInstance = cache.create(config[productName]); - caches[productName] = cacheInstance; - debug('created cache for', productName); - debug('caches are ', caches) - }); - - return { - onrequest: function (req, res, next) { - middleware(req, res, next); - } - }; -}; \ No newline at end of file
diff --git a/cache/package.json b/cache/package.json deleted file mode 100644 index 7516753..0000000 --- a/cache/package.json +++ /dev/null
@@ -1,19 +0,0 @@ -{ - "name": "edgemicro-plugin-cache", - "version": "1.0.0", - "description": "caching plugin for the gateway", - "main": "index.js", - "scripts": { - "test": "mocha tests" - }, - "author": "sfeldman@apigee.com", - "dependencies": { - "async": "^1.5.2", - "debug": "^2.2.0", - "volos-cache-memory": "^0.10.0" - }, - "devDependencies": { - "mocha": "^2.4.5", - "should": "^8.2.1" - } -}
diff --git a/cache/tests/testIndex.js b/cache/tests/testIndex.js deleted file mode 100644 index a55c654..0000000 --- a/cache/tests/testIndex.js +++ /dev/null
@@ -1,12 +0,0 @@ -var should = require('should'); -var assert = require('assert'); -var plugin = require('../index'); -describe('construct',function(){ - it('should work',function(done){ - var req = plugin.init(); - req.onrequest(null,null,function(err){ - should(err).be.null - done(); - }) - }) ; -}); \ No newline at end of file
diff --git a/index.js b/index.js index 01f90dd..fd4f20a 100644 --- a/index.js +++ b/index.js
@@ -4,7 +4,6 @@ 'accumulate-request':require('./accumulate-request'), 'accumulate-response':require('./accumulate-response'), analytics:require('./analytics'), - cache:require('./cache'), 'header-uppercase':require('./header-uppercase'), oauth:require('./oauth'), quota:require('./quota'), @@ -13,4 +12,6 @@ 'transform-uppercase':require('./transform-uppercase'), accesscontrol:require('./accesscontrol'), eurekaclient:require('./eurekaclient') + json2xml: require('./json2xml'), + healthcheck: require('./healthcheck') }
diff --git a/json2xml/index.js b/json2xml/index.js index 2b78e72..8548727 100644 --- a/json2xml/index.js +++ b/json2xml/index.js
@@ -74,14 +74,14 @@ //if plugin is disabled don't process headers. if (!disable) { - if (method === "get" && acceptType === "application/xml") { + if (method === "get" && acceptType.indexOf("application/xml") > -1) { responseXML = true; - } else if (method === "get" && acceptType === "application/json") { + } else if (method === "get" && acceptType.indexOf("application/json") > -1) { responseJSON = true; - } else if (method !== "get" && contentType === "application/json") { + } else if (method !== "get" && contentType.indexOf("application/json") > -1) { requestJSON = true; responseJSON = true; - } else if (method !== "get" && contentType === "application/xml") { + } else if (method !== "get" && contentType.indexOf("application/xml") > -1) { requestXML = true; responseXML = true; } @@ -156,9 +156,9 @@ if (data && data.length > 0 && disable == false) accumulateResponse(res, data); var contentType = res.getHeader('content-type'); - if (contentType === "application/xml") { + if (contentType.indexOf("application/xml") > -1) { responseIsXML = true; - } else if (contentType === "application/json") { + } else if (contentType.indexOf("application/json") > -1) { responseIsJSON = true; } @@ -191,4 +191,4 @@ } } }; -} \ No newline at end of file +}
diff --git a/package.json b/package.json index 09aa659..a068b50 100644 --- a/package.json +++ b/package.json
@@ -1,22 +1,25 @@ { "name": "microgateway-plugins", - "version": "2.0.4", + "version": "2.3.5", "description": "Plugins for Apige Edge Microgateway", "main": "index.js", "scripts": { - "test": "bin/test" + "test": "./node_modules/.bin/mocha -R spec" }, "dependencies": { "async": "^1.4.2", "debug": "^2.2.0", - "volos-spikearrest-memory": "^0.10.0", - "volos-quota-memory": "^0.11.0", - "volos-quota-apigee": "^0.13.0", + "js2xmlparser": "^2.0.2", "jsonwebtoken": "^5.0.1", "lodash": "^3.10.1", "request": "^2.65.0", + "toobusy-js": "^0.5.1", + "volos-analytics-apigee": "^0.4.0", "volos-cache-memory": "^0.10.0", - "volos-analytics-apigee": "^0.4.0" + "volos-quota-apigee": "^0.13.0", + "volos-quota-memory": "^0.11.0", + "volos-spikearrest-memory": "^0.10.0", + "xml2js": "^0.4.17" }, "devDependencies": { "js-yaml": "^3.4.2",
diff --git a/quota-memory/index.js b/quota-memory/index.js index 6d0579d..337bf6e 100644 --- a/quota-memory/index.js +++ b/quota-memory/index.js
@@ -5,7 +5,6 @@ var debug = require('debug')('gateway:quota'); module.exports.init = function(config, logger, stats) { - var quotas = {}; // productName -> connectMiddleware var options = { @@ -14,7 +13,10 @@ Object.keys(config).forEach(function(productName) { var product = config[productName]; - if (!product.uri && !product.key && !product.secret && !product.allow && !product.interval) return; // skip non-quota config + if (!product.uri && !product.key && !product.secret && !product.allow && !product.interval) { + return; // skip non-quota config + } + var quota = Quota.create(config[productName]); quotas[productName] = quota.connectMiddleware().apply(options); debug('created quota for', productName);
diff --git a/quota/index.js b/quota/index.js index 0830ecf..7e377fb 100644 --- a/quota/index.js +++ b/quota/index.js
@@ -9,12 +9,19 @@ var quotas = {}; // productName -> connectMiddleware var options = { - key: function(req) { return req.token.application_name; } + key: function(req) { + return req.token.application_name; + } }; Object.keys(config).forEach(function(productName) { var product = config[productName]; - if (!product.uri && !product.key && !product.secret && !product.allow && !product.interval) return; // skip non-quota config + if (!product.uri && !product.key && !product.secret && !product.allow && !product.interval) { + // skip non-quota config + console.log('Not enough info for configuring quota'); + return; + } + var quota = Quota.create(config[productName]); quotas[productName] = quota.connectMiddleware().apply(options); debug('created quota for', productName);
diff --git a/test/accumulate-request-test.js b/test/accumulate-request-test.js new file mode 100644 index 0000000..1983c25 --- /dev/null +++ b/test/accumulate-request-test.js
@@ -0,0 +1,107 @@ +const accumulateRequest = require('../accumulate-request/index'); +const assert = require('assert'); + +describe('accumulate request plugin', () => { + var plugin = null; + + beforeEach(() => { + var config = {}; + var logger = {}; + var stats = {}; + + plugin = accumulateRequest.init.apply(null, [config, logger, stats]); + }); + + it('exposes an ondata_request handler', () => { + assert.ok(plugin.ondata_request); + }); + + it('exposes an onend_request handler', () => { + assert.ok(plugin.onend_request); + }); + + it('calls back with two null function arguments in the ondata_request handler', (done) => { + var cb = (err, result) => { + assert.equal(err, null); + assert.equal(result, null); + done(); + } + + + plugin.ondata_request.apply(null, [{}, {}, Buffer.alloc(5, 'a'), cb]); + }); + + it('will collect all buffers provided to ondata_request handler, concatenate them, and return them as a single buffer', (done) => { + var desiredResult = 'aaaaaaaaaaaaaaa'; + + var ondata_cb = (err, result) => { + assert.equal(err, null); + assert.equal(result, null); + assert.ok(req._chunks); + } + + var onend_cb = (err, result) => { + assert.equal(err, null); + assert.equal(result.toString(), desiredResult); + done(); + } + + var req = {}; + + plugin.ondata_request.apply(null, [req, {}, Buffer.alloc(5, 'a'), ondata_cb]); + plugin.ondata_request.apply(null, [req, {}, Buffer.alloc(5, 'a'), ondata_cb]); + plugin.ondata_request.apply(null, [req, {}, Buffer.alloc(5, 'a'), ondata_cb]); + + plugin.onend_request.apply(null, [req, {}, null, onend_cb]); + }); + + it('will append data included in the end call to the buffer', (done) => { + var desiredResult = 'aaaaaaaaaaaaaaaaaaaa'; + + var ondata_cb = (err, result) => { + assert.equal(err, null); + assert.equal(result, null); + assert.ok(req._chunks); + } + + var onend_cb = (err, result) => { + assert.equal(err, null); + assert.equal(result.toString(), desiredResult); + done(); + } + + var req = {}; + + plugin.ondata_request.apply(null, [req, {}, Buffer.alloc(5, 'a'), ondata_cb]); + plugin.ondata_request.apply(null, [req, {}, Buffer.alloc(5, 'a'), ondata_cb]); + plugin.ondata_request.apply(null, [req, {}, Buffer.alloc(5, 'a'), ondata_cb]); + + plugin.onend_request.apply(null, [req, {}, Buffer.alloc(5, 'a'), onend_cb]); + }); + + it('will create a req._chunks object on the request object', (done) => { + var req = {}; + var cb = (err, result) => { + assert.equal(err, null); + assert.equal(result, null); + assert.ok(req._chunks); + assert.equal(req._chunks.toString(), 'aaaaa'); + done(); + } + + plugin.ondata_request.apply(null, [req, {}, Buffer.alloc(5, 'a'), cb]); + }); + + it('will call the callback with null if no data events are provided.', (done) => { + var onend_cb = (err, result) => { + assert.equal(err, null); + assert.equal(result, null); + done(); + } + + var req = {}; + + plugin.onend_request.apply(null, [req, {}, null, onend_cb]); + + }); +})
diff --git a/test/accumulate-response-test.js b/test/accumulate-response-test.js new file mode 100644 index 0000000..0a13840 --- /dev/null +++ b/test/accumulate-response-test.js
@@ -0,0 +1,107 @@ +const accumulateResponse = require('../accumulate-response/index'); +const assert = require('assert'); + +describe('accumulate response plugin', () => { + var plugin = null; + + beforeEach(() => { + var config = {}; + var logger = {}; + var stats = {}; + + plugin = accumulateResponse.init.apply(null, [config, logger, stats]); + }); + + it('exposes an ondata_response handler', () => { + assert.ok(plugin.ondata_response); + }); + + it('exposes an onend_response handler', () => { + assert.ok(plugin.onend_response); + }); + + it('calls back with two null function arguments in the ondata_response handler', (done) => { + var cb = (err, result) => { + assert.equal(err, null); + assert.equal(result, null); + done(); + } + + + plugin.ondata_response.apply(null, [{}, {}, Buffer.alloc(5, 'a'), cb]); + }); + + it('will collect all buffers provided to ondata_response handler, concatenate them, and return them as a single buffer', (done) => { + var desiredResult = 'aaaaaaaaaaaaaaa'; + + var ondata_cb = (err, result) => { + assert.equal(err, null); + assert.equal(result, null); + assert.ok(res._chunks); + } + + var onend_cb = (err, result) => { + assert.equal(err, null); + assert.equal(result.toString(), desiredResult); + done(); + } + + var res = {}; + + plugin.ondata_response.apply(null, [{}, res, Buffer.alloc(5, 'a'), ondata_cb]); + plugin.ondata_response.apply(null, [{}, res, Buffer.alloc(5, 'a'), ondata_cb]); + plugin.ondata_response.apply(null, [{}, res, Buffer.alloc(5, 'a'), ondata_cb]); + + plugin.onend_response.apply(null, [{}, res, null, onend_cb]); + }); + + it('will append data included in the end call to the buffer', (done) => { + var desiredResult = 'aaaaaaaaaaaaaaaaaaaa'; + + var ondata_cb = (err, result) => { + assert.equal(err, null); + assert.equal(result, null); + assert.ok(res._chunks); + } + + var onend_cb = (err, result) => { + assert.equal(err, null); + assert.equal(result.toString(), desiredResult); + done(); + } + + var res = {}; + + plugin.ondata_response.apply(null, [{}, res, Buffer.alloc(5, 'a'), ondata_cb]); + plugin.ondata_response.apply(null, [{}, res, Buffer.alloc(5, 'a'), ondata_cb]); + plugin.ondata_response.apply(null, [{}, res, Buffer.alloc(5, 'a'), ondata_cb]); + + plugin.onend_response.apply(null, [{}, res, Buffer.alloc(5, 'a'), onend_cb]); + }); + + it('will create a res._chunks object on the request object', (done) => { + var res = {}; + var cb = (err, result) => { + assert.equal(err, null); + assert.equal(result, null); + assert.ok(res._chunks); + assert.equal(res._chunks.toString(), 'aaaaa'); + done(); + } + + plugin.ondata_response.apply(null, [{}, res, Buffer.alloc(5, 'a'), cb]); + }); + + it('will callback with null if no response body is present in targetResponse', (done) => { + var res = {}; + var cb = (err, result) => { + assert.equal(err, null); + assert.equal(result, null); + done(); + } + + plugin.onend_response.apply(null, [{}, res, null, cb]); + + }); + +})
diff --git a/test/quota-test.js b/test/quota-test.js new file mode 100644 index 0000000..e8a2a31 --- /dev/null +++ b/test/quota-test.js
@@ -0,0 +1,93 @@ +const quota = require('../quota/index'); +const assert = require('assert'); + +var exampleConfig = { + EdgeMicroTestProduct: { + allow: process.env.QUOTA_ALLOW, + interval: Number(process.env.QUOTA_INTERVAL), + timeUnit: process.env.QUOTA_TIMEUNIT, + bufferSize: process.env.QUOTA_BUFFERSIZE, + uri: process.env.QUOTA_URI, + key: process.env.QUOTA_KEY, + secret: process.env.QUOTA_SECRET + } +} + +describe('quota plugin', () => { + var plugin = null; + + beforeEach(() => { + var logger = {}; + var stats = {}; + + plugin = quota.init.apply(null, [exampleConfig, logger, stats]); + + }); + + it('exposes an onrequest handler', () => { + assert.ok(plugin.onrequest); + }); + + it('will quota limit after 3 API calls', (done) => { + var count = 0; + var onrequest_cb = (err) => { + count++; + if(count == 4) { + assert.equal(count, 4); + assert.equal(err.message, 'exceeded quota'); + done(); + } + }; + + var req = { + token: { + application_name: '0e7762f4-ea67-4cc1-ae4a-21598c35b18f', + api_product_list: ['EdgeMicroTestProduct'] + } + } + + var res = { + headers: {}, + setHeader: (key, val) => { + res.headers[key] = val; + } + } + + plugin.onrequest.apply(null, [req, res, onrequest_cb]); + plugin.onrequest.apply(null, [req, res, onrequest_cb]); + plugin.onrequest.apply(null, [req, res, onrequest_cb]); + plugin.onrequest.apply(null, [req, res, onrequest_cb]); + }); + + it('will not quota limit before 3 API calls', (done) => { + var count = 0; + var onrequest_cb = (err) => { + count++; + if(count == 3) { + assert.equal(count, 3); + assert.ok(!(err instanceof Error)); + done(); + } + }; + + var req = { + token: { + application_name: '0e7762f4-ea67-4cc1-ae4a-21598c35b18f', + api_product_list: ['EdgeMicroTestProduct'] + } + } + + var res = { + headers: {}, + setHeader: (key, val) => { + res.headers[key] = val; + } + } + + plugin.onrequest.apply(null, [req, res, onrequest_cb]); + plugin.onrequest.apply(null, [req, res, onrequest_cb]); + plugin.onrequest.apply(null, [req, res, onrequest_cb]); + }); +}); + +
diff --git a/test/spike-arrest-test.js b/test/spike-arrest-test.js new file mode 100644 index 0000000..409eb77 --- /dev/null +++ b/test/spike-arrest-test.js
@@ -0,0 +1,48 @@ +const spikeArrest = require('../spikearrest/index'); +const assert = require('assert'); + +describe('spike arrest plugin', () => { + var plugin = null; + + beforeEach(() => { + var config = { + timeUnit: 'minute', + bufferSize: 0, + allow: 1 + }; + var logger = {}; + var stats = {}; + + plugin = spikeArrest.init.apply(null, [config, logger, stats]); + }); + + it('exposes an onrequest handler', () => { + assert.ok(plugin.onrequest); + }); + + it('will accept a request', (done) => { + var onrequest_cb = () => { + done(); + }; + + var req = {}; + var res = {}; + plugin.onrequest.apply(null, [req, res, onrequest_cb]); + }); + + it('will reject a requests that come in too fast', (done) => { + var onrequest_cb = () => { + }; + + var onrequest_cb_second = (req, res, next) => { + assert.ok(req instanceof Error); + assert.equal(req.message, 'SpikeArrest engaged'); + done(); + }; + + var req = {}; + var res = {}; + plugin.onrequest.apply(null, [req, res, onrequest_cb]); + plugin.onrequest.apply(null, [req, res, onrequest_cb_second]); + }); +});