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  }