Skip to content

When accessing an http2 server, the first request is http1 instead of http2 #2326

@binsee

Description

@binsee

Bug Description

When an Http2 request is initiated for the first time, since no connection has been established with the server yet, this[kHTTPConnVersion] ===1, the communication sent is http1 instead of http2.
So now the test code related to http2 in undici, the actual requests are http1 instead of http2

undici/lib/client.js

Lines 358 to 374 in 882ff6d

[kDispatch] (opts, handler) {
const origin = opts.origin || this[kUrl].origin
const request = this[kHTTPConnVersion] === 'h2'
? Request[kHTTP2BuildRequest](origin, opts, handler)
: Request[kHTTP1BuildRequest](origin, opts, handler)
this[kQueue].push(request)
if (this[kResuming]) {
// Do nothing.
} else if (util.bodyLength(request.body) == null && util.isIterable(request.body)) {
// Wait a tick in case stream/iterator is ended in the same tick.
this[kResuming] = 1
process.nextTick(resume, this)
} else {
resume(this, true)
}

Reproducible By

I added the parameter allowHTTP1: false to createSecureServer

undici/test/http2.js

Lines 22 to 24 in 882ff6d

test('Should support H2 connection', async t => {
const body = []
const server = createSecureServer(pem)

test('Should support H2 connection', async t => {
  const body = []
  const server = createSecureServer({ pem, allowHTTP1: false })

  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!')
})

Expected Behavior

If the server supports http2, the first request should be http2

Logs & Screenshots

 FAIL ​ test/http2.js
 ✖ Client network socket disconnected before secure TLS connection was established

  test: Should support H2 connection
  at:
    line: 705
    column: 14
    file: node:internal/errors
    function: connResetException
  code: ECONNRESET
  path: null
  host: localhost
  port: "54451"
  localAddress: null
  tapCaught: returnedPromiseRejection

test/http2.js 2> (node:20913) [UNDICI-H2] Warning: H2 support is experimental, expect them to change at any time.
test/http2.js 2> (Use `node --trace-warnings ...` to show where the warning was created)
​ SKIP ​ test/http2.js
 ~ [v20] Request should fail if allowH2 is false and server advertises h1 only

​ FAIL ​ test/http2.js 1 failed 1 skip of 101 1s
 ✖ Client network socket disconnected before secure TLS connection was established
 ~ [v20] Request should fail if allowH2 is false and server advertises h1 only



                         
  🌈 SUMMARY RESULTS 🌈  
                         
​ FAIL ​ test/http2.js 1 failed 1 skip of 101 1s
 ✖ Client network socket disconnected before secure TLS connection was established
 ~ [v20] Request should fail if allowH2 is false and server advertises h1 only


Suites:   ​1 failed​, ​1 of 1 completed​
Asserts:  ​​​1 failed​, ​99 passed​, ​1 skip​, ​of 101​
​Time:​   ​2s​

Environment

  • MacOS 14.0
  • Nodejs v16.19.0

Additional context

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions