diff --git a/helm-chart/renku-ui/templates/ui-server-deployment.yaml b/helm-chart/renku-ui/templates/ui-server-deployment.yaml index 2c40658573..43c70fa954 100644 --- a/helm-chart/renku-ui/templates/ui-server-deployment.yaml +++ b/helm-chart/renku-ui/templates/ui-server-deployment.yaml @@ -43,8 +43,6 @@ spec: value: {{ .Values.server.url | default (printf "%s://%s" (include "ui.protocol" .) .Values.global.renku.domain) | quote }} - name: UI_SERVER_VERSION value: {{ .Chart.Version | quote }} - - name: SERVER_PORT - value: {{ .Values.server.port | default (printf "8080") | quote }} - name: GATEWAY_URL value: {{ .Values.gateway.url | default (printf "%s://%s/api" (include "ui.protocol" .) .Values.global.renku.domain) | quote }} - name: GATEWAY_LOGIN_PATH diff --git a/helm-chart/renku-ui/values.yaml b/helm-chart/renku-ui/values.yaml index bc213a9ffe..af86fac9d3 100644 --- a/helm-chart/renku-ui/values.yaml +++ b/helm-chart/renku-ui/values.yaml @@ -175,7 +175,6 @@ client: server: ## The URL for the server service; the URL used by the client is the server.url + /ui-server endpoint. url: - port: 8080 replicaCount: 1 image: diff --git a/server/src/config.ts b/server/src/config.ts index 7af70b75de..39690ec148 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -16,11 +16,11 @@ * limitations under the License. */ -import { convertType } from "./utils"; +import { convertType, urlJoin } from "./utils"; const SERVER = { url: process.env.SERVER_URL, - port: convertType(process.env.SERVER_PORT) || 8080, + port: 8080, prefix: "/ui-server", logLevel: process.env.SERVER_LOG_LEVEL || "info", serverUiVersion: process.env.UI_SERVER_VERSION || "unknown", @@ -28,14 +28,18 @@ const SERVER = { wsSuffix: "/ws", }; +const gatewayUrl = process.env.GATEWAY_URL || urlJoin(SERVER.url ?? "", "/api"); + const DEPLOYMENT = { - gatewayUrl: process.env.GATEWAY_URL || SERVER.url + "/api", - gatewayLoginUrl: - (process.env.GATEWAY_URL || SERVER.url + "/api") + - (process.env.GATEWAY_LOGIN_PATH || "/auth/login"), - gatewayLogoutUrl: - (process.env.GATEWAY_URL || SERVER.url + "/api") + - (process.env.GATEWAY_LOGOUT_PATH || "/auth/logout"), + gatewayUrl, + gatewayLoginUrl: urlJoin( + gatewayUrl, + process.env.GATEWAY_LOGIN_PATH || "/auth/login" + ), + gatewayLogoutUrl: urlJoin( + gatewayUrl, + process.env.GATEWAY_LOGOUT_PATH || "/auth/logout" + ), }; const SENTRY = { diff --git a/server/src/utils/index.ts b/server/src/utils/index.ts index 73ff78ceab..e8ed60efb9 100644 --- a/server/src/utils/index.ts +++ b/server/src/utils/index.ts @@ -16,6 +16,8 @@ * limitations under the License. */ +import urlJoin from "./url-join"; + /** * Convert string to booloan or numbers. Useful to handle values coming from environmental variables. @@ -134,4 +136,4 @@ function simpleHash(str: string, seed = 0): number { return 4294967296 * (2097151 & h2) + (h1 >>> 0); } -export { clamp, convertType, getCookieValueByName, getRelease, simpleHash, sleep }; +export { clamp, convertType, getCookieValueByName, getRelease, simpleHash, sleep, urlJoin }; diff --git a/server/src/utils/url-join.ts b/server/src/utils/url-join.ts new file mode 100644 index 0000000000..71b5e561e2 --- /dev/null +++ b/server/src/utils/url-join.ts @@ -0,0 +1,70 @@ +/* eslint-disable brace-style */ +/* eslint-disable no-useless-escape */ +/* eslint-disable curly */ + +/** url-join library from https://github.com/jfromaniello/url-join/blob/main/lib/url-join.js */ +function normalize(strArray: string[]) { + const resultArray = []; + if (strArray.length === 0) { + return ""; + } + + if (typeof strArray[0] !== "string") { + throw new TypeError("Url must be a string. Received " + strArray[0]); + } + + // If the first part is a plain protocol, we combine it with the next part. + if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) { + strArray[0] = strArray.shift() + strArray[0]; + } + + // There must be two or three slashes in the file protocol, two slashes in anything else. + if (strArray[0].match(/^file:\/\/\//)) { + strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1:///"); + } else { + strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, "$1://"); + } + + for (let i = 0; i < strArray.length; i++) { + let component = strArray[i]; + + if (typeof component !== "string") { + throw new TypeError("Url must be a string. Received " + component); + } + + if (component === "") { + continue; + } + + if (i > 0) { + // Removing the starting slashes for each component but the first. + component = component.replace(/^[\/]+/, ""); + } + if (i < strArray.length - 1) { + // Removing the ending slashes for each component but the last. + component = component.replace(/[\/]+$/, ""); + } else { + // For the last component we will combine multiple slashes to a single one. + component = component.replace(/[\/]+$/, "/"); + } + + resultArray.push(component); + } + + let str = resultArray.join("/"); + // Each input component is now separated by a single slash except the possible first plain protocol part. + + // remove trailing slash before parameters or hash + str = str.replace(/\/(\?|&|#[^!])/g, "$1"); + + // replace ? in parameters with & + const parts = str.split("?"); + str = parts.shift() + (parts.length > 0 ? "?" : "") + parts.join("&"); + + return str; +} + +export default function urlJoin(...args: string[]): string { + const parts = Array.from(Array.isArray(args[0]) ? args[0] : args); + return normalize(parts); +}