| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 | package httpimport (	"bytes"	"errors"	"strings"	"v2ray.com/core")type version byteconst (	HTTP1 version = iota	HTTP2)type SniffHeader struct {	version version	host    string}func (h *SniffHeader) Protocol() string {	switch h.version {	case HTTP1:		return "http1"	case HTTP2:		return "http2"	default:		return "unknown"	}}func (h *SniffHeader) Domain() string {	return h.host}var (	methods = [...]string{"get", "post", "head", "put", "delete", "options", "connect"}	errNotHTTPMethod = errors.New("not an HTTP method"))func beginWithHTTPMethod(b []byte) error {	for _, m := range &methods {		if len(b) >= len(m) && strings.ToLower(string(b[:len(m)])) == m {			return nil		}		if len(b) < len(m) {			return core.ErrNoClue		}	}	return errNotHTTPMethod}func SniffHTTP(b []byte) (*SniffHeader, error) {	if err := beginWithHTTPMethod(b); err != nil {		return nil, err	}	sh := &SniffHeader{		version: HTTP1,	}	headers := bytes.Split(b, []byte{'\n'})	for i := 1; i < len(headers); i++ {		header := headers[i]		if len(header) == 0 {			break		}		parts := bytes.SplitN(header, []byte{':'}, 2)		if len(parts) != 2 {			continue		}		key := strings.ToLower(string(parts[0]))		value := strings.ToLower(string(bytes.Trim(parts[1], " ")))		if key == "host" {			domain := strings.Split(value, ":")			sh.host = strings.TrimSpace(domain[0])		}	}	if len(sh.host) > 0 {		return sh, nil	}	return nil, core.ErrNoClue}
 |