/
githubmirror
/
angular
Обзор
Документация
Войти
/
githubmirror
/
angular
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/platform-server/src/location.ts
125 строк
3 KB
Alan Agius
fix(platform-server): harden platform location origin validation during SSR (#69184)
05 июн 2026, 20:20
05 июн 2026, 20:20
cf9d7fa
Код
Авторство
О чём код?
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ import { DOCUMENT, LocationChangeEvent, LocationChangeListener, PlatformLocation, ɵgetDOM as getDOM, } from '@angular/common'; import {inject, Injectable, ɵWritable as Writable} from '@angular/core'; import {Subject} from 'rxjs'; import {INITIAL_CONFIG} from './tokens'; import {resolveUrl} from './url'; /** * Server-side implementation of URL state. Implements `pathname`, `search`, and `hash` * but not the state stack. */ @Injectable() export class ServerPlatformLocation implements PlatformLocation { public readonly href: string = '/'; public readonly hostname: string = '/'; public readonly protocol: string = '/'; public readonly port: string = '/'; public readonly pathname: string = '/'; public readonly search: string = ''; public readonly hash: string = ''; private _hashUpdate = new Subject<LocationChangeEvent>(); private readonly _doc = inject(DOCUMENT); private readonly origin = this._doc.location.origin; constructor() { const config = inject(INITIAL_CONFIG, {optional: true}); if (!config) { return; } if (config.url) { const {protocol, hostname, port, pathname, search, hash, href, origin} = resolveUrl( config.url, this.origin, ); this.protocol = protocol; this.hostname = hostname; this.port = port; this.pathname = pathname; this.search = search; this.hash = hash; this.href = href; this.origin = origin; } } getBaseHrefFromDOM(): string { return getDOM().getBaseHref(this._doc)!; } onPopState(fn: LocationChangeListener): VoidFunction { // No-op: a state stack is not implemented, so // no events will ever come. return () => {}; } onHashChange(fn: LocationChangeListener): VoidFunction { const subscription = this._hashUpdate.subscribe(fn); return () => subscription.unsubscribe(); } get url(): string { return `${this.pathname}${this.search}${this.hash}`; } private setHash(value: string, oldUrl: string) { if (this.hash === value) { // Don't fire events if the hash has not changed. return; } (this as Writable<this>).hash = value; const newUrl = this.url; queueMicrotask(() => this._hashUpdate.next({ type: 'hashchange', state: null, oldUrl, newUrl, } as LocationChangeEvent), ); } replaceState(state: any, title: string, newUrl: string): void { const oldUrl = this.url; const {pathname, search, hash, href, protocol} = resolveUrl(newUrl, this.origin, { allowOriginChange: false, }); const writableThis = this as Writable<this>; writableThis.pathname = pathname; writableThis.search = search; writableThis.href = href; writableThis.protocol = protocol; this.setHash(hash, oldUrl); } pushState(state: any, title: string, newUrl: string): void { this.replaceState(state, title, newUrl); } forward(): void { throw new Error('Not implemented'); } back(): void { throw new Error('Not implemented'); } // History API isn't available on server, therefore return undefined getState(): unknown { return undefined; } }