github.com/metacubex/mihomo@v1.18.5/listener/http/utils.go (about)

     1  package http
     2  
     3  import (
     4  	"encoding/base64"
     5  	"errors"
     6  	"net"
     7  	"net/http"
     8  	"net/netip"
     9  	"strings"
    10  )
    11  
    12  // removeHopByHopHeaders remove Proxy-* headers
    13  func removeProxyHeaders(header http.Header) {
    14  	header.Del("Proxy-Connection")
    15  	header.Del("Proxy-Authenticate")
    16  	header.Del("Proxy-Authorization")
    17  }
    18  
    19  // removeHopByHopHeaders remove hop-by-hop header
    20  func removeHopByHopHeaders(header http.Header) {
    21  	// Strip hop-by-hop header based on RFC:
    22  	// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
    23  	// https://www.mnot.net/blog/2011/07/11/what_proxies_must_do
    24  
    25  	removeProxyHeaders(header)
    26  
    27  	header.Del("TE")
    28  	header.Del("Trailers")
    29  	header.Del("Transfer-Encoding")
    30  	header.Del("Upgrade")
    31  
    32  	connections := header.Get("Connection")
    33  	header.Del("Connection")
    34  	if len(connections) == 0 {
    35  		return
    36  	}
    37  	for _, h := range strings.Split(connections, ",") {
    38  		header.Del(strings.TrimSpace(h))
    39  	}
    40  }
    41  
    42  // removeExtraHTTPHostPort remove extra host port (example.com:80 --> example.com)
    43  // It resolves the behavior of some HTTP servers that do not handle host:80 (e.g. baidu.com)
    44  func removeExtraHTTPHostPort(req *http.Request) {
    45  	host := req.Host
    46  	if host == "" {
    47  		host = req.URL.Host
    48  	}
    49  
    50  	if pHost, port, err := net.SplitHostPort(host); err == nil && (port == "80" || port == "443") {
    51  		host = pHost
    52  		if ip, err := netip.ParseAddr(pHost); err == nil && ip.Is6() {
    53  			// RFC 2617 Sec 3.2.2, for IPv6 literal
    54  			// addresses the Host header needs to follow the RFC 2732 grammar for "host"
    55  			host = "[" + host + "]"
    56  		}
    57  	}
    58  
    59  	req.Host = host
    60  	req.URL.Host = host
    61  }
    62  
    63  // parseBasicProxyAuthorization parse header Proxy-Authorization and return base64-encoded credential
    64  func parseBasicProxyAuthorization(request *http.Request) string {
    65  	value := request.Header.Get("Proxy-Authorization")
    66  	if !strings.HasPrefix(value, "Basic ") {
    67  		return ""
    68  	}
    69  
    70  	return value[6:] // value[len("Basic "):]
    71  }
    72  
    73  // decodeBasicProxyAuthorization decode base64-encoded credential
    74  func decodeBasicProxyAuthorization(credential string) (string, string, error) {
    75  	plain, err := base64.StdEncoding.DecodeString(credential)
    76  	if err != nil {
    77  		return "", "", err
    78  	}
    79  
    80  	user, pass, found := strings.Cut(string(plain), ":")
    81  	if !found {
    82  		return "", "", errors.New("invalid login")
    83  	}
    84  
    85  	return user, pass, nil
    86  }