/
utils_transport.go
130 lines (116 loc) · 3.08 KB
/
utils_transport.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
* Copyright (c) 2018 The Go Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
*/
package tport
import (
"crypto/tls"
"net"
"strings"
"github.com/badu/http/url"
. "github.com/badu/http"
"golang.org/x/net/proxy"
)
func newOneConnDialer(c net.Conn) proxy.Dialer {
ch := make(chan net.Conn, 1)
ch <- c
return oneConnDialer(ch)
}
// useProxy reports whether requests to addr should use a proxy,
// according to the NO_PROXY or no_proxy environment variable.
// addr is always a canonicalAddr with a host and port.
func useProxy(addr string) bool {
if len(addr) == 0 {
return true
}
host, _, err := net.SplitHostPort(addr)
if err != nil {
return false
}
if host == "localhost" {
return false
}
if ip := net.ParseIP(host); ip != nil {
if ip.IsLoopback() {
return false
}
}
noProxy := NoProxyEnv.Get()
if noProxy == "*" {
return false
}
addr = strings.ToLower(strings.TrimSpace(addr))
if hasPort(addr) {
addr = addr[:strings.LastIndexByte(addr, ':')]
}
for _, p := range strings.Split(noProxy, ",") {
p = strings.ToLower(strings.TrimSpace(p))
if len(p) == 0 {
continue
}
if hasPort(p) {
p = p[:strings.LastIndexByte(p, ':')]
}
if addr == p {
return false
}
if len(p) == 0 {
// There is no host part, likely the entry is malformed; ignore.
continue
}
if p[0] == '.' && ((len(addr) >= len(p) && addr[len(addr)-len(p):] == p) || addr == p[1:]) {
// no_proxy ".foo.com" matches "bar.foo.com" or "foo.com"
return false
}
if p[0] != '.' && (len(addr) >= len(p) && addr[len(addr)-len(p):] == p) && addr[len(addr)-len(p)-1] == '.' {
// no_proxy "foo.com" matches "bar.foo.com"
return false
}
}
return true
}
// canonicalAddr returns url.Host but always with a ":port" suffix
func canonicalAddr(url *url.URL) string {
addr := url.Hostname()
if v, err := IdnaASCII(addr); err == nil {
addr = v
}
port := url.Port()
if port == "" {
port = portMap[url.Scheme]
}
return net.JoinHostPort(addr, port)
}
// clneTLSConfig returns a shallow clone of cfg, or a new zero tls.Config if
// cfg is nil. This is safe to call even if cfg is in active use by a TLS
// client or server.
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
if cfg == nil {
return &tls.Config{}
}
return cfg.Clone()
}
// validPort reports whether p (without the colon) is a valid port in
// a URL, per RFC 3986 Section 3.2.3, which says the port may be
// empty, or only contain digits.
func validPort(p string) bool {
for _, r := range []byte(p) {
if r < '0' || r > '9' {
return false
}
}
return true
}
//@ comment : duplicated from utils_http.go
// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
// return true if the string includes a port.
func hasPort(s string) bool { return strings.LastIndexByte(s, ':') > strings.LastIndexByte(s, ']') }
func isReplayable(r *Request) bool {
if r.Body == nil || r.Body == NoBody || r.GetBody != nil {
switch ValueOrDefault(r.Method, GET) {
case GET, HEAD, OPTIONS, TRACE:
return true
}
}
return false
}