• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cameri / nostream / 26391600408

25 May 2026 08:38AM UTC coverage: 65.081% (-0.04%) from 65.119%
26391600408

Pull #628

github

web-flow
Merge 44477a61c into 54139ed49
Pull Request #628: refactor(http): remove deprecated remote_ip_header fallback

1834 of 3164 branches covered (57.96%)

Branch coverage included in aggregate %.

8 of 8 new or added lines in 1 file covered. (100.0%)

2 existing lines in 1 file now uncovered.

4173 of 6066 relevant lines covered (68.79%)

18.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.74
/src/utils/http.ts
1
import { IncomingMessage } from 'http'
2

3
import { createLogger } from '../factories/logger-factory'
2✔
4
import { Settings } from '../@types/settings'
5

6
const logger = createLogger('http-utils')
2✔
7

8
const normalizeIpAddress = (input: string): string => {
2✔
9
  if (input.startsWith('::ffff:')) {
996✔
10
    return input.slice(7)
245✔
11
  }
12

13
  return input
751✔
14
}
15

16
const isTrustedProxy = (ipAddress: string, settings: Settings): boolean => {
2✔
17
  const trustedProxies = settings.network?.trustedProxies
303✔
18

19
  if (!Array.isArray(trustedProxies) || trustedProxies.length === 0) {
303✔
20
    return false
49✔
21
  }
22

23
  const normalizedRemote = normalizeIpAddress(ipAddress)
254✔
24

25
  return trustedProxies.some((trustedProxy) => {
254✔
26
    return normalizeIpAddress(trustedProxy) === normalizedRemote
742✔
27
  })
28
}
29

30
export const getRemoteAddress = (request: IncomingMessage, settings: Settings): string => {
2✔
31
  const header = settings.network.remoteIpHeader as string
286✔
32

33
  const trustedProxies = settings.network?.trustedProxies
286✔
34
  if (header && (!Array.isArray(trustedProxies) || trustedProxies.length === 0)) {
286✔
35
    logger.warn('WARNING: network.remoteIpHeader is set but network.trustedProxies is empty. Forwarded headers will be ignored. Add your proxy IP to network.trustedProxies.')
2✔
36
  }
37

38
  const rawHeaderAddress = header ? request.headers[header] : undefined
286✔
39
  const headerAddress = Array.isArray(rawHeaderAddress) ? rawHeaderAddress[0] : rawHeaderAddress
286✔
40
  const socketAddress = request.socket.remoteAddress
286✔
41

42
  const trustedProxy = typeof socketAddress === 'string'
286✔
43
    && isTrustedProxy(socketAddress, settings)
44

45
  const result = trustedProxy && typeof headerAddress === 'string'
286✔
46
    ? headerAddress
47
    : socketAddress
48

49
  return (result as string).split(',')[0].trim()
286✔
50
}
51

52
const normalizePathPrefix = (pathPrefix: string | undefined): string => {
2✔
53
  if (typeof pathPrefix !== 'string') {
65✔
54
    return ''
9✔
55
  }
56

57
  const prefix = pathPrefix.split(',')[0].trim()
56✔
58

59
  if (!prefix.startsWith('/') || prefix.startsWith('//')) {
56✔
60
    return ''
2✔
61
  }
62

63
  try {
54✔
64
    const { pathname } = new URL(prefix, 'http://nostream.local')
54✔
65
    const normalized = pathname.replace(/\/+$/, '')
54✔
66

67
    return normalized === '/' ? '' : normalized
54!
68
  } catch {
UNCOV
69
    return ''
×
70
  }
71
}
72

73
const getRelayUrlPathPrefix = (relayUrl: string | undefined): string => {
2✔
74
  if (typeof relayUrl !== 'string') {
61✔
75
    return ''
9✔
76
  }
77

78
  try {
52✔
79
    return normalizePathPrefix(new URL(relayUrl).pathname)
52✔
80
  } catch {
UNCOV
81
    return ''
×
82
  }
83
}
84

85
const getTrustedForwardedPathPrefix = (request: IncomingMessage, settings: Settings): string => {
2✔
86
  const socketAddress = request.socket?.remoteAddress
63✔
87
  if (typeof socketAddress !== 'string' || !isTrustedProxy(socketAddress, settings)) {
63✔
88
    return ''
50✔
89
  }
90

91
  const rawHeader = request.headers?.['x-forwarded-prefix']
13✔
92
  const rawPrefix = Array.isArray(rawHeader) ? rawHeader[0] : rawHeader
13!
93

94
  return normalizePathPrefix(rawPrefix)
13✔
95
}
96

97
export const getPublicPathPrefix = (request: IncomingMessage, settings: Settings): string => {
2✔
98
  return getTrustedForwardedPathPrefix(request, settings) || getRelayUrlPathPrefix(settings.info?.relay_url)
63✔
99
}
100

101
export const joinPathPrefix = (prefix: string, path: string): string => {
2✔
102
  const normalizedPrefix = prefix.replace(/\/+$/, '')
17✔
103
  const normalizedPath = path.startsWith('/') ? path : `/${path}`
17!
104

105
  return `${normalizedPrefix}${normalizedPath}`
17✔
106
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc