Skip to content

doc: document http2 header constants#64548

Open
harjothkhara wants to merge 1 commit into
nodejs:mainfrom
harjothkhara:codex/doc-http2-25952
Open

doc: document http2 header constants#64548
harjothkhara wants to merge 1 commit into
nodejs:mainfrom
harjothkhara:codex/doc-http2-25952

Conversation

@harjothkhara

@harjothkhara harjothkhara commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #25952.

Related: #64235, which was closed unmerged after addressing the compatibility
example and leaving the constants documentation for a follow-up.

This change:

  • documents all 86 exported HTTP2_HEADER_* constants;
  • explains that regular header constants are optional string values and are
    interchangeable with accepted literal header names;
  • documents compatibility-API handling for pseudo-headers, header casing,
    validation, trailers, and connection-specific fields;
  • simplifies the introductory compatibility example so both response headers
    are set directly through writeHead().

The documentation is the correct fix boundary because the runtime constants
and behavior already exist. This change does not alter HTTP/2 runtime behavior,
public APIs, or compatibility. The blast radius is limited to
doc/api/http2.md.

Verification

The full documentation target passed:

$ make test-doc
Running JS linter...
Running Markdown linter...
[00:00|% 100|+   3|-   0]: Done

All tests passed.

The existing HTTP/2 binding test passed:

$ ./node test/parallel/test-http2-binding.js
# exited successfully

All documented constant names and values were compared with the current
runtime export:

$ ./node -e 'const assert=require("node:assert/strict");const fs=require("node:fs");const constants=require("node:http2").constants;const md=fs.readFileSync("doc/api/http2.md","utf8");const rows=new Map();for(const line of md.split("\n")){const match=line.match(/`http2\.constants\.(HTTP2_HEADER_[A-Z0-9_]+)`\s*\|\s*`\x27([^\x27]+)\x27`/);if(match)rows.set(match[1],match[2]);}const expected=Object.entries(constants).filter(([name])=>name.startsWith("HTTP2_HEADER_"));assert.equal(rows.size,expected.length);for(const [name,value] of expected)assert.equal(rows.get(name),value,name);console.log(`${rows.size} documented header constants verified`);'
86 documented header constants verified

The committed diff also passes:

$ git diff origin/main...HEAD --check
# no output

Real-behavior proof

This uses an actual HTTP/2 compatibility server and client. It compares a
response using HTTP2_HEADER_CONTENT_TYPE with one using the mixed-case
literal Content-Type, verifies the client-visible status, headers, and body,
and checks compatibility-API rejection of HTTP2_HEADER_STATUS.

$ ./node - <<'NODE'
const assert = require('node:assert/strict');
const { connect, constants, createServer } = require('node:http2');

let statusConstantError;
const server = createServer((request, response) => {
  try {
    response.setHeader(constants.HTTP2_HEADER_STATUS, 201);
  } catch (error) {
    statusConstantError = error.code;
  }

  const headers = request.url === '/constant' ?
    {
      [constants.HTTP2_HEADER_CONTENT_TYPE]: 'text/plain; charset=utf-8',
      'X-Foo': 'bar',
    } :
    {
      'Content-Type': 'text/plain; charset=utf-8',
      'X-Foo': 'bar',
    };

  response.writeHead(200, headers);
  response.end('ok');
});

server.listen(0, () => {
  const client = connect(`http://127.0.0.1:${server.address().port}`);
  const run = (path) => new Promise((resolve, reject) => {
    const request = client.request({ ':path': path });
    let body = '';
    let headers;

    request.on('response', (value) => { headers = value; });
    request.setEncoding('utf8');
    request.on('data', (chunk) => { body += chunk; });
    request.on('end', () => resolve({
      status: headers[':status'],
      contentType: headers['content-type'],
      xFoo: headers['x-foo'],
      body,
    }));
    request.on('error', reject);
    request.end();
  });

  Promise.all([run('/constant'), run('/literal')]).then(
    ([constant, literal]) => {
      assert.deepEqual(constant, literal);
      assert.deepEqual(constant, {
        status: 200,
        contentType: 'text/plain; charset=utf-8',
        xFoo: 'bar',
        body: 'ok',
      });
      assert.equal(
        statusConstantError,
        'ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED',
      );

      console.log(JSON.stringify({
        constant,
        literal,
        statusConstantError,
      }, null, 2));
      client.close();
      server.close();
    },
  );
});
NODE
{
  "constant": {
    "status": 200,
    "contentType": "text/plain; charset=utf-8",
    "xFoo": "bar",
    "body": "ok"
  },
  "literal": {
    "status": 200,
    "contentType": "text/plain; charset=utf-8",
    "xFoo": "bar",
    "body": "ok"
  },
  "statusConstantError": "ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED"
}

AI-assisted: developed with OpenAI Codex; I reviewed the documentation and verified the behavior and test results above.

Signed-off-by: harjoth <harjoth.khara@gmail.com>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/http
  • @nodejs/http2
  • @nodejs/net

@nodejs-github-bot nodejs-github-bot added doc Issues and PRs related to the documentations. http2 Issues or PRs related to the http2 subsystem. labels Jul 17, 2026
@harjothkhara
harjothkhara marked this pull request as ready for review July 17, 2026 00:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

doc Issues and PRs related to the documentations. http2 Issues or PRs related to the http2 subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

http2 API documentation issues

2 participants