-
Notifications
You must be signed in to change notification settings - Fork 75
/
http_proxy.go
93 lines (84 loc) · 2.17 KB
/
http_proxy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package socks
import (
"fmt"
"io"
"net"
"net/http"
"net/http/httputil"
"net/url"
)
// HTTPProxy is an HTTP Handler that serve CONNECT method and
// route request to proxy server by Router.
type HTTPProxy struct {
*httputil.ReverseProxy
forward Dialer
}
// NewHTTPProxy constructs one HTTPProxy
func NewHTTPProxy(forward Dialer) *HTTPProxy {
return &HTTPProxy{
ReverseProxy: &httputil.ReverseProxy{
Director: director,
Transport: &http.Transport{
Dial: func(network, addr string) (net.Conn, error) {
return forward.Dial(network, addr)
},
},
},
forward: forward,
}
}
func director(request *http.Request) {
u, err := url.Parse(request.RequestURI)
if err != nil {
return
}
request.RequestURI = u.RequestURI()
v := request.Header.Get("Proxy-Connection")
if v != "" {
request.Header.Del("Proxy-Connection")
request.Header.Del("Connection")
request.Header.Add("Connection", v)
}
}
// ServeHTTPTunnel serve incoming request with CONNECT method, then route data to proxy server
func (h *HTTPProxy) ServeHTTPTunnel(response http.ResponseWriter, request *http.Request) {
var conn net.Conn
if hj, ok := response.(http.Hijacker); ok {
var err error
if conn, _, err = hj.Hijack(); err != nil {
http.Error(response, err.Error(), http.StatusInternalServerError)
return
}
} else {
http.Error(response, "Hijacker failed", http.StatusInternalServerError)
return
}
defer conn.Close()
dest, err := h.forward.Dial("tcp", request.Host)
if err != nil {
fmt.Fprintf(conn, "HTTP/1.0 500 NewRemoteSocks failed, err:%s\r\n\r\n", err)
return
}
defer dest.Close()
if request.Body != nil {
if _, err = io.Copy(dest, request.Body); err != nil {
fmt.Fprintf(conn, "%d %s", http.StatusBadGateway, err.Error())
return
}
}
fmt.Fprintf(conn, "HTTP/1.0 200 Connection established\r\n\r\n")
go func() {
defer conn.Close()
defer dest.Close()
io.Copy(dest, conn)
}()
io.Copy(conn, dest)
}
// ServeHTTP implements HTTP Handler
func (h *HTTPProxy) ServeHTTP(response http.ResponseWriter, request *http.Request) {
if request.Method == "CONNECT" {
h.ServeHTTPTunnel(response, request)
} else {
h.ReverseProxy.ServeHTTP(response, request)
}
}