refactor(platform-server): replace Node.js URL API usage (#52231)

This commit replace the usage of URL node API to WHATWG URL API.

See: https://nodejs.org/api/url.html#the-whatwg-url-api

PR Close #52231
This commit is contained in:
Alan Agius 2023-10-19 07:44:55 +00:00 committed by Dylan Hunn
parent c07805612f
commit 7978b408df
2 changed files with 87 additions and 9 deletions

View file

@ -9,19 +9,45 @@
import {DOCUMENT, LocationChangeEvent, LocationChangeListener, PlatformLocation, ɵgetDOM as getDOM} from '@angular/common';
import {Inject, Injectable, Optional, ɵWritable as Writable} from '@angular/core';
import {Subject} from 'rxjs';
import * as url from 'url';
import {INITIAL_CONFIG, PlatformConfig} from './tokens';
function parseUrl(urlStr: string) {
const parsedUrl = url.parse(urlStr);
const RESOLVE_PROTOCOL = 'resolve:';
function parseUrl(urlStr: string): {
hostname: string,
protocol: string,
port: string,
pathname: string,
search: string,
hash: string,
} {
let {hostname, protocol, port, pathname, search, hash} = new URL(urlStr, RESOLVE_PROTOCOL + '//');
/**
* TODO(alanagius): Remove the below in version 18.
* The following are done to maintain the same behaviour as `url.parse`.
* The main differences are;
* - `pathname` is always suffixed with a `/`.
* - `port` is empty when `http:` protocol and port in url is `80`
* - `port` is empty when `https:` protocol and port in url is `443`
*/
if (protocol !== RESOLVE_PROTOCOL && port === '' && /\:(80|443)/.test(urlStr)) {
port = protocol === 'http:' ? '80' : '443';
}
if (protocol === RESOLVE_PROTOCOL && urlStr.charAt(0) !== '/') {
pathname = pathname.slice(1); // Remove leading slash.
}
// END TODO
return {
hostname: parsedUrl.hostname || '',
protocol: parsedUrl.protocol || '',
port: parsedUrl.port || '',
pathname: parsedUrl.pathname || '',
search: parsedUrl.search || '',
hash: parsedUrl.hash || '',
hostname,
protocol: protocol === RESOLVE_PROTOCOL ? '' : protocol,
port,
pathname,
search,
hash,
};
}

View file

@ -707,6 +707,58 @@ describe('platform-server integration', () => {
location.pushState(null, 'Test', '/foo#bar');
});
});
describe('Legacy (Remove once url normalization is removed)', () => {
it('parses and returns pathname without a slash', async () => {
const platform = platformServer([{
provide: INITIAL_CONFIG,
useValue: {document: '<app></app>', url: 'deep/path?query#hash'}
}]);
const appRef = await platform.bootstrapModule(ExampleModule);
const location = appRef.injector.get(PlatformLocation);
expect(location.hostname).toBe('');
expect(location.protocol).toBe('');
expect(location.port).toBe('');
expect(location.pathname).toBe('deep/path');
expect(location.search).toBe('?query');
expect(location.hash).toBe('#hash');
});
it('port is set to 443 when using https protocol', async () => {
const platform = platformServer([{
provide: INITIAL_CONFIG,
useValue: {document: '<app></app>', url: 'https://test.com:443/deep/path?query#hash'}
}]);
const appRef = await platform.bootstrapModule(ExampleModule);
const location = appRef.injector.get(PlatformLocation);
expect(location.hostname).toBe('test.com');
expect(location.protocol).toBe('https:');
expect(location.port).toBe('443');
expect(location.pathname).toBe('/deep/path');
expect(location.search).toBe('?query');
expect(location.hash).toBe('#hash');
});
it('port is set to 80 when using http protocol', async () => {
const platform = platformServer([{
provide: INITIAL_CONFIG,
useValue: {document: '<app></app>', url: 'http://test.com:80/deep/path?query#hash'}
}]);
const appRef = await platform.bootstrapModule(ExampleModule);
const location = appRef.injector.get(PlatformLocation);
expect(location.hostname).toBe('test.com');
expect(location.protocol).toBe('http:');
expect(location.port).toBe('80');
expect(location.pathname).toBe('/deep/path');
expect(location.search).toBe('?query');
expect(location.hash).toBe('#hash');
});
});
});
describe('render', () => {