From dff548b372cef6af82e0932424622fc3efc9ca05 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Fri, 9 Aug 2019 15:28:41 +0200 Subject: [PATCH] Handle local dependencies correctly Especially libraries where not handled correctly. ABAP URI retrieval now moved to type formatters --- lib/middleware/proxyRewrite.js | 28 +++++++++------ lib/proxyConfiguration.js | 66 ++++++++++++++++++++++++++++------ 2 files changed, 73 insertions(+), 21 deletions(-) diff --git a/lib/middleware/proxyRewrite.js b/lib/middleware/proxyRewrite.js index 2b76aa78..94397207 100644 --- a/lib/middleware/proxyRewrite.js +++ b/lib/middleware/proxyRewrite.js @@ -1,14 +1,17 @@ const log = require("@ui5/logger").getLogger("server:middleware:proxyRewrite"); function createMiddleware({resources, configuration, cdnUrl}) { - const resourceRootPath = !configuration.appOnly && configuration.destination.ui5Root; - const applicationRootPath = configuration.destination.appRoot; + const rewriteRootPaths = configuration.rewriteRootPaths; + const cacheBusterRegex = /~.*~[A-Z0-9]?\/?/; const preloadRegex = /^.*(?:Component-preload\.js|library-preload\.js|library-preload\.json)$/i; return function proxyRewrite(req, res, next) { - if ((!resourceRootPath || req.path.indexOf(resourceRootPath) === -1) && - (!applicationRootPath || req.path.indexOf(applicationRootPath) === -1)) { + const rewriteApplicable = Object.keys(rewriteRootPaths).some((resourceRootPath) => { + return req.path.indexOf(resourceRootPath) !== -1; + }); + + if (!rewriteApplicable) { // No normalization applicable next(); return; @@ -82,14 +85,19 @@ function createMiddleware({resources, configuration, cdnUrl}) { async function normalizeRequestPath(reqPath) { let normalizedPath = reqPath; - if (resourceRootPath && normalizedPath.indexOf(resourceRootPath) !== -1) { - normalizedPath = normalizedPath.substr(resourceRootPath.length); - } else if (applicationRootPath && normalizedPath.indexOf(applicationRootPath) !== -1) { - normalizedPath = normalizedPath.substr(applicationRootPath.length); + // Strip off first matching rewrite root path + for (const rootPath in rewriteRootPaths) { + if (rewriteRootPaths.hasOwnProperty(rootPath)) { + if (normalizedPath.indexOf(rootPath) !== -1) { + normalizedPath = normalizedPath.substr(rootPath.length); + if (rewriteRootPaths[rootPath].rewriteTo) { + normalizedPath = rewriteRootPaths[rootPath].rewriteTo + normalizedPath; + } + break; + } + } } - normalizedPath = normalizedPath.replace(cacheBusterRegex, ""); - return rewriteSpecials(normalizedPath); } diff --git a/lib/proxyConfiguration.js b/lib/proxyConfiguration.js index dc17320f..caaf0bae 100644 --- a/lib/proxyConfiguration.js +++ b/lib/proxyConfiguration.js @@ -1,5 +1,4 @@ -const log = require("@ui5/logger").getLogger("proxyConfiguration"); -const {resourceFactory} = require("@ui5/fs"); +const log = require("@ui5/logger").getLogger("server:proxyConfiguration"); const proxyConfigurations = {}; @@ -10,6 +9,9 @@ function addConfiguration(name, proxyConfig) { if (proxyConfigurations[name]) { throw new Error(`proxyConfiguration: A configuration with name ${name} is already known`); } + if (proxyConfig.rewriteRootPaths) { + throw new Error(`Proxy Configuration ${name} must not define "rewriteRootPaths"`); + } if (!proxyConfig.destination) { proxyConfig.destination = {}; @@ -26,23 +28,65 @@ async function getConfigurationForProject(project) { throw new Error(`Found multiple proxy configurations. ` + `This is not yet supported.`); // TODO } + + log.verbose(`Applying proxy configuration ${configNames[0]} to project ${project.metadata.name}...`); const config = JSON.parse(JSON.stringify(proxyConfigurations[configNames[0]])); + config.rewriteRootPaths = {}; + + if (config.destination.ui5Root && !config.appOnly) { + log.verbose(`Using configured "destination.ui5Root": ${config.destination.ui5Root}`); + config.rewriteRootPaths[config.destination.ui5Root] = { + rewriteTo: "" + }; + } + + mapProjectDependencies(project, (proj) => { + if (proj.specVersion !== "1.1a") { + log.warn(`Project ${project.metadata.name} defines specification version ${proj.specVersion}. ` + + `Some proxy configuration features require projects to define specification version 1.1a`); + } + log.verbose(`Using ABAP URI ${proj.metadata.abapUri} from metadata of project ${proj.metadata.name}`); + let prefix = ""; + if (proj.type !== "application") { + if (project.resources.pathMappings["/resources"]) { + // If the project defines a /resources path mapping, + // we expect this to match the ABAP URI deployment path + prefix += "/resources/"; + + // If this is not an application and there is no /resources path mapping, somebody does something wild + // and hopefully knows what he/she does + } + prefix += proj.metadata.namespace; + } + config.rewriteRootPaths[proj.metadata.abapUri] = { + rewriteTo: prefix + }; + }); - const {source} = resourceFactory.createCollectionsForTree(project); - const manifestResource = await source.byPath("/manifest.json"); - if (manifestResource) { - const manifest = JSON.parse(await manifestResource.getBuffer()); - if (manifest["sap.platform.abap"] && manifest["sap.platform.abap"].uri) { - log.verbose(`Using sap.platform.abap URI configuration as application root ` + - `path: ${manifest["sap.platform.abap"].uri}`); - config.destination.appRoot = manifest["sap.platform.abap"].uri; + if (log.isLevelEnabled("verbose")) { + log.verbose(`Configured ${config.rewriteRootPaths.length} root paths to rewrite for ` + + `project ${project.metadata.name};`); + for (const abapUri in config.rewriteRootPaths) { + if (config.rewriteRootPaths.hasOwnProperty(abapUri)) { + if (config.rewriteRootPaths[abapUri].rewriteTo) { + log.verbose(`Rewriting ${abapUri} to ${config.rewriteRootPaths[abapUri].rewriteTo}`); + } else { + log.verbose(`Rewriting ${abapUri}`); + } + } } } - log.verbose(`UI5 root path configured as: ${config.destination.ui5Root}`); return config; } +function mapProjectDependencies(tree, handler) { + handler(tree); + tree.dependencies.map((dep) => { + mapProjectDependencies(dep, handler); + }); +} + module.exports = { addConfiguration, getConfigurationForProject