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