Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion lib/core/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ const {
serializePathWithQuery,
assertRequestHandler,
getServerName,
normalizedMethodRecords
normalizedMethodRecords,
getProtocolFromUrlString
} = require('./util')
const { channels } = require('./diagnostics.js')
const { headerNameLowerCasedRecord } = require('./constants')
Expand Down Expand Up @@ -141,8 +142,11 @@ class Request {

this.path = query ? serializePathWithQuery(path, query) : path

// TODO: shall we maybe standardize it to an URL object?
this.origin = origin

this.protocol = getProtocolFromUrlString(origin)

this.idempotent = idempotent == null
? method === 'HEAD' || method === 'GET'
: idempotent
Expand Down
27 changes: 26 additions & 1 deletion lib/core/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,30 @@ function onConnectTimeout (socket, opts) {
destroy(socket, new ConnectTimeoutError(message))
}

/**
* @param {string} urlString
* @returns {string}
*/
function getProtocolFromUrlString (urlString) {
if (
urlString[0] === 'h' &&
urlString[1] === 't' &&
urlString[2] === 't' &&
urlString[3] === 'p'
) {
switch (urlString[4]) {
case ':':
return 'http:'
case 's':
if (urlString[5] === ':') {
return 'https:'
}
}
}
// fallback if none of the usual suspects
return urlString.slice(0, urlString.indexOf(':') + 1)
}

const kEnumerableProperty = Object.create(null)
kEnumerableProperty.enumerable = true

Expand Down Expand Up @@ -950,5 +974,6 @@ module.exports = {
nodeMinor,
safeHTTPMethods: Object.freeze(['GET', 'HEAD', 'OPTIONS', 'TRACE']),
wrapRequestBody,
setupConnectTimeout
setupConnectTimeout,
getProtocolFromUrlString
}
4 changes: 2 additions & 2 deletions lib/dispatcher/client-h2.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ function shouldSendContentLength (method) {
function writeH2 (client, request) {
const requestTimeout = request.bodyTimeout ?? client[kBodyTimeout]
const session = client[kHTTP2Session]
const { method, path, host, upgrade, expectContinue, signal, headers: reqHeaders } = request
const { method, path, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request
let { body } = request

if (upgrade) {
Expand Down Expand Up @@ -387,7 +387,7 @@ function writeH2 (client, request) {
// :path and :scheme headers must be omitted when sending CONNECT

headers[HTTP2_HEADER_PATH] = path
headers[HTTP2_HEADER_SCHEME] = 'https'
headers[HTTP2_HEADER_SCHEME] = protocol === 'http:' ? 'http' : 'https'

// https://tools.ietf.org/html/rfc7231#section-4.3.1
// https://tools.ietf.org/html/rfc7231#section-4.3.2
Expand Down
3 changes: 1 addition & 2 deletions lib/dispatcher/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,7 @@ class Client extends DispatcherBase {
}

[kDispatch] (opts, handler) {
const origin = opts.origin || this[kUrl].origin
Comment thread
Uzlopak marked this conversation as resolved.
const request = new Request(origin, opts, handler)
const request = new Request(this[kUrl].origin, opts, handler)

this[kQueue].push(request)
if (this[kResuming]) {
Expand Down
10 changes: 8 additions & 2 deletions test/h2c-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,22 @@ test('Should throw if pipelining greather than concurrent streams', async t => {
})

test('Should support h2c connection', async t => {
const planner = tspl(t, { plan: 2 })
const planner = tspl(t, { plan: 6 })
let authority = ''

const server = createServer((req, res) => {
planner.equal(req.headers[':authority'], authority)
planner.equal(req.headers[':method'], 'GET')
planner.equal(req.headers[':path'], '/')
planner.equal(req.headers[':scheme'], 'http')
res.writeHead(200)
res.end('Hello, world!')
})

server.listen()
await once(server, 'listening')
const client = new H2CClient(`http://localhost:${server.address().port}/`)
authority = `localhost:${server.address().port}`
const client = new H2CClient(`http://${authority}/`)

t.after(() => client.close())
t.after(() => server.close())
Expand Down
10 changes: 7 additions & 3 deletions test/http2.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ const isGreaterThanv20 = process.versions.node.split('.').map(Number)[0] >= 20
test('Should support H2 connection', async t => {
const body = []
const server = createSecureServer(await pem.generate({ opts: { keySize: 2048 } }))
let authority = ''

server.on('stream', (stream, headers, _flags, rawHeaders) => {
t.strictEqual(headers['x-my-header'], 'foo')
t.strictEqual(headers[':method'], 'GET')
t.strictEqual(headers[':scheme'], 'https')
t.strictEqual(headers[':path'], '/')
t.strictEqual(headers[':authority'], authority)
stream.respond({
'content-type': 'text/plain; charset=utf-8',
'x-custom-h2': 'hello',
Expand All @@ -30,15 +34,15 @@ test('Should support H2 connection', async t => {

server.listen(0)
await once(server, 'listening')

const client = new Client(`https://localhost:${server.address().port}`, {
authority = `localhost:${server.address().port}`
const client = new Client(`https://${authority}`, {
connect: {
rejectUnauthorized: false
},
allowH2: true
})

t = tspl(t, { plan: 6 })
t = tspl(t, { plan: 9 })
after(() => server.close())
after(() => client.close())

Expand Down
Loading