http.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package net
  14. import (
  15. "crypto/tls"
  16. "fmt"
  17. "io"
  18. "net"
  19. "net/http"
  20. "net/url"
  21. "os"
  22. "strconv"
  23. "strings"
  24. "github.com/golang/glog"
  25. "golang.org/x/net/http2"
  26. )
  27. // IsProbableEOF returns true if the given error resembles a connection termination
  28. // scenario that would justify assuming that the watch is empty.
  29. // These errors are what the Go http stack returns back to us which are general
  30. // connection closure errors (strongly correlated) and callers that need to
  31. // differentiate probable errors in connection behavior between normal "this is
  32. // disconnected" should use the method.
  33. func IsProbableEOF(err error) bool {
  34. if uerr, ok := err.(*url.Error); ok {
  35. err = uerr.Err
  36. }
  37. switch {
  38. case err == io.EOF:
  39. return true
  40. case err.Error() == "http: can't write HTTP request on broken connection":
  41. return true
  42. case strings.Contains(err.Error(), "connection reset by peer"):
  43. return true
  44. case strings.Contains(strings.ToLower(err.Error()), "use of closed network connection"):
  45. return true
  46. }
  47. return false
  48. }
  49. var defaultTransport = http.DefaultTransport.(*http.Transport)
  50. // SetOldTransportDefaults applies the defaults from http.DefaultTransport
  51. // for the Proxy, Dial, and TLSHandshakeTimeout fields if unset
  52. func SetOldTransportDefaults(t *http.Transport) *http.Transport {
  53. if t.Proxy == nil || isDefault(t.Proxy) {
  54. // http.ProxyFromEnvironment doesn't respect CIDRs and that makes it impossible to exclude things like pod and service IPs from proxy settings
  55. // ProxierWithNoProxyCIDR allows CIDR rules in NO_PROXY
  56. t.Proxy = NewProxierWithNoProxyCIDR(http.ProxyFromEnvironment)
  57. }
  58. if t.Dial == nil {
  59. t.Dial = defaultTransport.Dial
  60. }
  61. if t.TLSHandshakeTimeout == 0 {
  62. t.TLSHandshakeTimeout = defaultTransport.TLSHandshakeTimeout
  63. }
  64. return t
  65. }
  66. // SetTransportDefaults applies the defaults from http.DefaultTransport
  67. // for the Proxy, Dial, and TLSHandshakeTimeout fields if unset
  68. func SetTransportDefaults(t *http.Transport) *http.Transport {
  69. t = SetOldTransportDefaults(t)
  70. // Allow HTTP2 clients but default off for now
  71. if s := os.Getenv("ENABLE_HTTP2"); len(s) > 0 {
  72. if err := http2.ConfigureTransport(t); err != nil {
  73. glog.Warningf("Transport failed http2 configuration: %v", err)
  74. }
  75. }
  76. return t
  77. }
  78. type RoundTripperWrapper interface {
  79. http.RoundTripper
  80. WrappedRoundTripper() http.RoundTripper
  81. }
  82. type DialFunc func(net, addr string) (net.Conn, error)
  83. func Dialer(transport http.RoundTripper) (DialFunc, error) {
  84. if transport == nil {
  85. return nil, nil
  86. }
  87. switch transport := transport.(type) {
  88. case *http.Transport:
  89. return transport.Dial, nil
  90. case RoundTripperWrapper:
  91. return Dialer(transport.WrappedRoundTripper())
  92. default:
  93. return nil, fmt.Errorf("unknown transport type: %v", transport)
  94. }
  95. }
  96. func TLSClientConfig(transport http.RoundTripper) (*tls.Config, error) {
  97. if transport == nil {
  98. return nil, nil
  99. }
  100. switch transport := transport.(type) {
  101. case *http.Transport:
  102. return transport.TLSClientConfig, nil
  103. case RoundTripperWrapper:
  104. return TLSClientConfig(transport.WrappedRoundTripper())
  105. default:
  106. return nil, fmt.Errorf("unknown transport type: %v", transport)
  107. }
  108. }
  109. func FormatURL(scheme string, host string, port int, path string) *url.URL {
  110. return &url.URL{
  111. Scheme: scheme,
  112. Host: net.JoinHostPort(host, strconv.Itoa(port)),
  113. Path: path,
  114. }
  115. }
  116. func GetHTTPClient(req *http.Request) string {
  117. if userAgent, ok := req.Header["User-Agent"]; ok {
  118. if len(userAgent) > 0 {
  119. return userAgent[0]
  120. }
  121. }
  122. return "unknown"
  123. }
  124. // Extracts and returns the clients IP from the given request.
  125. // Looks at X-Forwarded-For header, X-Real-Ip header and request.RemoteAddr in that order.
  126. // Returns nil if none of them are set or is set to an invalid value.
  127. func GetClientIP(req *http.Request) net.IP {
  128. hdr := req.Header
  129. // First check the X-Forwarded-For header for requests via proxy.
  130. hdrForwardedFor := hdr.Get("X-Forwarded-For")
  131. if hdrForwardedFor != "" {
  132. // X-Forwarded-For can be a csv of IPs in case of multiple proxies.
  133. // Use the first valid one.
  134. parts := strings.Split(hdrForwardedFor, ",")
  135. for _, part := range parts {
  136. ip := net.ParseIP(strings.TrimSpace(part))
  137. if ip != nil {
  138. return ip
  139. }
  140. }
  141. }
  142. // Try the X-Real-Ip header.
  143. hdrRealIp := hdr.Get("X-Real-Ip")
  144. if hdrRealIp != "" {
  145. ip := net.ParseIP(hdrRealIp)
  146. if ip != nil {
  147. return ip
  148. }
  149. }
  150. // Fallback to Remote Address in request, which will give the correct client IP when there is no proxy.
  151. // Remote Address in Go's HTTP server is in the form host:port so we need to split that first.
  152. host, _, err := net.SplitHostPort(req.RemoteAddr)
  153. if err == nil {
  154. return net.ParseIP(host)
  155. }
  156. // Fallback if Remote Address was just IP.
  157. return net.ParseIP(req.RemoteAddr)
  158. }
  159. var defaultProxyFuncPointer = fmt.Sprintf("%p", http.ProxyFromEnvironment)
  160. // isDefault checks to see if the transportProxierFunc is pointing to the default one
  161. func isDefault(transportProxier func(*http.Request) (*url.URL, error)) bool {
  162. transportProxierPointer := fmt.Sprintf("%p", transportProxier)
  163. return transportProxierPointer == defaultProxyFuncPointer
  164. }
  165. // NewProxierWithNoProxyCIDR constructs a Proxier function that respects CIDRs in NO_PROXY and delegates if
  166. // no matching CIDRs are found
  167. func NewProxierWithNoProxyCIDR(delegate func(req *http.Request) (*url.URL, error)) func(req *http.Request) (*url.URL, error) {
  168. // we wrap the default method, so we only need to perform our check if the NO_PROXY envvar has a CIDR in it
  169. noProxyEnv := os.Getenv("NO_PROXY")
  170. noProxyRules := strings.Split(noProxyEnv, ",")
  171. cidrs := []*net.IPNet{}
  172. for _, noProxyRule := range noProxyRules {
  173. _, cidr, _ := net.ParseCIDR(noProxyRule)
  174. if cidr != nil {
  175. cidrs = append(cidrs, cidr)
  176. }
  177. }
  178. if len(cidrs) == 0 {
  179. return delegate
  180. }
  181. return func(req *http.Request) (*url.URL, error) {
  182. host := req.URL.Host
  183. // for some urls, the Host is already the host, not the host:port
  184. if net.ParseIP(host) == nil {
  185. var err error
  186. host, _, err = net.SplitHostPort(req.URL.Host)
  187. if err != nil {
  188. return delegate(req)
  189. }
  190. }
  191. ip := net.ParseIP(host)
  192. if ip == nil {
  193. return delegate(req)
  194. }
  195. for _, cidr := range cidrs {
  196. if cidr.Contains(ip) {
  197. return nil, nil
  198. }
  199. }
  200. return delegate(req)
  201. }
  202. }