From f32aa41f8e886713819e55538128916773a9eae3 Mon Sep 17 00:00:00 2001 From: Olaf Lessenich Date: Mon, 12 Feb 2024 23:11:03 +0100 Subject: [PATCH] electron: allow accessing the metrics endpoint for performance analysis By default, when running Theia in Electron, all endpoints are protected by the ElectronTokenValidator. This patch allows accessing the '/metrics' endpoint without a token, which enables us to collect metrics for performance analysis. For this, ElectronTokenValidator is extended to allow access to the metrics endpoint. All other endpoints are still protected. Contributed on behalf of STMicroelectronics Signed-off-by: Olaf Lessenich --- packages/metrics/package.json | 1 + .../electron-metrics-backend-module.ts | 42 +++++++++++++++++++ .../electron-node/electron-token-validator.ts | 38 +++++++++++++++++ ...etrics-backend-application-contribution.ts | 3 +- 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 packages/metrics/src/electron-node/electron-metrics-backend-module.ts create mode 100644 packages/metrics/src/electron-node/electron-token-validator.ts diff --git a/packages/metrics/package.json b/packages/metrics/package.json index 8a2e8927f1a24..7086fcc8a090d 100644 --- a/packages/metrics/package.json +++ b/packages/metrics/package.json @@ -12,6 +12,7 @@ "theiaExtensions": [ { "frontend": "lib/browser/metrics-frontend-module", + "backendElectron": "lib/electron-node/electron-metrics-backend-module", "backend": "lib/node/metrics-backend-module" } ], diff --git a/packages/metrics/src/electron-node/electron-metrics-backend-module.ts b/packages/metrics/src/electron-node/electron-metrics-backend-module.ts new file mode 100644 index 0000000000000..30fc472129495 --- /dev/null +++ b/packages/metrics/src/electron-node/electron-metrics-backend-module.ts @@ -0,0 +1,42 @@ +// ***************************************************************************** +// Copyright (C) 2023 STMicroelectronics and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** + +import { ContainerModule } from '@theia/core/shared/inversify'; +import { MetricsElectronTokenValidator } from './electron-token-validator'; +import { ElectronTokenValidator } from '@theia/core/lib/electron-node/token/electron-token-validator'; +import { BackendApplicationContribution } from '@theia/core/lib/node'; +import { ExtensionMetricsContribution, MetricsBackendApplicationContribution, MetricsContribution, NodeMetricsContribution } from '../node'; +import { ConnectionHandler, RpcConnectionHandler, bindContributionProvider } from '@theia/core'; +import { measurementNotificationServicePath } from '../common'; +import { MeasurementMetricsBackendContribution } from '../node/measurement-metrics-contribution'; + + +export default new ContainerModule((bind, unbind, isBound, rebind) => { + bind(MetricsElectronTokenValidator).toSelf().inSingletonScope(); + rebind(ElectronTokenValidator).to(MetricsElectronTokenValidator); + + bindContributionProvider(bind, MetricsContribution); + bind(MetricsContribution).to(NodeMetricsContribution).inSingletonScope(); + bind(MetricsContribution).to(ExtensionMetricsContribution).inSingletonScope(); + + bind(MeasurementMetricsBackendContribution).toSelf().inSingletonScope(); + bind(MetricsContribution).toService(MeasurementMetricsBackendContribution); + bind(ConnectionHandler).toDynamicValue(ctx => + new RpcConnectionHandler(measurementNotificationServicePath, + () => ctx.container.get(MeasurementMetricsBackendContribution))); + + bind(BackendApplicationContribution).to(MetricsBackendApplicationContribution).inSingletonScope(); +}); diff --git a/packages/metrics/src/electron-node/electron-token-validator.ts b/packages/metrics/src/electron-node/electron-token-validator.ts new file mode 100644 index 0000000000000..5e062c8f03d4e --- /dev/null +++ b/packages/metrics/src/electron-node/electron-token-validator.ts @@ -0,0 +1,38 @@ +// ***************************************************************************** +// Copyright (C) 2023 STMicroelectronics and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** + +import * as http from 'http'; +import { injectable, postConstruct } from '@theia/core/shared/inversify'; +import { ElectronTokenValidator } from '@theia/core/lib/electron-node/token/electron-token-validator'; +import { IncomingMessage } from 'http'; +import { MetricsBackendApplicationContribution } from '../node/metrics-backend-application-contribution'; +import { MaybePromise } from '@theia/core'; + +@injectable() +export class MetricsElectronTokenValidator extends ElectronTokenValidator { + @postConstruct() + protected override init(): void { + super.init(); + } + + override allowWsUpgrade(request: http.IncomingMessage): MaybePromise { + return this.allowRequest(request); + } + + override allowRequest(request: IncomingMessage): boolean { + return request.url === MetricsBackendApplicationContribution.ENDPOINT || super.allowRequest(request); + } +} diff --git a/packages/metrics/src/node/metrics-backend-application-contribution.ts b/packages/metrics/src/node/metrics-backend-application-contribution.ts index b672e2e982bde..cba07eaf38b66 100644 --- a/packages/metrics/src/node/metrics-backend-application-contribution.ts +++ b/packages/metrics/src/node/metrics-backend-application-contribution.ts @@ -24,6 +24,7 @@ import { MetricsContribution } from './metrics-contribution'; @injectable() export class MetricsBackendApplicationContribution implements BackendApplicationContribution { + static ENDPOINT = '/metrics'; constructor( @inject(ContributionProvider) @named(MetricsContribution) protected readonly metricsProviders: ContributionProvider @@ -31,7 +32,7 @@ export class MetricsBackendApplicationContribution implements BackendApplication } configure(app: express.Application): void { - app.get('/metrics', (req, res) => { + app.get(MetricsBackendApplicationContribution.ENDPOINT, (req, res) => { const lastMetrics = this.fetchMetricsFromProviders(); res.send(lastMetrics); });