Repository: honojs/hono
File: src/helper/proxy/index.ts (TypeScript)

Code before:
    | [string, string][]
    | Record<RequestHeader, string | undefined>
    | Record<string, string | undefined>
  customFetch?: (request: Request) => Promise<Response>
}

interface ProxyFetch {
  (input: string | URL | Request, init?: ProxyRequestInit): Promise<Response>
}

const buildRequestInitFromRequest = (
  request: Request | undefined
): RequestInit & { duplex?: 'half' } => {
  if (!request) {
    return {}
  }

  const headers = new Headers(request.headers)

  // https://datatracker.ietf.org/doc/html/rfc9110#section-7.6.1
  // Parse Connection header and remove listed headers (MUST per RFC 9110)
  const connectionValue = headers.get('connection')
  if (connectionValue) {
    connectionValue
      .split(',')
      .map((h) => h.trim().toLowerCase())
      .forEach((h) => headers.delete(h))
  }

  hopByHopHeaders.forEach((header) => {
    headers.delete(header)
  })

  return {
    method: request.method,
    body: request.body,
    duplex: request.body ? 'half' : undefined,
    headers,
    signal: request.signal,
  }
}

const preprocessRequestInit = (requestInit: RequestInit): RequestInit => {
  if (
    !requestInit.headers ||
    Array.isArray(requestInit.headers) ||
    requestInit.headers instanceof Headers
  ) {
    return requestInit
  }


Review comment (suggestion):
The header name is normalized within `headers.delete()`, so I believe `.toLowerCase()` is unnecessary.

```suggestion
      .map((h) => h.trim()
```

Code after:
interface ProxyRequestInit extends Omit<RequestInit, 'headers'> {
  raw?: Request
  headers?:
    | HeadersInit
    | [string, string][]
    | Record<RequestHeader, string | undefined>
    | Record<string, string | undefined>
  customFetch?: (request: Request) => Promise<Response>
  /**
   * Enable strict RFC 9110 compliance for Connection header processing.
   *
   * - `false` (default): Ignores Connection header to prevent potential
   *   Hop-by-Hop Header Injection attacks. Recommended for untrusted clients.
   * - `true`: Processes Connection header per RFC 9110 and removes listed headers.
   *   Only use in trusted environments.
   *
   * @default false
   * @see https://datatracker.ietf.org/doc/html/rfc9110#section-7.6.1
   */
  strictConnectionProcessing?: boolean
}

interface ProxyFetch {
  (input: string | URL | Request, init?: ProxyRequestInit): Promise<Response>
}

const buildRequestInitFromRequest = (
  request: Request | undefined,
  strictConnectionProcessing: boolean
): RequestInit & { duplex?: 'half' } => {
  if (!request) {
    return {}
  }

  const headers = new Headers(request.headers)

  if (strictConnectionProcessing) {
    // https://datatracker.ietf.org/doc/html/rfc9110#section-7.6.1
    // Parse Connection header and remove listed headers (MUST per RFC 9110)
    const connectionValue = headers.get('connection')
    if (connectionValue) {
      const headerNames = connectionValue.split(',').map((h) => h.trim())
      // Validate header names per RFC 9110 Section 5.6.2 (token syntax)
      const invalidHeaders = headerNames.filter((h) => !ALLOWED_TOKEN_PATTERN.test(h))

      if (invalidHeaders.length > 0) {
        throw new HTTPException(400, {
          message: `Invalid Connection header value: ${invalidHeaders.join(', ')}`,
        })
      }
      headerNames.forEach((headerName) => {