-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: support HTTP/2 in astro dev
#11284
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
'astro': patch | ||
--- | ||
|
||
Fixes an issue that would break `Astro.request.url` and `Astro.request.headers` in `astro dev` if HTTP/2 was enabled. | ||
|
||
HTTP/2 is now enabled by default in `astro dev` if `https` is configured in the Vite config. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import assert from 'node:assert/strict'; | ||
import { after, before, describe, it } from 'node:test'; | ||
import * as cheerio from 'cheerio'; | ||
import { loadFixture } from './test-utils.js'; | ||
|
||
describe('Astro HTTP/2 support', () => { | ||
let fixture; | ||
let devServer; | ||
|
||
before(async () => { | ||
fixture = await loadFixture({ | ||
root: './fixtures/astro-dev-http2/', | ||
}); | ||
devServer = await fixture.startDevServer(); | ||
}); | ||
|
||
after(async () => { | ||
await devServer.stop(); | ||
}); | ||
|
||
describe('dev', () => { | ||
it('returns custom headers for valid URLs', async () => { | ||
const result = await fixture.fetch('/'); | ||
assert.equal(result.status, 200); | ||
const html = await result.text(); | ||
console.log(result.headers); | ||
const $ = cheerio.load(html); | ||
const urlString = $('main').text(); | ||
assert.equal(Boolean(urlString), true); | ||
const url = new URL(urlString); | ||
// Not asserting host because of all the ways localhost can be represented | ||
assert.equal(url.protocol, 'https:'); | ||
assert.equal(url.port, '4321'); | ||
assert.equal($('p').text(), '2.0'); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
-----BEGIN CERTIFICATE----- | ||
MIIEHDCCAoSgAwIBAgIRAIWPzjvpgZGzQqe1TFcdGmAwDQYJKoZIhvcNAQELBQAw | ||
ZTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMR0wGwYDVQQLDBRhbGV4 | ||
QERFU0tUT1AtMFM5OFUzMDEkMCIGA1UEAwwbbWtjZXJ0IGFsZXhAREVTS1RPUC0w | ||
Uzk4VTMwMB4XDTI0MDIyNjAwNDkyOVoXDTI2MDUyNTIzNDkyOVowSDEnMCUGA1UE | ||
ChMebWtjZXJ0IGRldmVsb3BtZW50IGNlcnRpZmljYXRlMR0wGwYDVQQLDBRhbGV4 | ||
QERFU0tUT1AtMFM5OFUzMDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB | ||
AMRj8/YGXRRWkpIxdaWbL+v2RZoI7iGOyJliC2Iudag5/irpiBAFgZAqpjSb1i1E | ||
OKkXRQlCx21jQWe/jEFGqEPIqjeLPrXHATKU+6prOH2FV2qF7PDd0gi1gkR0cxX7 | ||
dUA9kUeqm1HHkogUuhRjg5uCklyCraN49yz6QU6U7uiTo4ZM9mjfig0EfG2W1DBp | ||
G0bKkEhgkSKw3v1mvGVYN5yAv6unLjDVJGwLKqTTpDpsahG47h+ZPHj7wjSOQiDB | ||
tXR+HNLJdSe59+GQ8D5/M7hRG6rZ+8GzaNjQWRl8BK6Ls0k1qtMgcEFeNDLEWTj1 | ||
16yNmd4/IX4irMmSA+F7PgUCAwEAAaNkMGIwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud | ||
JQQMMAoGCCsGAQUFBwMBMB8GA1UdIwQYMBaAFE+Vk1SZFKjFDIsieTVT/860OBs6 | ||
MBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAYEA | ||
szcc7pdwdYu3uIN8f8LHFABDhxiPDLMqmyEJXym5z8c44Mtl0mfGnKs0uIzl/XtL | ||
F1aLH8yHubZ1LJkIczAypcryekmk+VzTsNdv1aKelhsZ9QJUxg/NsrMXe5DZ9Eeu | ||
KxlJBJKo+oRpDsxRYo1l5FvIljcVvOUTaKR3UtY6FU2xdDMNMtoJDbaJCPAg143H | ||
ZnSa7xEv7fGDTcn9oKFc1fc1BnCy4qCHkxF8pIeXbXEZ/q1fqNNtp87/PigPT7YO | ||
ppcYvEsj4Y+6yuDfIrWAZNcbtiOfFUyPXy1KN+/VxZhcZ/MuAbl4EiESDFbE5j8U | ||
whIHlRXUY6B09PL9NVNGyjNDH3NMQkSKVFA2KVeaFeDIROjPeMkrKY56lWVpEiru | ||
HVLuFVpM27uJEKgSNeAYttfOEvsvr20Otmt29Uu59qfX+w0crQUEElcUJB4DgRH+ | ||
NVoYZLYMm88B5aVUsmwkkrJJrAJ+M6UnzIhdN2alJxXojW38jDWzn+dWbc0a2hIB | ||
-----END CERTIFICATE----- |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
-----BEGIN PRIVATE KEY----- | ||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDEY/P2Bl0UVpKS | ||
MXWlmy/r9kWaCO4hjsiZYgtiLnWoOf4q6YgQBYGQKqY0m9YtRDipF0UJQsdtY0Fn | ||
v4xBRqhDyKo3iz61xwEylPuqazh9hVdqhezw3dIItYJEdHMV+3VAPZFHqptRx5KI | ||
FLoUY4ObgpJcgq2jePcs+kFOlO7ok6OGTPZo34oNBHxtltQwaRtGypBIYJEisN79 | ||
ZrxlWDecgL+rpy4w1SRsCyqk06Q6bGoRuO4fmTx4+8I0jkIgwbV0fhzSyXUnuffh | ||
kPA+fzO4URuq2fvBs2jY0FkZfASui7NJNarTIHBBXjQyxFk49desjZnePyF+IqzJ | ||
kgPhez4FAgMBAAECggEBAL+70d89ATys9LYT4YcIBnY5XmRvGYXbr47IANMfBrFx | ||
xOpCSxtRNNf6O4AbMLPK6gJzfGv5LVhnUeCnSpgkEnzy+PP3VwcDPfETMMyFl4Y8 | ||
W0bdb6EM/1SPWJnaks1ATY2lTiQItVDXJgEDM1Raf4+gn6H/1uRFYhQgUwgUMVcP | ||
rb/6qk+vFJXGuyx1R1DoIoqz+8iBfcsddUplx8ulJv74/Lgn5B/5sZ6I6cnW8lva | ||
FskuY1DL2RUywuV2J2fnFGNuGPPvc5elE0ORYLjlUGDMHQq+a9UxXsfCC4gHoks1 | ||
P4vYZjzOVGRA3o+F8khuZLeCebMsKnoyzmkeRGejlzUCgYEA8d+TtwU3qlFUl3sa | ||
TGJm+tD5sgLaZHDssMhkkTtTVzYIllFSyvT8UI7/9ZwYinq0JOnGN0Cb7TsH4AGQ | ||
jQzHfiudibvODK4HL3rVkiOwj+kdjH+oTMlCTGsCj9uZhEajzKpXgpSlYkpqhDR2 | ||
zCdMdFXCE+SpJCJaTI+jcbup6P8CgYEAz9xUBQIk8CdySkgIB0gmpIgtvS1EwYod | ||
YvYu+coQ1lEtALetDdbx5VfasWd1A18sIFlkfZZMKr5+1QXVuKOFhx2n49XIev/6 | ||
t+Hgx8aToIpB0tz/3CTea5HGK8FvX6t5QKDL6XqDrRGO1FVdMSWl9WLfmpTynJdj | ||
sNHr7JFwNPsCgYAz5OE/ekoYK7z3hzz8OHyZwa5hCAWtWSEfSM9y7YSTCI/NGIOn | ||
8eoUqqm2G5iUVYFDDjkt75nEy06EPDG0YZKHunnhbD7oL4pxIGykHy4poj1pwJXu | ||
a5vi4264SMhmPfW02rNN2/Cj5w11cgAvCxt3NlMei4fSreAr3wGVTEtHJwKBgEBw | ||
QIfQ81yUDgVjMUH4pyoooW1dRExvoc6VHVkIwJGAVuA7EOYSdakwxDZtKURjU82v | ||
iMy6NGCn76/ggDIeV33cvriOBPnEs5gf6Uxljkydr+xL4PIBaAaXCYV1ES7qfMuB | ||
TdXSylFz+QBwelSLJFjfTwygElpjQF+HpIkRSWTTAoGBAJIqeQ4edg4weut00+32 | ||
A8rQEpiz5SByPYNUPCI5BReKd+/Dw2QdXnfJNVg7/NFfuUdvPVkmptsisYdfWhlp | ||
y+KFAwdbgDUU+ruPuv5fHU4sA85Uuxazr/YXZIB6wmsQKt8cNezqNhjY6UovTOdZ | ||
7qnkPUO8VGcnrRZiav8WIevg | ||
-----END PRIVATE KEY----- |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { defineConfig } from "astro/config"; | ||
import { readFileSync } from "fs"; | ||
// https://astro.build/config | ||
export default defineConfig({ | ||
output: "hybrid", | ||
vite: { | ||
server: { | ||
https: { | ||
key: readFileSync(new URL(".cert/key.pem", import.meta.url)), | ||
cert: readFileSync(new URL(".cert/cert.pem", import.meta.url)), | ||
}, | ||
}, | ||
plugins: [ | ||
{ | ||
name: 'http-version-plugin', | ||
// This plugin allows tests to track the version of HTTP used in the request | ||
configureServer: (server) => { | ||
server.middlewares.use((req, res, next) => { | ||
req.headers['x-http-version'] = req.httpVersion; | ||
next(); | ||
}); | ||
} | ||
}, | ||
], | ||
}, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"name": "@test/astro-dev-http2", | ||
"version": "0.0.1", | ||
"private": true, | ||
"dependencies": { | ||
"astro": "workspace:*" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
--- | ||
const url = Astro.request.url | ||
const httpVersion = Astro.request.headers.get('x-http-version') | ||
export const prerender = false | ||
--- | ||
|
||
<html> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<meta name="viewport" content="width=device-width" /> | ||
<link rel="icon" type="image/x-icon" href="/favicon.ico" /> | ||
</head> | ||
<body> | ||
<main>{url}</main> | ||
<p>{httpVersion}</p> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ import { fileURLToPath } from 'node:url'; | |
import { execa } from 'execa'; | ||
import fastGlob from 'fast-glob'; | ||
import stripAnsi from 'strip-ansi'; | ||
import { Agent } from 'undici'; | ||
import { check } from '../dist/cli/check/index.js'; | ||
import build from '../dist/core/build/index.js'; | ||
import { RESOLVED_SPLIT_MODULE_ID } from '../dist/core/build/plugins/plugin-ssr.js'; | ||
|
@@ -122,8 +123,13 @@ export async function loadFixture(inlineConfig) { | |
// Load the config. | ||
const { astroConfig: config } = await resolveConfig(inlineConfig, 'dev'); | ||
|
||
const protocol = config.vite?.server?.https ? 'https' : 'http'; | ||
|
||
const resolveUrl = (url) => | ||
`http://${config.server.host || 'localhost'}:${config.server.port}${url.replace(/^\/?/, '/')}`; | ||
`${protocol}://${config.server.host || 'localhost'}:${config.server.port}${url.replace( | ||
/^\/?/, | ||
'/' | ||
)}`; | ||
|
||
// A map of files that have been edited. | ||
let fileEdits = new Map(); | ||
|
@@ -171,6 +177,17 @@ export async function loadFixture(inlineConfig) { | |
config, | ||
resolveUrl, | ||
fetch: async (url, init) => { | ||
if (config.vite?.server?.https) { | ||
init = { | ||
dispatcher: new Agent({ | ||
connect: { | ||
rejectUnauthorized: false, | ||
}, | ||
allowH2: true, | ||
}), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's this for? I have no knowledge of this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This tells undici fetch to use a custom dispatcher. This lets you customise some of the HTTP options for the request. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll add comments for both of these |
||
...init, | ||
}; | ||
} | ||
const resolvedUrl = resolveUrl(url); | ||
try { | ||
return await fetch(resolvedUrl, init); | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are H2 pseudo-headers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They're fake headers that are added to all HTTP/2 requests. They're only allowed to be generated internally though: it's an error to add one to Headers yourself. https://httpwg.org/specs/rfc7540.html#HttpRequest