OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / net / proxy / per_host.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package proxy
6
7 import (
8         "net"
9         "strings"
10 )
11
12 // A PerHost directs connections to a default Dialer unless the host name
13 // requested matches one of a number of exceptions.
14 type PerHost struct {
15         def, bypass Dialer
16
17         bypassNetworks []*net.IPNet
18         bypassIPs      []net.IP
19         bypassZones    []string
20         bypassHosts    []string
21 }
22
23 // NewPerHost returns a PerHost Dialer that directs connections to either
24 // defaultDialer or bypass, depending on whether the connection matches one of
25 // the configured rules.
26 func NewPerHost(defaultDialer, bypass Dialer) *PerHost {
27         return &PerHost{
28                 def:    defaultDialer,
29                 bypass: bypass,
30         }
31 }
32
33 // Dial connects to the address addr on the given network through either
34 // defaultDialer or bypass.
35 func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) {
36         host, _, err := net.SplitHostPort(addr)
37         if err != nil {
38                 return nil, err
39         }
40
41         return p.dialerForRequest(host).Dial(network, addr)
42 }
43
44 func (p *PerHost) dialerForRequest(host string) Dialer {
45         if ip := net.ParseIP(host); ip != nil {
46                 for _, net := range p.bypassNetworks {
47                         if net.Contains(ip) {
48                                 return p.bypass
49                         }
50                 }
51                 for _, bypassIP := range p.bypassIPs {
52                         if bypassIP.Equal(ip) {
53                                 return p.bypass
54                         }
55                 }
56                 return p.def
57         }
58
59         for _, zone := range p.bypassZones {
60                 if strings.HasSuffix(host, zone) {
61                         return p.bypass
62                 }
63                 if host == zone[1:] {
64                         // For a zone "example.com", we match "example.com"
65                         // too.
66                         return p.bypass
67                 }
68         }
69         for _, bypassHost := range p.bypassHosts {
70                 if bypassHost == host {
71                         return p.bypass
72                 }
73         }
74         return p.def
75 }
76
77 // AddFromString parses a string that contains comma-separated values
78 // specifying hosts that should use the bypass proxy. Each value is either an
79 // IP address, a CIDR range, a zone (*.example.com) or a host name
80 // (localhost). A best effort is made to parse the string and errors are
81 // ignored.
82 func (p *PerHost) AddFromString(s string) {
83         hosts := strings.Split(s, ",")
84         for _, host := range hosts {
85                 host = strings.TrimSpace(host)
86                 if len(host) == 0 {
87                         continue
88                 }
89                 if strings.Contains(host, "/") {
90                         // We assume that it's a CIDR address like 127.0.0.0/8
91                         if _, net, err := net.ParseCIDR(host); err == nil {
92                                 p.AddNetwork(net)
93                         }
94                         continue
95                 }
96                 if ip := net.ParseIP(host); ip != nil {
97                         p.AddIP(ip)
98                         continue
99                 }
100                 if strings.HasPrefix(host, "*.") {
101                         p.AddZone(host[1:])
102                         continue
103                 }
104                 p.AddHost(host)
105         }
106 }
107
108 // AddIP specifies an IP address that will use the bypass proxy. Note that
109 // this will only take effect if a literal IP address is dialed. A connection
110 // to a named host will never match an IP.
111 func (p *PerHost) AddIP(ip net.IP) {
112         p.bypassIPs = append(p.bypassIPs, ip)
113 }
114
115 // AddNetwork specifies an IP range that will use the bypass proxy. Note that
116 // this will only take effect if a literal IP address is dialed. A connection
117 // to a named host will never match.
118 func (p *PerHost) AddNetwork(net *net.IPNet) {
119         p.bypassNetworks = append(p.bypassNetworks, net)
120 }
121
122 // AddZone specifies a DNS suffix that will use the bypass proxy. A zone of
123 // "example.com" matches "example.com" and all of its subdomains.
124 func (p *PerHost) AddZone(zone string) {
125         if strings.HasSuffix(zone, ".") {
126                 zone = zone[:len(zone)-1]
127         }
128         if !strings.HasPrefix(zone, ".") {
129                 zone = "." + zone
130         }
131         p.bypassZones = append(p.bypassZones, zone)
132 }
133
134 // AddHost specifies a host name that will use the bypass proxy.
135 func (p *PerHost) AddHost(host string) {
136         if strings.HasSuffix(host, ".") {
137                 host = host[:len(host)-1]
138         }
139         p.bypassHosts = append(p.bypassHosts, host)
140 }