1package v4
2
3import (
4 "net/http"
5 "strings"
6)
7
8// SanitizeHostForHeader removes default port from host and updates request.Host
9func SanitizeHostForHeader(r *http.Request) {
10 host := getHost(r)
11 port := portOnly(host)
12 if port != "" && isDefaultPort(r.URL.Scheme, port) {
13 r.Host = stripPort(host)
14 }
15}
16
17// Returns host from request
18func getHost(r *http.Request) string {
19 if r.Host != "" {
20 return r.Host
21 }
22
23 return r.URL.Host
24}
25
26// Hostname returns u.Host, without any port number.
27//
28// If Host is an IPv6 literal with a port number, Hostname returns the
29// IPv6 literal without the square brackets. IPv6 literals may include
30// a zone identifier.
31//
32// Copied from the Go 1.8 standard library (net/url)
33func stripPort(hostport string) string {
34 colon := strings.IndexByte(hostport, ':')
35 if colon == -1 {
36 return hostport
37 }
38 if i := strings.IndexByte(hostport, ']'); i != -1 {
39 return strings.TrimPrefix(hostport[:i], "[")
40 }
41 return hostport[:colon]
42}
43
44// Port returns the port part of u.Host, without the leading colon.
45// If u.Host doesn't contain a port, Port returns an empty string.
46//
47// Copied from the Go 1.8 standard library (net/url)
48func portOnly(hostport string) string {
49 colon := strings.IndexByte(hostport, ':')
50 if colon == -1 {
51 return ""
52 }
53 if i := strings.Index(hostport, "]:"); i != -1 {
54 return hostport[i+len("]:"):]
55 }
56 if strings.Contains(hostport, "]") {
57 return ""
58 }
59 return hostport[colon+len(":"):]
60}
61
62// Returns true if the specified URI is using the standard port
63// (i.e. port 80 for HTTP URIs or 443 for HTTPS URIs)
64func isDefaultPort(scheme, port string) bool {
65 if port == "" {
66 return true
67 }
68
69 lowerCaseScheme := strings.ToLower(scheme)
70 if (lowerCaseScheme == "http" && port == "80") || (lowerCaseScheme == "https" && port == "443") {
71 return true
72 }
73
74 return false
75}