package-rebuilds/pkgs/node-undici/node-undici-5.28.4+dfsg1+~cs23.12.11/test/http2.js
Fabian Grünbichler afee63929c add node-undici for libgit2 1.8.1
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
2024-09-10 11:23:24 +02:00

1192 lines
28 KiB
JavaScript

'use strict'
const { createSecureServer } = require('http2')
const { createReadStream, readFileSync } = require('fs')
const { once } = require('events')
const { Blob } = require('buffer')
const { Writable, pipeline, PassThrough, Readable } = require('stream')
const { test, plan } = require('tap')
const { gte } = require('semver')
const pem = require('https-pem')
const { Client, Agent } = require('..')
const isGreaterThanv20 = gte(process.version.slice(1), '20.0.0')
// NOTE: node versions <16.14.1 have a bug which changes the order of pseudo-headers
// https://github.com/nodejs/node/pull/41735
const hasPseudoHeadersOrderFix = gte(process.version.slice(1), '16.14.1')
plan(23)
test('Should support H2 connection', async t => {
const body = []
const server = createSecureServer(pem)
server.on('stream', (stream, headers, _flags, rawHeaders) => {
t.equal(headers['x-my-header'], 'foo')
t.equal(headers[':method'], 'GET')
stream.respond({
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': 'hello',
':status': 200
})
stream.end('hello h2!')
})
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.plan(6)
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
const response = await client.request({
path: '/',
method: 'GET',
headers: {
'x-my-header': 'foo'
}
})
response.body.on('data', chunk => {
body.push(chunk)
})
await once(response.body, 'end')
t.equal(response.statusCode, 200)
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
t.equal(response.headers['x-custom-h2'], 'hello')
t.equal(Buffer.concat(body).toString('utf8'), 'hello h2!')
})
test('Should support H2 connection(multiple requests)', async t => {
const server = createSecureServer(pem)
server.on('stream', async (stream, headers, _flags, rawHeaders) => {
t.equal(headers['x-my-header'], 'foo')
t.equal(headers[':method'], 'POST')
const reqData = []
stream.on('data', chunk => reqData.push(chunk.toString()))
await once(stream, 'end')
const reqBody = reqData.join('')
t.equal(reqBody.length > 0, true)
stream.respond({
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': 'hello',
':status': 200
})
stream.end(`hello h2! ${reqBody}`)
})
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.plan(21)
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
for (let i = 0; i < 3; i++) {
const sendBody = `seq ${i}`
const body = []
const response = await client.request({
path: '/',
method: 'POST',
headers: {
'content-type': 'text/plain; charset=utf-8',
'x-my-header': 'foo'
},
body: Readable.from(sendBody)
})
response.body.on('data', chunk => {
body.push(chunk)
})
await once(response.body, 'end')
t.equal(response.statusCode, 200)
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
t.equal(response.headers['x-custom-h2'], 'hello')
t.equal(Buffer.concat(body).toString('utf8'), `hello h2! ${sendBody}`)
}
})
test('Should support H2 connection (headers as array)', async t => {
const body = []
const server = createSecureServer(pem)
server.on('stream', (stream, headers) => {
t.equal(headers['x-my-header'], 'foo')
t.equal(headers['x-my-drink'], 'coffee,tea')
t.equal(headers[':method'], 'GET')
stream.respond({
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': 'hello',
':status': 200
})
stream.end('hello h2!')
})
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.plan(7)
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
const response = await client.request({
path: '/',
method: 'GET',
headers: ['x-my-header', 'foo', 'x-my-drink', ['coffee', 'tea']]
})
response.body.on('data', chunk => {
body.push(chunk)
})
await once(response.body, 'end')
t.equal(response.statusCode, 200)
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
t.equal(response.headers['x-custom-h2'], 'hello')
t.equal(Buffer.concat(body).toString('utf8'), 'hello h2!')
})
test('Should support H2 connection(POST Buffer)', async t => {
const server = createSecureServer({ ...pem, allowHTTP1: false })
server.on('stream', async (stream, headers, _flags, rawHeaders) => {
t.equal(headers[':method'], 'POST')
const reqData = []
stream.on('data', chunk => reqData.push(chunk.toString()))
await once(stream, 'end')
t.equal(reqData.join(''), 'hello!')
stream.respond({
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': 'hello',
':status': 200
})
stream.end('hello h2!')
})
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.plan(6)
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
const sendBody = 'hello!'
const body = []
const response = await client.request({
path: '/',
method: 'POST',
body: sendBody
})
response.body.on('data', chunk => {
body.push(chunk)
})
await once(response.body, 'end')
t.equal(response.statusCode, 200)
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
t.equal(response.headers['x-custom-h2'], 'hello')
t.equal(Buffer.concat(body).toString('utf8'), 'hello h2!')
})
test('Should support H2 GOAWAY (server-side)', async t => {
const body = []
const server = createSecureServer(pem)
server.on('stream', (stream, headers) => {
t.equal(headers['x-my-header'], 'foo')
t.equal(headers[':method'], 'GET')
stream.respond({
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': 'hello',
':status': 200
})
stream.end('hello h2!')
})
server.on('session', session => {
setTimeout(() => {
session.goaway(204)
}, 1000)
})
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.plan(9)
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
const response = await client.request({
path: '/',
method: 'GET',
headers: {
'x-my-header': 'foo'
}
})
response.body.on('data', chunk => {
body.push(chunk)
})
await once(response.body, 'end')
t.equal(response.statusCode, 200)
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
t.equal(response.headers['x-custom-h2'], 'hello')
t.equal(Buffer.concat(body).toString('utf8'), 'hello h2!')
const [url, disconnectClient, err] = await once(client, 'disconnect')
t.type(url, URL)
t.same(disconnectClient, [client])
t.equal(err.message, 'HTTP/2: "GOAWAY" frame received with code 204')
})
test('Should throw if bad allowH2 has been pased', async t => {
try {
// eslint-disable-next-line
new Client('https://localhost:1000', {
allowH2: 'true'
})
t.fail()
} catch (error) {
t.equal(error.message, 'allowH2 must be a valid boolean value')
}
})
test('Should throw if bad maxConcurrentStreams has been pased', async t => {
try {
// eslint-disable-next-line
new Client('https://localhost:1000', {
allowH2: true,
maxConcurrentStreams: {}
})
t.fail()
} catch (error) {
t.equal(
error.message,
'maxConcurrentStreams must be a possitive integer, greater than 0'
)
}
try {
// eslint-disable-next-line
new Client('https://localhost:1000', {
allowH2: true,
maxConcurrentStreams: -1
})
t.fail()
} catch (error) {
t.equal(
error.message,
'maxConcurrentStreams must be a possitive integer, greater than 0'
)
}
})
test(
'Request should fail if allowH2 is false and server advertises h1 only',
{ skip: isGreaterThanv20 },
async t => {
const server = createSecureServer(
{
...pem,
allowHTTP1: false,
ALPNProtocols: ['http/1.1']
},
(req, res) => {
t.fail('Should not create a valid h2 stream')
}
)
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
allowH2: false,
connect: {
rejectUnauthorized: false
}
})
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
const response = await client.request({
path: '/',
method: 'GET',
headers: {
'x-my-header': 'foo'
}
})
t.equal(response.statusCode, 403)
}
)
test(
'[v20] Request should fail if allowH2 is false and server advertises h1 only',
{ skip: !isGreaterThanv20 },
async t => {
const server = createSecureServer(
{
...pem,
allowHTTP1: false,
ALPNProtocols: ['http/1.1']
},
(req, res) => {
t.fail('Should not create a valid h2 stream')
}
)
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
allowH2: false,
connect: {
rejectUnauthorized: false
}
})
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
t.plan(2)
try {
await client.request({
path: '/',
method: 'GET',
headers: {
'x-my-header': 'foo'
}
})
} catch (error) {
t.equal(
error.message,
'Client network socket disconnected before secure TLS connection was established'
)
t.equal(error.code, 'ECONNRESET')
}
}
)
test('Should handle h2 continue', async t => {
const requestBody = []
const server = createSecureServer(pem, () => {})
const responseBody = []
server.on('checkContinue', (request, response) => {
t.equal(request.headers.expect, '100-continue')
t.equal(request.headers['x-my-header'], 'foo')
t.equal(request.headers[':method'], 'POST')
response.writeContinue()
request.on('data', chunk => requestBody.push(chunk))
response.writeHead(200, {
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': 'foo'
})
response.end('hello h2!')
})
t.plan(7)
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
expectContinue: true,
allowH2: true
})
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
const response = await client.request({
path: '/',
method: 'POST',
headers: {
'x-my-header': 'foo'
},
expectContinue: true
})
response.body.on('data', chunk => {
responseBody.push(chunk)
})
await once(response.body, 'end')
t.equal(response.statusCode, 200)
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
t.equal(response.headers['x-custom-h2'], 'foo')
t.equal(Buffer.concat(responseBody).toString('utf-8'), 'hello h2!')
})
test('Dispatcher#Stream', t => {
const server = createSecureServer(pem)
const expectedBody = 'hello from client!'
const bufs = []
let requestBody = ''
server.on('stream', async (stream, headers) => {
stream.setEncoding('utf-8')
stream.on('data', chunk => {
requestBody += chunk
})
stream.respond({ ':status': 200, 'x-custom': 'custom-header' })
stream.end('hello h2!')
})
t.plan(4)
server.listen(0, async () => {
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
await client.stream(
{ path: '/', opaque: { bufs }, method: 'POST', body: expectedBody },
({ statusCode, headers, opaque: { bufs } }) => {
t.equal(statusCode, 200)
t.equal(headers['x-custom'], 'custom-header')
return new Writable({
write (chunk, _encoding, cb) {
bufs.push(chunk)
cb()
}
})
}
)
t.equal(Buffer.concat(bufs).toString('utf-8'), 'hello h2!')
t.equal(requestBody, expectedBody)
})
})
test('Dispatcher#Pipeline', t => {
const server = createSecureServer(pem)
const expectedBody = 'hello from client!'
const bufs = []
let requestBody = ''
server.on('stream', async (stream, headers) => {
stream.setEncoding('utf-8')
stream.on('data', chunk => {
requestBody += chunk
})
stream.respond({ ':status': 200, 'x-custom': 'custom-header' })
stream.end('hello h2!')
})
t.plan(5)
server.listen(0, () => {
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
pipeline(
new Readable({
read () {
this.push(Buffer.from(expectedBody))
this.push(null)
}
}),
client.pipeline(
{ path: '/', method: 'POST', body: expectedBody },
({ statusCode, headers, body }) => {
t.equal(statusCode, 200)
t.equal(headers['x-custom'], 'custom-header')
return pipeline(body, new PassThrough(), () => {})
}
),
new Writable({
write (chunk, _, cb) {
bufs.push(chunk)
cb()
}
}),
err => {
t.error(err)
t.equal(Buffer.concat(bufs).toString('utf-8'), 'hello h2!')
t.equal(requestBody, expectedBody)
}
)
})
})
test('Dispatcher#Connect', t => {
const server = createSecureServer(pem)
const expectedBody = 'hello from client!'
let requestBody = ''
server.on('stream', async (stream, headers) => {
stream.setEncoding('utf-8')
stream.on('data', chunk => {
requestBody += chunk
})
stream.respond({ ':status': 200, 'x-custom': 'custom-header' })
stream.end('hello h2!')
})
t.plan(6)
server.listen(0, () => {
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
let result = ''
client.connect({ path: '/' }, (err, { socket }) => {
t.error(err)
socket.on('data', chunk => {
result += chunk
})
socket.on('response', headers => {
t.equal(headers[':status'], 200)
t.equal(headers['x-custom'], 'custom-header')
t.notOk(socket.closed)
})
// We need to handle the error event although
// is not controlled by Undici, the fact that a session
// is destroyed and destroys subsequent streams, causes
// unhandled errors to surface if not handling this event.
socket.on('error', () => {})
socket.once('end', () => {
t.equal(requestBody, expectedBody)
t.equal(result, 'hello h2!')
})
socket.end(expectedBody)
})
})
})
test('Dispatcher#Upgrade', t => {
const server = createSecureServer(pem)
server.on('stream', async (stream, headers) => {
stream.end()
})
t.plan(1)
server.listen(0, async () => {
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
try {
await client.upgrade({ path: '/' })
} catch (error) {
t.equal(error.message, 'Upgrade not supported for H2')
}
})
})
test('Dispatcher#destroy', async t => {
const promises = []
const server = createSecureServer(pem)
server.on('stream', (stream, headers) => {
setTimeout(stream.end.bind(stream), 1500)
})
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.plan(4)
t.teardown(server.close.bind(server))
promises.push(
client.request({
path: '/',
method: 'GET',
headers: {
'x-my-header': 'foo'
}
})
)
promises.push(
client.request({
path: '/',
method: 'GET',
headers: {
'x-my-header': 'foo'
}
})
)
promises.push(
client.request({
path: '/',
method: 'GET',
headers: {
'x-my-header': 'foo'
}
})
)
promises.push(
client.request({
path: '/',
method: 'GET',
headers: {
'x-my-header': 'foo'
}
})
)
await client.destroy()
const results = await Promise.allSettled(promises)
t.equal(results[0].status, 'rejected')
t.equal(results[1].status, 'rejected')
t.equal(results[2].status, 'rejected')
t.equal(results[3].status, 'rejected')
})
test('Should handle h2 request with body (string or buffer) - dispatch', t => {
const server = createSecureServer(pem)
const expectedBody = 'hello from client!'
const response = []
const requestBody = []
server.on('stream', async (stream, headers) => {
stream.on('data', chunk => requestBody.push(chunk))
stream.respond({
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': headers['x-my-header'],
':status': 200
})
stream.end('hello h2!')
})
t.plan(7)
server.listen(0, () => {
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
client.dispatch(
{
path: '/',
method: 'POST',
headers: {
'x-my-header': 'foo',
'content-type': 'text/plain'
},
body: expectedBody
},
{
onConnect () {
t.ok(true)
},
onError (err) {
t.error(err)
},
onHeaders (statusCode, headers) {
t.equal(statusCode, 200)
t.equal(headers['content-type'], 'text/plain; charset=utf-8')
t.equal(headers['x-custom-h2'], 'foo')
},
onData (chunk) {
response.push(chunk)
},
onBodySent (body) {
t.equal(body.toString('utf-8'), expectedBody)
},
onComplete () {
t.equal(Buffer.concat(response).toString('utf-8'), 'hello h2!')
t.equal(
Buffer.concat(requestBody).toString('utf-8'),
'hello from client!'
)
}
}
)
})
})
test('Should handle h2 request with body (stream)', async t => {
const server = createSecureServer(pem)
const expectedBody = readFileSync(__filename, 'utf-8')
const stream = createReadStream(__filename)
const requestChunks = []
const responseBody = []
server.on('stream', async (stream, headers) => {
t.equal(headers[':method'], 'PUT')
t.equal(headers[':path'], '/')
t.equal(headers[':scheme'], 'https')
stream.respond({
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': headers['x-my-header'],
':status': 200
})
for await (const chunk of stream) {
requestChunks.push(chunk)
}
stream.end('hello h2!')
})
t.plan(8)
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
const response = await client.request({
path: '/',
method: 'PUT',
headers: {
'x-my-header': 'foo'
},
body: stream
})
for await (const chunk of response.body) {
responseBody.push(chunk)
}
t.equal(response.statusCode, 200)
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
t.equal(response.headers['x-custom-h2'], 'foo')
t.equal(Buffer.concat(responseBody).toString('utf-8'), 'hello h2!')
t.equal(Buffer.concat(requestChunks).toString('utf-8'), expectedBody)
})
test('Should handle h2 request with body (iterable)', async t => {
const server = createSecureServer(pem)
const expectedBody = 'hello'
const requestChunks = []
const responseBody = []
const iterableBody = {
[Symbol.iterator]: function * () {
const end = expectedBody.length - 1
for (let i = 0; i < end + 1; i++) {
yield expectedBody[i]
}
return expectedBody[end]
}
}
server.on('stream', async (stream, headers) => {
t.equal(headers[':method'], 'POST')
t.equal(headers[':path'], '/')
t.equal(headers[':scheme'], 'https')
stream.on('data', chunk => requestChunks.push(chunk))
stream.respond({
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': headers['x-my-header'],
':status': 200
})
stream.end('hello h2!')
})
t.plan(8)
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
const response = await client.request({
path: '/',
method: 'POST',
headers: {
'x-my-header': 'foo'
},
body: iterableBody
})
response.body.on('data', chunk => {
responseBody.push(chunk)
})
await once(response.body, 'end')
t.equal(response.statusCode, 200)
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
t.equal(response.headers['x-custom-h2'], 'foo')
t.equal(Buffer.concat(responseBody).toString('utf-8'), 'hello h2!')
t.equal(Buffer.concat(requestChunks).toString('utf-8'), expectedBody)
})
test('Should handle h2 request with body (Blob)', { skip: !Blob }, async t => {
const server = createSecureServer(pem)
const expectedBody = 'asd'
const requestChunks = []
const responseBody = []
const body = new Blob(['asd'], {
type: 'application/json'
})
server.on('stream', async (stream, headers) => {
t.equal(headers[':method'], 'POST')
t.equal(headers[':path'], '/')
t.equal(headers[':scheme'], 'https')
stream.on('data', chunk => requestChunks.push(chunk))
stream.respond({
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': headers['x-my-header'],
':status': 200
})
stream.end('hello h2!')
})
t.plan(8)
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
const response = await client.request({
path: '/',
method: 'POST',
headers: {
'x-my-header': 'foo'
},
body
})
response.body.on('data', chunk => {
responseBody.push(chunk)
})
await once(response.body, 'end')
t.equal(response.statusCode, 200)
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
t.equal(response.headers['x-custom-h2'], 'foo')
t.equal(Buffer.concat(responseBody).toString('utf-8'), 'hello h2!')
t.equal(Buffer.concat(requestChunks).toString('utf-8'), expectedBody)
})
test(
'Should handle h2 request with body (Blob:ArrayBuffer)',
{ skip: !Blob },
async t => {
const server = createSecureServer(pem)
const expectedBody = 'hello'
const requestChunks = []
const responseBody = []
const buf = Buffer.from(expectedBody)
const body = new ArrayBuffer(buf.byteLength)
buf.copy(new Uint8Array(body))
server.on('stream', async (stream, headers) => {
t.equal(headers[':method'], 'POST')
t.equal(headers[':path'], '/')
t.equal(headers[':scheme'], 'https')
stream.on('data', chunk => requestChunks.push(chunk))
stream.respond({
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': headers['x-my-header'],
':status': 200
})
stream.end('hello h2!')
})
t.plan(8)
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
const response = await client.request({
path: '/',
method: 'POST',
headers: {
'x-my-header': 'foo'
},
body
})
response.body.on('data', chunk => {
responseBody.push(chunk)
})
await once(response.body, 'end')
t.equal(response.statusCode, 200)
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
t.equal(response.headers['x-custom-h2'], 'foo')
t.equal(Buffer.concat(responseBody).toString('utf-8'), 'hello h2!')
t.equal(Buffer.concat(requestChunks).toString('utf-8'), expectedBody)
}
)
test('Agent should support H2 connection', async t => {
const body = []
const server = createSecureServer(pem)
server.on('stream', (stream, headers) => {
t.equal(headers['x-my-header'], 'foo')
t.equal(headers[':method'], 'GET')
stream.respond({
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': 'hello',
':status': 200
})
stream.end('hello h2!')
})
server.listen(0)
await once(server, 'listening')
const client = new Agent({
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.plan(6)
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
const response = await client.request({
origin: `https://localhost:${server.address().port}`,
path: '/',
method: 'GET',
headers: {
'x-my-header': 'foo'
}
})
response.body.on('data', chunk => {
body.push(chunk)
})
await once(response.body, 'end')
t.equal(response.statusCode, 200)
t.equal(response.headers['content-type'], 'text/plain; charset=utf-8')
t.equal(response.headers['x-custom-h2'], 'hello')
t.equal(Buffer.concat(body).toString('utf8'), 'hello h2!')
})
test(
'Should provide pseudo-headers in proper order',
{ skip: !hasPseudoHeadersOrderFix },
async t => {
const server = createSecureServer(pem)
server.on('stream', (stream, _headers, _flags, rawHeaders) => {
t.same(rawHeaders, [
':authority',
`localhost:${server.address().port}`,
':method',
'GET',
':path',
'/',
':scheme',
'https'
])
stream.respond({
'content-type': 'text/plain; charset=utf-8',
':status': 200
})
stream.end()
})
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
const response = await client.request({
path: '/',
method: 'GET'
})
t.equal(response.statusCode, 200)
}
)
test('The h2 pseudo-headers is not included in the headers', async t => {
const server = createSecureServer(pem)
server.on('stream', (stream, headers) => {
stream.respond({
':status': 200
})
stream.end('hello h2!')
})
server.listen(0)
await once(server, 'listening')
const client = new Client(`https://localhost:${server.address().port}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})
t.plan(2)
t.teardown(server.close.bind(server))
t.teardown(client.close.bind(client))
const response = await client.request({
path: '/',
method: 'GET'
})
await response.body.text()
t.equal(response.statusCode, 200)
t.equal(response.headers[':status'], undefined)
})