From ebe1cee6dc3f062fc2703eacb08a4d74a1ad4e46 Mon Sep 17 00:00:00 2001 From: Dreamacro <305009791@qq.com> Date: Sun, 12 Aug 2018 16:18:58 +0800 Subject: [PATCH] Improve: clean code --- adapters/local/http.go | 92 ++++++----------------------------------- adapters/local/socks.go | 5 +++ adapters/local/util.go | 76 +++++++++++++++++++++++++++++++++- config/config.go | 1 + proxy/http/server.go | 2 +- tunnel/connection.go | 2 +- tunnel/tunnel.go | 2 +- 7 files changed, 97 insertions(+), 83 deletions(-) diff --git a/adapters/local/http.go b/adapters/local/http.go index 574f02bc..e9d3f622 100644 --- a/adapters/local/http.go +++ b/adapters/local/http.go @@ -5,12 +5,12 @@ import ( "bytes" "io" "net" - "net/http" "strings" C "github.com/Dreamacro/clash/constant" ) +// PeekedConn handle http connection and buffed HTTP data type PeekedConn struct { net.Conn Peeked []byte @@ -47,26 +47,31 @@ func (c *PeekedConn) Read(p []byte) (n int, err error) { return c.Conn.Read(p) } -type HttpAdapter struct { +// HTTPAdapter is a adapter for HTTP connection +type HTTPAdapter struct { addr *C.Addr conn *PeekedConn } -func (h *HttpAdapter) Close() { +// Close HTTP connection +func (h *HTTPAdapter) Close() { h.conn.Close() } -func (h *HttpAdapter) Addr() *C.Addr { +// Addr return destination address +func (h *HTTPAdapter) Addr() *C.Addr { return h.addr } -func (h *HttpAdapter) Conn() net.Conn { +// Conn return raw net.Conn of HTTP +func (h *HTTPAdapter) Conn() net.Conn { return h.conn } -func NewHttp(host string, peeked []byte, isHTTP bool, conn net.Conn) *HttpAdapter { - return &HttpAdapter{ - addr: parseHttpAddr(host), +// NewHTTP is HTTPAdapter generator +func NewHTTP(host string, peeked []byte, isHTTP bool, conn net.Conn) *HTTPAdapter { + return &HTTPAdapter{ + addr: parseHTTPAddr(host), conn: &PeekedConn{ Peeked: peeked, Conn: conn, @@ -75,74 +80,3 @@ func NewHttp(host string, peeked []byte, isHTTP bool, conn net.Conn) *HttpAdapte }, } } - -// ParserHTTPHostHeader returns the HTTP Host header from br without -// consuming any of its bytes. It returns "" if it can't find one. -func ParserHTTPHostHeader(br *bufio.Reader) (method, host string) { - // br := bufio.NewReader(bytes.NewReader(data)) - const maxPeek = 4 << 10 - peekSize := 0 - for { - peekSize++ - if peekSize > maxPeek { - b, _ := br.Peek(br.Buffered()) - return method, httpHostHeaderFromBytes(b) - } - b, err := br.Peek(peekSize) - if n := br.Buffered(); n > peekSize { - b, _ = br.Peek(n) - peekSize = n - } - if len(b) > 0 { - if b[0] < 'A' || b[0] > 'Z' { - // Doesn't look like an HTTP verb - // (GET, POST, etc). - return - } - if bytes.Index(b, crlfcrlf) != -1 || bytes.Index(b, lflf) != -1 { - req, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(b))) - if err != nil { - return - } - if len(req.Header["Host"]) > 1 { - // TODO(bradfitz): what does - // ReadRequest do if there are - // multiple Host headers? - return - } - return req.Method, req.Host - } - } - if err != nil { - return method, httpHostHeaderFromBytes(b) - } - } -} - -var ( - lfHostColon = []byte("\nHost:") - lfhostColon = []byte("\nhost:") - crlf = []byte("\r\n") - lf = []byte("\n") - crlfcrlf = []byte("\r\n\r\n") - lflf = []byte("\n\n") -) - -func httpHostHeaderFromBytes(b []byte) string { - if i := bytes.Index(b, lfHostColon); i != -1 { - return string(bytes.TrimSpace(untilEOL(b[i+len(lfHostColon):]))) - } - if i := bytes.Index(b, lfhostColon); i != -1 { - return string(bytes.TrimSpace(untilEOL(b[i+len(lfhostColon):]))) - } - return "" -} - -// untilEOL returns v, truncated before the first '\n' byte, if any. -// The returned slice may include a '\r' at the end. -func untilEOL(v []byte) []byte { - if i := bytes.IndexByte(v, '\n'); i != -1 { - return v[:i] - } - return v -} diff --git a/adapters/local/socks.go b/adapters/local/socks.go index dd1c4623..2f31cdc5 100644 --- a/adapters/local/socks.go +++ b/adapters/local/socks.go @@ -7,23 +7,28 @@ import ( "github.com/riobard/go-shadowsocks2/socks" ) +// SocksAdapter is a adapter for socks and redir connection type SocksAdapter struct { conn net.Conn addr *C.Addr } +// Close socks and redir connection func (s *SocksAdapter) Close() { s.conn.Close() } +// Addr return destination address func (s *SocksAdapter) Addr() *C.Addr { return s.addr } +// Conn return raw net.Conn func (s *SocksAdapter) Conn() net.Conn { return s.conn } +// NewSocks is SocksAdapter generator func NewSocks(target socks.Addr, conn net.Conn) *SocksAdapter { return &SocksAdapter{ conn: conn, diff --git a/adapters/local/util.go b/adapters/local/util.go index 0fb20430..90e9c472 100644 --- a/adapters/local/util.go +++ b/adapters/local/util.go @@ -1,7 +1,10 @@ package adapters import ( + "bufio" + "bytes" "net" + "net/http" "strconv" C "github.com/Dreamacro/clash/constant" @@ -37,7 +40,7 @@ func parseSocksAddr(target socks.Addr) *C.Addr { } } -func parseHttpAddr(target string) *C.Addr { +func parseHTTPAddr(target string) *C.Addr { host, port, _ := net.SplitHostPort(target) ipAddr, err := net.ResolveIPAddr("ip", host) var resolveIP *net.IP @@ -64,3 +67,74 @@ func parseHttpAddr(target string) *C.Addr { Port: port, } } + +// ParserHTTPHostHeader returns the HTTP Host header from br without +// consuming any of its bytes. It returns "" if it can't find one. +func ParserHTTPHostHeader(br *bufio.Reader) (method, host string) { + // br := bufio.NewReader(bytes.NewReader(data)) + const maxPeek = 4 << 10 + peekSize := 0 + for { + peekSize++ + if peekSize > maxPeek { + b, _ := br.Peek(br.Buffered()) + return method, httpHostHeaderFromBytes(b) + } + b, err := br.Peek(peekSize) + if n := br.Buffered(); n > peekSize { + b, _ = br.Peek(n) + peekSize = n + } + if len(b) > 0 { + if b[0] < 'A' || b[0] > 'Z' { + // Doesn't look like an HTTP verb + // (GET, POST, etc). + return + } + if bytes.Index(b, crlfcrlf) != -1 || bytes.Index(b, lflf) != -1 { + req, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(b))) + if err != nil { + return + } + if len(req.Header["Host"]) > 1 { + // TODO(bradfitz): what does + // ReadRequest do if there are + // multiple Host headers? + return + } + return req.Method, req.Host + } + } + if err != nil { + return method, httpHostHeaderFromBytes(b) + } + } +} + +var ( + lfHostColon = []byte("\nHost:") + lfhostColon = []byte("\nhost:") + crlf = []byte("\r\n") + lf = []byte("\n") + crlfcrlf = []byte("\r\n\r\n") + lflf = []byte("\n\n") +) + +func httpHostHeaderFromBytes(b []byte) string { + if i := bytes.Index(b, lfHostColon); i != -1 { + return string(bytes.TrimSpace(untilEOL(b[i+len(lfHostColon):]))) + } + if i := bytes.Index(b, lfhostColon); i != -1 { + return string(bytes.TrimSpace(untilEOL(b[i+len(lfhostColon):]))) + } + return "" +} + +// untilEOL returns v, truncated before the first '\n' byte, if any. +// The returned slice may include a '\r' at the end. +func untilEOL(v []byte) []byte { + if i := bytes.IndexByte(v, '\n'); i != -1 { + return v[:i] + } + return v +} diff --git a/config/config.go b/config/config.go index d77acc61..94e1a872 100644 --- a/config/config.go +++ b/config/config.go @@ -364,6 +364,7 @@ func newConfig() *Config { return config } +// Instance return singleton instance of Config func Instance() *Config { once.Do(func() { config = newConfig() diff --git a/proxy/http/server.go b/proxy/http/server.go index d015a085..5dae3960 100644 --- a/proxy/http/server.go +++ b/proxy/http/server.go @@ -75,5 +75,5 @@ func handleConn(conn net.Conn) { peeked, _ = br.Peek(br.Buffered()) } - tun.Add(adapters.NewHttp(hostName, peeked, method != http.MethodConnect, conn)) + tun.Add(adapters.NewHTTP(hostName, peeked, method != http.MethodConnect, conn)) } diff --git a/tunnel/connection.go b/tunnel/connection.go index 6fb27f18..ea3d42fd 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -7,7 +7,7 @@ import ( C "github.com/Dreamacro/clash/constant" ) -func (t *Tunnel) handleHTTP(request *adapters.HttpAdapter, proxy C.ProxyAdapter) { +func (t *Tunnel) handleHTTP(request *adapters.HTTPAdapter, proxy C.ProxyAdapter) { conn := newTrafficTrack(proxy.Conn(), t.traffic) // Before we unwrap src and/or dst, copy any buffered data. diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index f83d71bb..8d3e5773 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -104,7 +104,7 @@ func (t *Tunnel) handleConn(localConn C.ServerAdapter) { defer remoConn.Close() switch adapter := localConn.(type) { - case *LocalAdapter.HttpAdapter: + case *LocalAdapter.HTTPAdapter: t.handleHTTP(adapter, remoConn) case *LocalAdapter.SocksAdapter: t.handleSOCKS(adapter, remoConn)