diff --git a/README.md b/README.md index 84fd25be..4bffe244 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,15 @@ The development server has already a set of middlewares which supports the devel * Version info is created automatically (`/resources/sap-ui-version.json`). * List project files with URL (needed exclusively by the OpenUI5 testsuite): `/discovery/app_pages`, `/discovery/all_libs`, `/discovery/all_tests` +### Proxy requests +A neo-app.json and neo-dest.json file can be added to the project and used to proxy requests to an SAP gateway server for example. When you create your UI5 serve you need to add the path to the neo files. +The neo-app.json file can be reused from a WebIDE template, the neo-dest.json file is a json object that has the target name and the following attributes is available +* target : Target url +* Authentication : Authentication method, currently only basic is supported +* User : Username +* Password : Password for the proxy request +* sapclient : SAP Client + ## Certificates for HTTPS or HTTP/2 The UI5 Server can automatically generate an SSL certificate for HTTPS and HTTP/2 configurations. diff --git a/lib/server.js b/lib/server.js index 39cd320c..874ef72e 100644 --- a/lib/server.js +++ b/lib/server.js @@ -14,6 +14,8 @@ const nonReadRequests = require("./middleware/nonReadRequests"); const ui5Fs = require("@ui5/fs"); const resourceFactory = ui5Fs.resourceFactory; const ReaderCollectionPrioritized = ui5Fs.ReaderCollectionPrioritized; +const proxy = require("http-proxy-middleware"); +const noCache = require("nocache"); /** * Returns a promise resolving by starting the server. @@ -104,13 +106,19 @@ module.exports = { * @param {string} [options.cert] Path to certificate to be used for for https * @param {boolean} [options.acceptRemoteConnections=false] If true, listens to remote connections and * not only to localhost connections + * @param {Object} [options.neoApp] an JSON object that has the routes for proxy + * @param {Object} [options.destinations] Json object with the destination attributes for proxy * @returns {Promise} Promise resolving once the server is listening. * It resolves with an object containing the port, * h2-flag and a close function, * which can be used to stop the server. */ - serve(tree, {port, changePortIfInUse = false, h2 = false, key, cert, acceptRemoteConnections = false}) { + serve(tree, {port, changePortIfInUse = false, h2 = false, key, cert, acceptRemoteConnections = false, neoApp, destinations}) { return Promise.resolve().then(() => { + // Load the neo-app.json and the neo-dest.json file + const oNeoApp = neoApp; + const oDestinations = destinations; + const projectResourceCollections = resourceFactory.createCollectionsForTree(tree); const workspace = resourceFactory.createWorkspace({ @@ -170,6 +178,53 @@ module.exports = { secure: false })); + // no odata cache (including metadata) + app.use("/sap/opu", noCache()); + + // Proxy the neo-app.json and neo-dest.json files + if (oNeoApp && oNeoApp.routes) { + oNeoApp.routes.forEach(function(oRoute) { + const oTarget = oRoute.target; + if (oTarget) { + // proxy options + const oOptions = {}; + // search for destination + if (oDestinations && oTarget.name) { + const oDestination = oDestinations[oTarget.name]; + if (oDestination) { + oOptions.target = oDestination.target; + oOptions.changeOrigin = true; + oOptions.secure = false; + /* if (oDestination.useProxy) { + oOptions.agent = oAgent; + }*/ + + // Added support for client and basic authentication + if (oDestination.sapclient) { + oOptions.onProxyReq = function onProxyReq(proxyReq, req, res) { + req.originalUrl = req.originalUrl + "&sap-client=" +oDestination.sapclient; + }; + } + + if (oDestination.Authentication === "Basic") { + oOptions.headers = { + "Authorization": "Basic " + Buffer.from(oDestination.User + + ":" + oDestination.Password).toString("base64") + }; + } + } + } + if (oRoute.path && oTarget.entryPath) { + const oRouteNew = {}; + const sPathOld = "^" + oRoute.path; + oRouteNew[sPathOld] = oTarget.entryPath; + oOptions.pathRewrite = oRouteNew; + } + app.use(oRoute.path, proxy(oOptions)); + } + }); + } + // Handle anything but read operations *before* the serveIndex middleware // as it will reject them with a 405 (Method not allowed) instead of 404 like our old tooling app.use(nonReadRequests({resourceCollections})); diff --git a/package-lock.json b/package-lock.json index c9121728..0284e550 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3118,7 +3118,6 @@ "version": "1.8.2", "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dev": true, "requires": { "fill-range": "^2.1.0" }, @@ -3127,7 +3126,6 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "dev": true, "requires": { "is-number": "^2.1.0", "isobject": "^2.0.0", @@ -3140,7 +3138,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true, "requires": { "kind-of": "^3.0.2" } @@ -3149,7 +3146,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, "requires": { "isarray": "1.0.0" } @@ -3158,7 +3154,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -3365,8 +3360,7 @@ "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" }, "fill-range": { "version": "4.0.0", @@ -3484,7 +3478,6 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, "requires": { "for-in": "^1.0.1" } @@ -3553,8 +3546,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -3575,14 +3567,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3597,20 +3587,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -3727,8 +3714,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -3740,7 +3726,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3755,7 +3740,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3763,14 +3747,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -3789,7 +3771,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -3870,8 +3851,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -3883,7 +3863,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3969,8 +3948,7 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -4006,7 +3984,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4026,7 +4003,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4070,14 +4046,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -4161,7 +4135,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dev": true, "requires": { "glob-parent": "^2.0.0", "is-glob": "^2.0.0" @@ -4171,7 +4144,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, "requires": { "is-glob": "^2.0.0" } @@ -4391,6 +4363,121 @@ "requires-port": "^1.0.0" } }, + "http-proxy-middleware": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz", + "integrity": "sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=", + "requires": { + "http-proxy": "^1.16.2", + "is-glob": "^3.1.0", + "lodash": "^4.17.2", + "micromatch": "^2.3.11" + }, + "dependencies": { + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "requires": { + "is-extglob": "^1.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + } + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "^1.0.0" + } + } + } + } + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -4715,14 +4802,12 @@ "is-dotfile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" }, "is-equal-shallow": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, "requires": { "is-primitive": "^2.0.0" } @@ -4741,8 +4826,7 @@ "is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" }, "is-finite": { "version": "1.0.2", @@ -4771,7 +4855,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, "requires": { "is-extglob": "^1.0.0" } @@ -4859,14 +4942,12 @@ "is-posix-bracket": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" }, "is-primitive": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" }, "is-promise": { "version": "2.1.0", @@ -5418,8 +5499,7 @@ "math-random": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", - "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", - "dev": true + "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=" }, "md5-hex": { "version": "2.0.0", @@ -5797,6 +5877,12 @@ } } }, + "nocache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.0.0.tgz", + "integrity": "sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA=", + "dev": true + }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", @@ -5812,7 +5898,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" } @@ -6934,7 +7019,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, "requires": { "for-own": "^0.1.4", "is-extendable": "^0.1.1" @@ -7212,7 +7296,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, "requires": { "glob-base": "^0.3.0", "is-dotfile": "^1.0.0", @@ -7371,8 +7454,7 @@ "preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" }, "pretty-data": { "version": "0.40.0", @@ -7471,7 +7553,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz", "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==", - "dev": true, "requires": { "is-number": "^4.0.0", "kind-of": "^6.0.0", @@ -7481,8 +7562,7 @@ "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" } } }, @@ -7652,7 +7732,6 @@ "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "dev": true, "requires": { "is-equal-shallow": "^0.1.3" } @@ -7729,8 +7808,7 @@ "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" }, "repeat-element": { "version": "1.1.2", diff --git a/package.json b/package.json index 96538806..04e4367d 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,8 @@ "prompt": "^1.0.0", "replacestream": "^4.0.3", "spdy": "^3.4.7", - "treeify": "^1.0.1" + "treeify": "^1.0.1", + "http-proxy-middleware": "^0.17.4" }, "devDependencies": { "ava": "^0.25.0", @@ -121,6 +122,7 @@ "eslint-plugin-jsdoc": "^4.0.1", "jsdoc": "^3.5.5", "mock-require": "^3.0.3", + "nocache": "^2.0.0", "nyc": "^13.3.0", "opn-cli": "^4.0.0", "rimraf": "^2.6.3", diff --git a/test/lib/server/main.js b/test/lib/server/main.js index 151e2377..275b4183 100644 --- a/test/lib/server/main.js +++ b/test/lib/server/main.js @@ -3,7 +3,8 @@ const supertest = require("supertest"); const ui5Server = require("../../../"); const server = ui5Server.server; const normalizer = require("@ui5/project").normalizer; - +const neoApp = require("./neo-app.json"); +const destinations = require("./neo-dest.json"); let request; let serve; @@ -13,7 +14,9 @@ test.before((t) => { cwd: "./test/fixtures/application.a" }).then((tree) => { return server.serve(tree, { - port: 3333 + port: 3333, + neoApp: neoApp, + destinations: destinations }).then((serveResult) => { request = supertest("http://localhost:3333"); serve = serveResult; @@ -366,3 +369,25 @@ test("Get index of resources", (t) => { }) ]); }); + +test("Get odata from Northwind destination", + (t) => { + return request.get("/z_northwind/V2/Northwind/Northwind.svc/$metadata").then((res) => { + if (res.error) { + t.fail(res.error.text); + } + t.deepEqual(res.statusCode, 200, "Correct HTTP status code"); + t.regex(res.headers["content-type"], /xml/, "Correct content type"); + }); + }); + +test("Get odata from SAPDevCenter destination", + (t) => { + return request.get("/sap/opu/odata/IWBEP/GWSAMPLE_BASIC/$metadata").then((res) => { + if (res.error) { + t.fail(res.error.text); + } + t.deepEqual(res.statusCode, 200, "Correct HTTP status code"); + t.regex(res.headers["content-type"], /xml/, "Correct content type"); + }); + }); diff --git a/test/lib/server/neo-app.json b/test/lib/server/neo-app.json new file mode 100644 index 00000000..c39f1492 --- /dev/null +++ b/test/lib/server/neo-app.json @@ -0,0 +1,21 @@ +{ + "routes": [ + { + "path": "/z_northwind", + "target": { + "type": "destination", + "name": "northwind", + "entryPath": "/" + } + }, + { + "path": "/sap/opu/odata/", + "target": { + "type": "destination", + "name": "sapdevcenter", + "entryPath": "/sap/opu/odata/" + } + } + ] + } + diff --git a/test/lib/server/neo-dest.json b/test/lib/server/neo-dest.json new file mode 100644 index 00000000..716fcaf2 --- /dev/null +++ b/test/lib/server/neo-dest.json @@ -0,0 +1,10 @@ +{ + "northwind": { + "target": "https://services.odata.org" + }, + + "sapdevcenter": { + "target": "https://sapes5.sapdevcenter.com", + "sapclient": "002" + } + }