Improve: using native http request
This commit is contained in:
62
proxy/http/http.go
Normal file
62
proxy/http/http.go
Normal file
@ -0,0 +1,62 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
)
|
||||
|
||||
type HttpAdapter struct {
|
||||
addr *C.Addr
|
||||
r *http.Request
|
||||
w http.ResponseWriter
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func (h *HttpAdapter) Close() {
|
||||
h.done <- struct{}{}
|
||||
}
|
||||
|
||||
func (h *HttpAdapter) Addr() *C.Addr {
|
||||
return h.addr
|
||||
}
|
||||
|
||||
func (h *HttpAdapter) Connect(proxy C.ProxyAdapter) {
|
||||
req := http.Transport{
|
||||
Dial: func(string, string) (net.Conn, error) {
|
||||
return proxy.Conn(), nil
|
||||
},
|
||||
// from http.DefaultTransport
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
}
|
||||
resp, err := req.RoundTrip(h.r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
header := h.w.Header()
|
||||
for k, vv := range resp.Header {
|
||||
for _, v := range vv {
|
||||
header.Add(k, v)
|
||||
}
|
||||
}
|
||||
h.w.WriteHeader(resp.StatusCode)
|
||||
io.Copy(h.w, resp.Body)
|
||||
}
|
||||
|
||||
func NewHttp(host string, w http.ResponseWriter, r *http.Request) (*HttpAdapter, chan struct{}) {
|
||||
done := make(chan struct{})
|
||||
return &HttpAdapter{
|
||||
addr: parseHttpAddr(host),
|
||||
r: r,
|
||||
w: w,
|
||||
done: done,
|
||||
}, done
|
||||
}
|
35
proxy/http/https.go
Normal file
35
proxy/http/https.go
Normal file
@ -0,0 +1,35 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
)
|
||||
|
||||
type HttpsAdapter struct {
|
||||
addr *C.Addr
|
||||
conn net.Conn
|
||||
rw *bufio.ReadWriter
|
||||
}
|
||||
|
||||
func (h *HttpsAdapter) Close() {
|
||||
h.conn.Close()
|
||||
}
|
||||
|
||||
func (h *HttpsAdapter) Addr() *C.Addr {
|
||||
return h.addr
|
||||
}
|
||||
|
||||
func (h *HttpsAdapter) Connect(proxy C.ProxyAdapter) {
|
||||
go io.Copy(h.conn, proxy.ReadWriter())
|
||||
io.Copy(proxy.ReadWriter(), h.conn)
|
||||
}
|
||||
|
||||
func NewHttps(host string, conn net.Conn) *HttpsAdapter {
|
||||
return &HttpsAdapter{
|
||||
addr: parseHttpAddr(host),
|
||||
conn: conn,
|
||||
}
|
||||
}
|
@ -1,21 +1,22 @@
|
||||
package proxy
|
||||
package http
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"strings"
|
||||
|
||||
"github.com/Dreamacro/clash/constant"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/tunnel"
|
||||
|
||||
"github.com/riobard/go-shadowsocks2/socks"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
tun = tunnel.GetInstance()
|
||||
)
|
||||
|
||||
func NewHttpProxy(port string) {
|
||||
server := &http.Server{
|
||||
Addr: fmt.Sprintf(":%s", port),
|
||||
@ -32,21 +33,14 @@ func NewHttpProxy(port string) {
|
||||
}
|
||||
|
||||
func handleHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
buf, _ := httputil.DumpRequestOut(r, true)
|
||||
hijacker, ok := w.(http.Hijacker)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
conn, rw, err := hijacker.Hijack()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
addr := r.Host
|
||||
// padding default port
|
||||
if !strings.Contains(addr, ":") {
|
||||
addr += ":80"
|
||||
}
|
||||
tun.Add(NewHttp(addr, conn, rw, buf))
|
||||
req, done := NewHttp(addr, w, r)
|
||||
tun.Add(req)
|
||||
<-done
|
||||
}
|
||||
|
||||
func handleTunneling(w http.ResponseWriter, r *http.Request) {
|
||||
@ -54,38 +48,16 @@ func handleTunneling(w http.ResponseWriter, r *http.Request) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
conn, rw, err := hijacker.Hijack()
|
||||
conn, _, err := hijacker.Hijack()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// w.WriteHeader(http.StatusOK) doesn't works in Safari
|
||||
conn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
|
||||
tun.Add(NewHttp(r.Host, conn, rw, []byte{}))
|
||||
tun.Add(NewHttps(r.Host, conn))
|
||||
}
|
||||
|
||||
type HttpAdapter struct {
|
||||
addr *constant.Addr
|
||||
conn net.Conn
|
||||
r io.Reader
|
||||
}
|
||||
|
||||
func (h *HttpAdapter) Writer() io.Writer {
|
||||
return h.conn
|
||||
}
|
||||
|
||||
func (h *HttpAdapter) Reader() io.Reader {
|
||||
return h.r
|
||||
}
|
||||
|
||||
func (h *HttpAdapter) Close() {
|
||||
h.conn.Close()
|
||||
}
|
||||
|
||||
func (h *HttpAdapter) Addr() *constant.Addr {
|
||||
return h.addr
|
||||
}
|
||||
|
||||
func parseHttpAddr(target string) *constant.Addr {
|
||||
func parseHttpAddr(target string) *C.Addr {
|
||||
host, port, _ := net.SplitHostPort(target)
|
||||
ipAddr, _ := net.ResolveIPAddr("ip", host)
|
||||
var addType int
|
||||
@ -99,19 +71,11 @@ func parseHttpAddr(target string) *constant.Addr {
|
||||
addType = socks.AtypIPv4
|
||||
}
|
||||
|
||||
return &constant.Addr{
|
||||
return &C.Addr{
|
||||
NetWork: C.TCP,
|
||||
AddrType: addType,
|
||||
Host: host,
|
||||
IP: &ipAddr.IP,
|
||||
Port: port,
|
||||
}
|
||||
}
|
||||
|
||||
func NewHttp(host string, conn net.Conn, rw *bufio.ReadWriter, payload []byte) *HttpAdapter {
|
||||
r := io.MultiReader(bytes.NewReader(payload), rw)
|
||||
return &HttpAdapter{
|
||||
conn: conn,
|
||||
addr: parseHttpAddr(host),
|
||||
r: r,
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package proxy
|
||||
package socks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -6,7 +6,7 @@ import (
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/Dreamacro/clash/constant"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/tunnel"
|
||||
|
||||
"github.com/riobard/go-shadowsocks2/socks"
|
||||
@ -45,26 +45,23 @@ func handleSocks(conn net.Conn) {
|
||||
|
||||
type SocksAdapter struct {
|
||||
conn net.Conn
|
||||
addr *constant.Addr
|
||||
}
|
||||
|
||||
func (s *SocksAdapter) Writer() io.Writer {
|
||||
return s.conn
|
||||
}
|
||||
|
||||
func (s *SocksAdapter) Reader() io.Reader {
|
||||
return s.conn
|
||||
addr *C.Addr
|
||||
}
|
||||
|
||||
func (s *SocksAdapter) Close() {
|
||||
s.conn.Close()
|
||||
}
|
||||
|
||||
func (s *SocksAdapter) Addr() *constant.Addr {
|
||||
func (s *SocksAdapter) Addr() *C.Addr {
|
||||
return s.addr
|
||||
}
|
||||
|
||||
func parseSocksAddr(target socks.Addr) *constant.Addr {
|
||||
func (s *SocksAdapter) Connect(proxy C.ProxyAdapter) {
|
||||
go io.Copy(s.conn, proxy.ReadWriter())
|
||||
io.Copy(proxy.ReadWriter(), s.conn)
|
||||
}
|
||||
|
||||
func parseSocksAddr(target socks.Addr) *C.Addr {
|
||||
var host, port string
|
||||
var ip net.IP
|
||||
|
||||
@ -84,7 +81,8 @@ func parseSocksAddr(target socks.Addr) *constant.Addr {
|
||||
port = strconv.Itoa((int(target[1+net.IPv6len]) << 8) | int(target[1+net.IPv6len+1]))
|
||||
}
|
||||
|
||||
return &constant.Addr{
|
||||
return &C.Addr{
|
||||
NetWork: C.TCP,
|
||||
AddrType: int(target[0]),
|
||||
Host: host,
|
||||
IP: &ip,
|
1
proxy/socks/udp.go
Normal file
1
proxy/socks/udp.go
Normal file
@ -0,0 +1 @@
|
||||
package socks
|
Reference in New Issue
Block a user