Skip to content

Commit e46db01

Browse files
committed
fix(@angular-devkit/build-angular): construct SSR request URL using server resolvedUrls
With vite `header.host` is undefined when SSL is enabled. This resulted in an invalid URL to be constructed. Closes angular#26652
1 parent 5370b03 commit e46db01

File tree

3 files changed

+92
-3
lines changed

3 files changed

+92
-3
lines changed

packages/angular_devkit/build_angular/src/builders/dev-server/vite-server.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -680,11 +680,9 @@ export async function setupServer(
680680
}
681681

682682
transformIndexHtmlAndAddHeaders(url, rawHtml, res, next, async (html) => {
683-
const protocol = serverOptions.ssl ? 'https' : 'http';
684-
const route = `${protocol}://${req.headers.host}${req.originalUrl}`;
685683
const { content } = await renderPage({
686684
document: html,
687-
route,
685+
route: new URL(req.originalUrl ?? '/', server.resolvedUrls?.local[0]).toString(),
688686
serverContext: 'ssr',
689687
loadBundle: (uri: string) =>
690688
// eslint-disable-next-line @typescript-eslint/no-explicit-any

tests/legacy-cli/e2e.bzl

+4
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,17 @@ ESBUILD_TESTS = [
3333
"tests/build/**",
3434
"tests/commands/add/**",
3535
"tests/commands/e2e/**",
36+
"tests/commands/serve/ssr-http-requests-assets.js",
3637
"tests/i18n/**",
3738
"tests/vite/**",
3839
"tests/test/**",
3940
]
4041

4142
WEBPACK_IGNORE_TESTS = [
4243
"tests/vite/**",
44+
"tests/commands/serve/error-with-sourcemaps.js",
45+
"tests/commands/serve/ssr-http-requests-assets.js",
46+
"tests/build/prerender/http-requests-assets.js",
4347
]
4448

4549
def _to_glob(patterns):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import assert from 'node:assert';
2+
3+
import { killAllProcesses, ng } from '../../../utils/process';
4+
import { getGlobalVariable } from '../../../utils/env';
5+
import { rimraf, writeMultipleFiles } from '../../../utils/fs';
6+
import { installWorkspacePackages } from '../../../utils/packages';
7+
import { ngServe, useSha } from '../../../utils/project';
8+
9+
export default async function () {
10+
const useWebpackBuilder = !getGlobalVariable('argv')['esbuild'];
11+
if (useWebpackBuilder) {
12+
// Not supported by the webpack based builder.
13+
return;
14+
}
15+
16+
// Forcibly remove in case another test doesn't clean itself up.
17+
await rimraf('node_modules/@angular/ssr');
18+
await ng('add', '@angular/ssr', '--skip-confirmation');
19+
await useSha();
20+
await installWorkspacePackages();
21+
22+
await writeMultipleFiles({
23+
// Add http client and route
24+
'src/app/app.config.ts': `
25+
import { ApplicationConfig } from '@angular/core';
26+
import { provideRouter } from '@angular/router';
27+
28+
import {HomeComponent} from './home/home.component';
29+
import { provideClientHydration } from '@angular/platform-browser';
30+
import { provideHttpClient, withFetch } from '@angular/common/http';
31+
32+
export const appConfig: ApplicationConfig = {
33+
providers: [
34+
provideRouter([{
35+
path: '',
36+
component: HomeComponent,
37+
}]),
38+
provideClientHydration(),
39+
provideHttpClient(withFetch()),
40+
],
41+
};
42+
`,
43+
// Add asset
44+
'src/assets/media.json': JSON.stringify({ dataFromAssets: true }),
45+
// Update component to do an HTTP call to asset.
46+
'src/app/app.component.ts': `
47+
import { Component, inject } from '@angular/core';
48+
import { CommonModule } from '@angular/common';
49+
import { RouterOutlet } from '@angular/router';
50+
import { HttpClient } from '@angular/common/http';
51+
52+
@Component({
53+
selector: 'app-root',
54+
standalone: true,
55+
imports: [CommonModule, RouterOutlet],
56+
template: \`
57+
<p>{{ data | json }}</p>
58+
<router-outlet></router-outlet>
59+
\`,
60+
})
61+
export class AppComponent {
62+
data: any;
63+
constructor() {
64+
const http = inject(HttpClient);
65+
http.get('/assets/media.json').toPromise().then((d) => {
66+
this.data = d;
67+
});
68+
}
69+
}
70+
`,
71+
});
72+
73+
await ng('generate', 'component', 'home');
74+
const match = /<p>{[\S\s]*"dataFromAssets":[\s\S]*true[\S\s]*}<\/p>/;
75+
const port = await ngServe('--no-ssl');
76+
assert.match(await (await fetch(`http://localhost:${port}/`)).text(), match);
77+
78+
await killAllProcesses();
79+
80+
try {
81+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
82+
const sslPort = await ngServe('--ssl');
83+
assert.match(await (await fetch(`https://localhost:${sslPort}/`)).text(), match);
84+
} finally {
85+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1';
86+
}
87+
}

0 commit comments

Comments
 (0)