http.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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. "bufio"
  16. "bytes"
  17. "context"
  18. "crypto/tls"
  19. "fmt"
  20. "io"
  21. "net"
  22. "net/http"
  23. "net/url"
  24. "os"
  25. "path"
  26. "strconv"
  27. "strings"
  28. "github.com/golang/glog"
  29. "golang.org/x/net/http2"
  30. )
  31. // JoinPreservingTrailingSlash does a path.Join of the specified elements,
  32. // preserving any trailing slash on the last non-empty segment
  33. func JoinPreservingTrailingSlash(elem ...string) string {
  34. // do the basic path join
  35. result := path.Join(elem...)
  36. // find the last non-empty segment
  37. for i := len(elem) - 1; i >= 0; i-- {
  38. if len(elem[i]) > 0 {
  39. // if the last segment ended in a slash, ensure our result does as well
  40. if strings.HasSuffix(elem[i], "/") && !strings.HasSuffix(result, "/") {
  41. result += "/"
  42. }
  43. break
  44. }
  45. }
  46. return result
  47. }
  48. // IsProbableEOF returns true if the given error resembles a connection termination
  49. // scenario that would justify assuming that the watch is empty.
  50. // These errors are what the Go http stack returns back to us which are general
  51. // connection closure errors (strongly correlated) and callers that need to
  52. // differentiate probable errors in connection behavior between normal "this is
  53. // disconnected" should use the method.
  54. func IsProbableEOF(err error) bool {
  55. if err == nil {
  56. return false
  57. }
  58. if uerr, ok := err.(*url.Error); ok {
  59. err = uerr.Err
  60. }
  61. switch {
  62. case err == io.EOF:
  63. return true
  64. case err.Error() == "http: can't write HTTP request on broken connection":
  65. return true
  66. case strings.Contains(err.Error(), "connection reset by peer"):
  67. return true
  68. case strings.Contains(strings.ToLower(err.Error()), "use of closed network connection"):
  69. return true
  70. }
  71. return false
  72. }
  73. var defaultTransport = http.DefaultTransport.(*http.Transport)
  74. // SetOldTransportDefaults applies the defaults from http.DefaultTransport
  75. // for the Proxy, Dial, and TLSHandshakeTimeout fields if unset
  76. func SetOldTransportDefaults(t *http.Transport) *http.Transport {
  77. if t.Proxy == nil || isDefault(t.Proxy) {
  78. // http.ProxyFromEnvironment doesn't respect CIDRs and that makes it impossible to exclude things like pod and service IPs from proxy settings
  79. // ProxierWithNoProxyCIDR allows CIDR rules in NO_PROXY
  80. t.Proxy = NewProxierWithNoProxyCIDR(http.ProxyFromEnvironment)
  81. }
  82. if t.DialContext == nil {
  83. t.DialContext = defaultTransport.DialContext
  84. }
  85. if t.TLSHandshakeTimeout == 0 {
  86. t.TLSHandshakeTimeout = defaultTransport.TLSHandshakeTimeout
  87. }
  88. return t
  89. }
  90. // SetTransportDefaults applies the defaults from http.DefaultTransport
  91. // for the Proxy, Dial, and TLSHandshakeTimeout fields if unset
  92. func SetTransportDefaults(t *http.Transport) *http.Transport {
  93. t = SetOldTransportDefaults(t)
  94. // Allow clients to disable http2 if needed.
  95. if s := os.Getenv("DISABLE_HTTP2"); len(s) > 0 {
  96. glog.Infof("HTTP2 has been explicitly disabled")
  97. } else {
  98. if err := http2.ConfigureTransport(t); err != nil {
  99. glog.Warningf("Transport failed http2 configuration: %v", err)
  100. }
  101. }
  102. return t
  103. }
  104. type RoundTripperWrapper interface {
  105. http.RoundTripper
  106. WrappedRoundTripper() http.RoundTripper
  107. }
  108. type DialFunc func(ctx context.Context, net, addr string) (net.Conn, error)
  109. func DialerFor(transport http.RoundTripper) (DialFunc, error) {
  110. if transport == nil {
  111. return nil, nil
  112. }
  113. switch transport := transport.(type) {
  114. case *http.Transport:
  115. return transport.DialContext, nil
  116. case RoundTripperWrapper:
  117. return DialerFor(transport.WrappedRoundTripper())
  118. default:
  119. return nil, fmt.Errorf("unknown transport type: %T", transport)
  120. }
  121. }
  122. type TLSClientConfigHolder interface {
  123. TLSClientConfig() *tls.Config
  124. }
  125. func TLSClientConfig(transport http.RoundTripper) (*tls.Config, error) {
  126. if transport == nil {
  127. return nil, nil
  128. }
  129. switch transport := transport.(type) {
  130. case *http.Transport:
  131. return transport.TLSClientConfig, nil
  132. case TLSClientConfigHolder:
  133. return transport.TLSClientConfig(), nil
  134. case RoundTripperWrapper:
  135. return TLSClientConfig(transport.WrappedRoundTripper())
  136. default:
  137. return nil, fmt.Errorf("unknown transport type: %T", transport)
  138. }
  139. }
  140. func FormatURL(scheme string, host string, port int, path string) *url.URL {
  141. return &url.URL{
  142. Scheme: scheme,
  143. Host: net.JoinHostPort(host, strconv.Itoa(port)),
  144. Path: path,
  145. }
  146. }
  147. func GetHTTPClient(req *http.Request) string {
  148. if userAgent, ok := req.Header["User-Agent"]; ok {
  149. if len(userAgent) > 0 {
  150. return userAgent[0]
  151. }
  152. }
  153. return "unknown"
  154. }
  155. // SourceIPs splits the comma separated X-Forwarded-For header or returns the X-Real-Ip header or req.RemoteAddr,
  156. // in that order, ignoring invalid IPs. It returns nil if all of these are empty or invalid.
  157. func SourceIPs(req *http.Request) []net.IP {
  158. hdr := req.Header
  159. // First check the X-Forwarded-For header for requests via proxy.
  160. hdrForwardedFor := hdr.Get("X-Forwarded-For")
  161. forwardedForIPs := []net.IP{}
  162. if hdrForwardedFor != "" {
  163. // X-Forwarded-For can be a csv of IPs in case of multiple proxies.
  164. // Use the first valid one.
  165. parts := strings.Split(hdrForwardedFor, ",")
  166. for _, part := range parts {
  167. ip := net.ParseIP(strings.TrimSpace(part))
  168. if ip != nil {
  169. forwardedForIPs = append(forwardedForIPs, ip)
  170. }
  171. }
  172. }
  173. if len(forwardedForIPs) > 0 {
  174. return forwardedForIPs
  175. }
  176. // Try the X-Real-Ip header.
  177. hdrRealIp := hdr.Get("X-Real-Ip")
  178. if hdrRealIp != "" {
  179. ip := net.ParseIP(hdrRealIp)
  180. if ip != nil {
  181. return []net.IP{ip}
  182. }
  183. }
  184. // Fallback to Remote Address in request, which will give the correct client IP when there is no proxy.
  185. // Remote Address in Go's HTTP server is in the form host:port so we need to split that first.
  186. host, _, err := net.SplitHostPort(req.RemoteAddr)
  187. if err == nil {
  188. if remoteIP := net.ParseIP(host); remoteIP != nil {
  189. return []net.IP{remoteIP}
  190. }
  191. }
  192. // Fallback if Remote Address was just IP.
  193. if remoteIP := net.ParseIP(req.RemoteAddr); remoteIP != nil {
  194. return []net.IP{remoteIP}
  195. }
  196. return nil
  197. }
  198. // Extracts and returns the clients IP from the given request.
  199. // Looks at X-Forwarded-For header, X-Real-Ip header and request.RemoteAddr in that order.
  200. // Returns nil if none of them are set or is set to an invalid value.
  201. func GetClientIP(req *http.Request) net.IP {
  202. ips := SourceIPs(req)
  203. if len(ips) == 0 {
  204. return nil
  205. }
  206. return ips[0]
  207. }
  208. // Prepares the X-Forwarded-For header for another forwarding hop by appending the previous sender's
  209. // IP address to the X-Forwarded-For chain.
  210. func AppendForwardedForHeader(req *http.Request) {
  211. // Copied from net/http/httputil/reverseproxy.go:
  212. if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
  213. // If we aren't the first proxy retain prior
  214. // X-Forwarded-For information as a comma+space
  215. // separated list and fold multiple headers into one.
  216. if prior, ok := req.Header["X-Forwarded-For"]; ok {
  217. clientIP = strings.Join(prior, ", ") + ", " + clientIP
  218. }
  219. req.Header.Set("X-Forwarded-For", clientIP)
  220. }
  221. }
  222. var defaultProxyFuncPointer = fmt.Sprintf("%p", http.ProxyFromEnvironment)
  223. // isDefault checks to see if the transportProxierFunc is pointing to the default one
  224. func isDefault(transportProxier func(*http.Request) (*url.URL, error)) bool {
  225. transportProxierPointer := fmt.Sprintf("%p", transportProxier)
  226. return transportProxierPointer == defaultProxyFuncPointer
  227. }
  228. // NewProxierWithNoProxyCIDR constructs a Proxier function that respects CIDRs in NO_PROXY and delegates if
  229. // no matching CIDRs are found
  230. func NewProxierWithNoProxyCIDR(delegate func(req *http.Request) (*url.URL, error)) func(req *http.Request) (*url.URL, error) {
  231. // we wrap the default method, so we only need to perform our check if the NO_PROXY (or no_proxy) envvar has a CIDR in it
  232. noProxyEnv := os.Getenv("NO_PROXY")
  233. if noProxyEnv == "" {
  234. noProxyEnv = os.Getenv("no_proxy")
  235. }
  236. noProxyRules := strings.Split(noProxyEnv, ",")
  237. cidrs := []*net.IPNet{}
  238. for _, noProxyRule := range noProxyRules {
  239. _, cidr, _ := net.ParseCIDR(noProxyRule)
  240. if cidr != nil {
  241. cidrs = append(cidrs, cidr)
  242. }
  243. }
  244. if len(cidrs) == 0 {
  245. return delegate
  246. }
  247. return func(req *http.Request) (*url.URL, error) {
  248. ip := net.ParseIP(req.URL.Hostname())
  249. if ip == nil {
  250. return delegate(req)
  251. }
  252. for _, cidr := range cidrs {
  253. if cidr.Contains(ip) {
  254. return nil, nil
  255. }
  256. }
  257. return delegate(req)
  258. }
  259. }
  260. // DialerFunc implements Dialer for the provided function.
  261. type DialerFunc func(req *http.Request) (net.Conn, error)
  262. func (fn DialerFunc) Dial(req *http.Request) (net.Conn, error) {
  263. return fn(req)
  264. }
  265. // Dialer dials a host and writes a request to it.
  266. type Dialer interface {
  267. // Dial connects to the host specified by req's URL, writes the request to the connection, and
  268. // returns the opened net.Conn.
  269. Dial(req *http.Request) (net.Conn, error)
  270. }
  271. // ConnectWithRedirects uses dialer to send req, following up to 10 redirects (relative to
  272. // originalLocation). It returns the opened net.Conn and the raw response bytes.
  273. func ConnectWithRedirects(originalMethod string, originalLocation *url.URL, header http.Header, originalBody io.Reader, dialer Dialer) (net.Conn, []byte, error) {
  274. const (
  275. maxRedirects = 10
  276. maxResponseSize = 16384 // play it safe to allow the potential for lots of / large headers
  277. )
  278. var (
  279. location = originalLocation
  280. method = originalMethod
  281. intermediateConn net.Conn
  282. rawResponse = bytes.NewBuffer(make([]byte, 0, 256))
  283. body = originalBody
  284. )
  285. defer func() {
  286. if intermediateConn != nil {
  287. intermediateConn.Close()
  288. }
  289. }()
  290. redirectLoop:
  291. for redirects := 0; ; redirects++ {
  292. if redirects > maxRedirects {
  293. return nil, nil, fmt.Errorf("too many redirects (%d)", redirects)
  294. }
  295. req, err := http.NewRequest(method, location.String(), body)
  296. if err != nil {
  297. return nil, nil, err
  298. }
  299. req.Header = header
  300. intermediateConn, err = dialer.Dial(req)
  301. if err != nil {
  302. return nil, nil, err
  303. }
  304. // Peek at the backend response.
  305. rawResponse.Reset()
  306. respReader := bufio.NewReader(io.TeeReader(
  307. io.LimitReader(intermediateConn, maxResponseSize), // Don't read more than maxResponseSize bytes.
  308. rawResponse)) // Save the raw response.
  309. resp, err := http.ReadResponse(respReader, nil)
  310. if err != nil {
  311. // Unable to read the backend response; let the client handle it.
  312. glog.Warningf("Error reading backend response: %v", err)
  313. break redirectLoop
  314. }
  315. switch resp.StatusCode {
  316. case http.StatusFound:
  317. // Redirect, continue.
  318. default:
  319. // Don't redirect.
  320. break redirectLoop
  321. }
  322. // Redirected requests switch to "GET" according to the HTTP spec:
  323. // https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3
  324. method = "GET"
  325. // don't send a body when following redirects
  326. body = nil
  327. resp.Body.Close() // not used
  328. // Reset the connection.
  329. intermediateConn.Close()
  330. intermediateConn = nil
  331. // Prepare to follow the redirect.
  332. redirectStr := resp.Header.Get("Location")
  333. if redirectStr == "" {
  334. return nil, nil, fmt.Errorf("%d response missing Location header", resp.StatusCode)
  335. }
  336. // We have to parse relative to the current location, NOT originalLocation. For example,
  337. // if we request http://foo.com/a and get back "http://bar.com/b", the result should be
  338. // http://bar.com/b. If we then make that request and get back a redirect to "/c", the result
  339. // should be http://bar.com/c, not http://foo.com/c.
  340. location, err = location.Parse(redirectStr)
  341. if err != nil {
  342. return nil, nil, fmt.Errorf("malformed Location header: %v", err)
  343. }
  344. }
  345. connToReturn := intermediateConn
  346. intermediateConn = nil // Don't close the connection when we return it.
  347. return connToReturn, rawResponse.Bytes(), nil
  348. }
  349. // CloneRequest creates a shallow copy of the request along with a deep copy of the Headers.
  350. func CloneRequest(req *http.Request) *http.Request {
  351. r := new(http.Request)
  352. // shallow clone
  353. *r = *req
  354. // deep copy headers
  355. r.Header = CloneHeader(req.Header)
  356. return r
  357. }
  358. // CloneHeader creates a deep copy of an http.Header.
  359. func CloneHeader(in http.Header) http.Header {
  360. out := make(http.Header, len(in))
  361. for key, values := range in {
  362. newValues := make([]string, len(values))
  363. copy(newValues, values)
  364. out[key] = newValues
  365. }
  366. return out
  367. }