File size: 1,589 Bytes
9ada4bc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import { getValueBySymbol } from './getValueBySymbol'
import { isObject } from './isObject'

type RawHeadersMap = Map<string, string>
type HeadersMapHeader = { name: string; value: string }

/**
 * Returns raw headers from the given `Headers` instance.
 * @example
 * const headers = new Headers([
 *   ['X-HeadeR-NamE', 'Value']
 * ])
 * getRawFetchHeaders(headers)
 * // { 'X-HeadeR-NamE': 'Value' }
 */
export function getRawFetchHeaders(
  headers: Headers
): RawHeadersMap | undefined {
  const headersList = getValueBySymbol<object>('headers list', headers)

  if (!headersList) {
    return
  }

  const headersMap = getValueBySymbol<
    Map<string, string> | Map<string, HeadersMapHeader>
  >('headers map', headersList)

  /**
   * @note Older versions of Node.js (e.g. 18.8.0) keep headers map
   * as Map<normalizedHeaderName, value> without any means to tap
   * into raw header values. Detect that and return undefined.
   */
  if (!headersMap || !isHeadersMapWithRawHeaderNames(headersMap)) {
    return
  }

  // Raw headers is a map of { rawHeaderName: rawHeaderValue }
  const rawHeaders: RawHeadersMap = new Map<string, string>()

  headersMap.forEach(({ name, value }) => {
    rawHeaders.set(name, value)
  })

  return rawHeaders
}

function isHeadersMapWithRawHeaderNames(
  headersMap: Map<string, string> | Map<string, HeadersMapHeader>
): headersMap is Map<string, HeadersMapHeader> {
  return Array.from(
    headersMap.values() as Iterable<string | HeadersMapHeader>
  ).every((value) => {
    return isObject<HeadersMapHeader>(value) && 'name' in value
  })
}