github.com/searKing/golang/go@v1.2.117/net/http/transport.host.go (about) 1 // Copyright 2023 The searKing Author. 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 http 6 7 import ( 8 "fmt" 9 "net/http" 10 11 "github.com/searKing/golang/go/net/http/httphost" 12 "github.com/searKing/golang/go/net/http/httpproxy" 13 "github.com/searKing/golang/go/net/resolver" 14 time_ "github.com/searKing/golang/go/time" 15 ) 16 17 // RequestWithHostTarget replace Host in url.Url by resolver.Host 18 // replace Host in req if replaceHostInRequest is true 19 func RequestWithHostTarget(req *http.Request, target *httphost.Host) *http.Request { 20 if target == nil { 21 return req 22 } 23 return req.WithContext(httphost.WithHost(req.Context(), target)) 24 } 25 26 // HostFuncFromContext builds a host function from the given string, which should 27 // represent a Target that can be used as a host. It performs basic 28 // sanitization of the Target retrieved in context of Request, and returns any error encountered. 29 func HostFuncFromContext(req *http.Request) error { 30 host := httphost.ContextHost(req.Context()) 31 // load host from environment if host not set 32 if host == nil || host.HostTarget == "" { 33 return nil 34 } 35 if req.URL == nil { 36 return nil 37 } 38 39 if host.HostTarget == "" { 40 return nil 41 } 42 43 // replace host of host if target of host if resolved 44 address, err := resolver.ResolveOneAddr(req.Context(), host.HostTarget) 45 if err != nil { 46 return err 47 } 48 if address.Addr != "" { 49 req.URL.Host = address.Addr 50 } 51 host.HostTargetAddrResolved = address 52 if host.ReplaceHostInRequest { 53 req.Host = req.URL.Host 54 } 55 return nil 56 } 57 58 // DefaultTransportWithDynamicHost is the default implementation of Transport and is 59 // used by DefaultClientWithDynamicHost. It establishes network connections as needed 60 // and caches them for reuse by subsequent calls. 61 var DefaultTransportWithDynamicHost = RoundTripperWithTarget(http.DefaultTransport) 62 63 // DefaultClientWithDynamicHost is the default Client with DefaultTransportWithDynamicHost. 64 var DefaultClientWithDynamicHost = &http.Client{ 65 Transport: DefaultTransportWithDynamicHost, 66 } 67 68 // RoundTripperWithTarget wraps http.RoundTripper with request url replaced by Target resolved by resolver. 69 // Target is as like gRPC Naming for service discovery. 70 func RoundTripperWithTarget(rt http.RoundTripper) http.RoundTripper { 71 return RoundTripFunc(func(req *http.Request) (resp *http.Response, err error) { 72 err = HostFuncFromContext(req) 73 if err != nil { 74 return nil, err 75 } 76 var cost time_.Cost 77 cost.Start() 78 defer func() { 79 if host := httphost.ContextHost(req.Context()); host != nil { 80 _ = resolver.ResolveDone(req.Context(), host.HostTarget, resolver.DoneInfo{ 81 Err: err, 82 Addr: host.HostTargetAddrResolved, 83 Duration: cost.Elapse(), 84 }) 85 if err != nil && host.HostTargetAddrResolved.Addr != "" { 86 var s string 87 if host.HostTarget != "" { 88 s = fmt.Sprintf(" in target(%s)", host.HostTarget) 89 } 90 err = fmt.Errorf("->http_host(%s)%s: %w", host.HostTargetAddrResolved.Addr, s, err) 91 } 92 } 93 94 if proxy := httpproxy.ContextProxy(req.Context()); proxy != nil { 95 _ = resolver.ResolveDone(req.Context(), proxy.ProxyTarget, resolver.DoneInfo{ 96 Err: err, 97 Addr: proxy.ProxyAddrResolved, 98 Duration: cost.Elapse(), 99 }) 100 if err != nil && proxy.ProxyAddrResolved.Addr != "" { 101 var s string 102 if proxy.ProxyTarget != "" { 103 s = fmt.Sprintf(" in target(%s)", proxy.ProxyTarget) 104 } 105 err = fmt.Errorf("->http_proxy(%s)%s: %w", proxy.ProxyAddrResolved.Addr, s, err) 106 } 107 } 108 }() 109 return rt.RoundTrip(req) 110 }) 111 } 112 113 // DefaultTransportWithDynamicHostAndProxy is the default implementation of Transport and is 114 // used by DefaultClientWithDynamicHostAndProxy. It establishes network connections as needed 115 // and caches them for reuse by subsequent calls. 116 var DefaultTransportWithDynamicHostAndProxy = RoundTripperWithTarget(DefaultTransportWithDynamicProxy) 117 118 // DefaultClientWithDynamicHostAndProxy is the default Client with DefaultTransportWithDynamicHostAndProxy. 119 var DefaultClientWithDynamicHostAndProxy = &http.Client{ 120 Transport: DefaultTransportWithDynamicHostAndProxy, 121 }