-
Notifications
You must be signed in to change notification settings - Fork 9
/
index.js
98 lines (83 loc) · 3.75 KB
/
index.js
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
'use strict'
const parseUrl = require('url').parse
const parseForwarded = require('forwarded-parse')
const net = require('net')
module.exports = function (req) {
const raw = req.originalUrl || req.url
const url = parseUrl(raw || '')
const secure = req.secure || (req.connection && req.connection.encrypted)
const result = { raw: raw }
let host
if (req.headers.forwarded) {
let forwarded = getFirstHeader(req, 'forwarded')
try {
// Always choose the original (first) Forwarded pair in case the request
// passed through multiple proxies
forwarded = parseForwarded(forwarded)[0]
host = parsePartialURL(forwarded.host)
if (forwarded.for) {
const conn = forwarded.for.split(']') // in case of IPv6 addr: [2001:db8:cafe::17]:1337
const port = conn[conn.length - 1].split(':')[1]
if (port) host.port = Number(port)
}
if (forwarded.proto) host.protocol = forwarded.proto + ':'
} catch (e) {}
} else if (req.headers['x-forwarded-host']) {
host = parsePartialURL(getFirstHeader(req, 'x-forwarded-host'))
}
if (!host) {
if (typeof req.headers.host === 'string') {
host = parsePartialURL(req.headers.host)
} else {
host = {}
}
}
// protocol
if (url.protocol) result.protocol = url.protocol
else if (req.headers['x-forwarded-proto']) result.protocol = getFirstHeader(req, 'x-forwarded-proto') + ':'
else if (req.headers['x-forwarded-protocol']) result.protocol = getFirstHeader(req, 'x-forwarded-protocol') + ':'
else if (req.headers['x-url-scheme']) result.protocol = getFirstHeader(req, 'x-url-scheme') + ':'
else if (req.headers['front-end-https']) result.protocol = getFirstHeader(req, 'front-end-https') === 'on' ? 'https:' : 'http:'
else if (req.headers['x-forwarded-ssl']) result.protocol = getFirstHeader(req, 'x-forwarded-ssl') === 'on' ? 'https:' : 'http:'
else if (host.protocol) result.protocol = host.protocol
else if (secure) result.protocol = 'https:'
else result.protocol = 'http:'
// hostname
if (url.hostname) result.hostname = url.hostname
else if (host.hostname) result.hostname = host.hostname
// fix for IPv6 literal bug in legacy url - see https://github.com/watson/original-url/issues/3
if (net.isIPv6(result.hostname)) result.hostname = '[' + result.hostname + ']'
// port
if (url.port) result.port = Number(url.port)
else if (req.headers['x-forwarded-port']) result.port = Number(getFirstHeader(req, 'x-forwarded-port'))
else if (host.port) result.port = Number(host.port)
// pathname
if (url.pathname) result.pathname = url.pathname
else if (host.pathname) result.pathname = host.pathname // TODO: Consider if this should take priority over url.pathname
// search
if (url.search) result.search = url.search
else if (host.search) result.search = host.search // TODO: Consider if this shoudl take priority over uri.search
// hash
if (host.hash) result.hash = host.hash
// full
if (result.protocol && result.hostname) {
result.full = result.protocol + '//' + result.hostname
if (result.port) result.full += ':' + result.port
if (result.pathname) result.full += result.pathname
if (result.search) result.full += result.search
if (result.hash) result.full += result.hash
}
return result
}
// In case there's more than one header of a given name, we want the first one
// as it should be the one that was added by the first proxy in the chain
function getFirstHeader (req, header) {
const value = req.headers[header]
return (Array.isArray(value) ? value[0] : value).split(', ')[0]
}
function parsePartialURL (url) {
const containsProtocol = url.indexOf('://') !== -1
const result = parseUrl(containsProtocol ? url : 'invalid://' + url)
if (!containsProtocol) result.protocol = ''
return result
}