forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 1
/
httprequest.go
110 lines (97 loc) · 3.01 KB
/
httprequest.go
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
99
100
101
102
103
104
105
106
107
108
109
110
package httprequest
import (
"net"
"net/http"
"strings"
"bitbucket.org/ww/goautoneg"
)
// PrefersHTML returns true if the request was made by something that looks like a browser, or can receive HTML
func PrefersHTML(req *http.Request) bool {
accepts := goautoneg.ParseAccept(req.Header.Get("Accept"))
acceptsHTML := false
acceptsJSON := false
for _, accept := range accepts {
if accept.Type == "text" && accept.SubType == "html" {
acceptsHTML = true
} else if accept.Type == "application" && accept.SubType == "json" {
acceptsJSON = true
}
}
// If HTML is accepted, return true
if acceptsHTML {
return true
}
// If JSON was specifically requested, return false
// This gives browsers a way to make requests and add an "Accept" header to request JSON
if acceptsJSON {
return false
}
// In Intranet/Compatibility mode, IE sends an Accept header that does not contain "text/html".
if strings.HasPrefix(req.UserAgent(), "Mozilla") {
return true
}
return false
}
// SchemeHost returns the scheme and host used to make this request.
// Suitable for use to compute scheme/host in returned 302 redirect Location.
// Note the returned host is not normalized, and may or may not contain a port.
// Returned values are based on the following information:
//
// Host:
// * X-Forwarded-Host/X-Forwarded-Port headers
// * Host field on the request (parsed from Host header)
// * Host in the request's URL (parsed from Request-Line)
//
// Scheme:
// * X-Forwarded-Proto header
// * Existence of TLS information on the request implies https
// * Scheme in the request's URL (parsed from Request-Line)
// * Port (if included in calculated Host value, 443 implies https)
// * Otherwise, defaults to "http"
func SchemeHost(req *http.Request) (string /*scheme*/, string /*host*/) {
forwarded := func(attr string) string {
// Get the X-Forwarded-<attr> value
value := req.Header.Get("X-Forwarded-" + attr)
// Take the first comma-separated value, if multiple exist
value = strings.SplitN(value, ",", 2)[0]
// Trim whitespace
return strings.TrimSpace(value)
}
forwardedProto := forwarded("Proto")
forwardedHost := forwarded("Host")
// If both X-Forwarded-Host and X-Forwarded-Port are sent, use the explicit port info
if forwardedPort := forwarded("Port"); len(forwardedHost) > 0 && len(forwardedPort) > 0 {
if h, _, err := net.SplitHostPort(forwardedHost); err == nil {
forwardedHost = net.JoinHostPort(h, forwardedPort)
} else {
forwardedHost = net.JoinHostPort(forwardedHost, forwardedPort)
}
}
host := ""
switch {
case len(forwardedHost) > 0:
host = forwardedHost
case len(req.Host) > 0:
host = req.Host
case len(req.URL.Host) > 0:
host = req.URL.Host
}
port := ""
if _, p, err := net.SplitHostPort(host); err == nil {
port = p
}
scheme := ""
switch {
case len(forwardedProto) > 0:
scheme = forwardedProto
case req.TLS != nil:
scheme = "https"
case len(req.URL.Scheme) > 0:
scheme = req.URL.Scheme
case port == "443":
scheme = "https"
default:
scheme = "http"
}
return scheme, host
}