带域阻止的 http 转发
http forward with domain blocking
我正在尝试实现支持域阻止的 http 转发服务器。我试过了
go io.Copy(dst, src)
go io.Copy(src, dst)
而且它在 tcp 转发方面非常有用。然后我尝试用类似于
的东西来解析请求行
go func(){
reader := io.TeeReader(src, dst)
textReader := textproto.NewReader(bufio.NewReader(reader))
requestLine, _ = textReader.ReadLine()
// ...
ioutil.ReadAll(reader)
}
它工作正常,但我开始担心性能不佳(ioutil.ReadAll
)。所以我写了下面的代码。
func (f *Forwarder) handle(src, dst net.Conn) {
defer dst.Close()
defer src.Close()
done := make(chan struct{})
go func() {
textReader := bufio.NewReader(src)
requestLine, _ = textReader.ReadString('\n')
// parse request line and apply domain blocking
dst.Write([]byte(requestLine))
io.Copy(dst, src)
done <- struct{}{}
}()
go func() {
textReader := bufio.NewReader(dst)
s.statusLine, _ = textReader.ReadString('\n')
src.Write([]byte(s.statusLine))
io.Copy(src, dst)
done <- struct{}{}
}()
<-done
<-done
}
不幸的是,它根本不起作用。请求可以打印出来,但不能用于响应。我一直卡在这里,不知道出了什么问题。
TCP转发是实现隧道代理不需要解析数据。反向代理可以使用standard library.
隧道代理实现了http和https协议的分离。客户端一般使用隧道发送https,发送Connect方法。发送http是Get方法。对于https请求服务,只有dail创建连接tcp转换,http请求使用反向代理实现。
func(w http.ResponseWriter, r *http.Request) {
// check url host
if r.URL.Host != "" {
if r.Method == eudore.MethodConnect {
// tunnel proxy
conn, err := net.Dial("tcp", r.URL.Host)
if err != nil {
w.WriteHeader(502)
return
}
client, _, err := w.Hijack()
if err != nil {
w.WriteHeader(502)
conn.Close()
return
}
client.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
go func() {
io.Copy(client, conn)
client.Close()
conn.Close()
}()
go func() {
io.Copy(conn, client)
client.Close()
conn.Close()
}()
} else {
// reverse proxy
httputil.NewSingleHostReverseProxy(r.URL).ServeHTTP(w, r)
}
}
}
实现反向代理将解析客户端请求,代理将请求发送到目标服务器。
反向代理转换请求,未测试:
func(w http.ResponseWriter, r *http.Request) {
// set host
r.URL.Scheme = "http"
r.URL.Path = "example.com"
// send
resp,err := http.DefaultClient.Do(r)
if err != nil {
w.WriteHeader(502)
return
}
// write respsonse
defer resp.Body.Close()
w.WriteHeader(resp.StatusCode)
h := w.Header()
for k,v := range resp.Header {
h[k]=v
}
io.Copy(w, resp.Body)
}
但是直接转发请求不处理hop-to-hopheader。 hop-to-hopheader在rfc中写得很清楚。 hop-to-hop header 是两个连接之间的传输信息。比如client到proxy和proxy到server就是两个。服务器的客户端是 end-to-end.
反向代理请直接使用standard library,它已经为您处理了hop-to-hop header和升级
带有过滤器的 NewSingleHostReverseProxy 示例:
package main
import (
"net/http"
"strings"
"net/http/httputil"
"net/url"
)
func main() {
addr, _ := url.Parse("http://localhost:8088")
proxy := httputil.NewSingleHostReverseProxy(addr)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/api/") {
proxy.ServeHTTP(w, r)
} else {
w.WriteHeader(404)
}
})
// Listen Server
}
我正在尝试实现支持域阻止的 http 转发服务器。我试过了
go io.Copy(dst, src)
go io.Copy(src, dst)
而且它在 tcp 转发方面非常有用。然后我尝试用类似于
的东西来解析请求行go func(){
reader := io.TeeReader(src, dst)
textReader := textproto.NewReader(bufio.NewReader(reader))
requestLine, _ = textReader.ReadLine()
// ...
ioutil.ReadAll(reader)
}
它工作正常,但我开始担心性能不佳(ioutil.ReadAll
)。所以我写了下面的代码。
func (f *Forwarder) handle(src, dst net.Conn) {
defer dst.Close()
defer src.Close()
done := make(chan struct{})
go func() {
textReader := bufio.NewReader(src)
requestLine, _ = textReader.ReadString('\n')
// parse request line and apply domain blocking
dst.Write([]byte(requestLine))
io.Copy(dst, src)
done <- struct{}{}
}()
go func() {
textReader := bufio.NewReader(dst)
s.statusLine, _ = textReader.ReadString('\n')
src.Write([]byte(s.statusLine))
io.Copy(src, dst)
done <- struct{}{}
}()
<-done
<-done
}
不幸的是,它根本不起作用。请求可以打印出来,但不能用于响应。我一直卡在这里,不知道出了什么问题。
TCP转发是实现隧道代理不需要解析数据。反向代理可以使用standard library.
隧道代理实现了http和https协议的分离。客户端一般使用隧道发送https,发送Connect方法。发送http是Get方法。对于https请求服务,只有dail创建连接tcp转换,http请求使用反向代理实现。
func(w http.ResponseWriter, r *http.Request) {
// check url host
if r.URL.Host != "" {
if r.Method == eudore.MethodConnect {
// tunnel proxy
conn, err := net.Dial("tcp", r.URL.Host)
if err != nil {
w.WriteHeader(502)
return
}
client, _, err := w.Hijack()
if err != nil {
w.WriteHeader(502)
conn.Close()
return
}
client.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
go func() {
io.Copy(client, conn)
client.Close()
conn.Close()
}()
go func() {
io.Copy(conn, client)
client.Close()
conn.Close()
}()
} else {
// reverse proxy
httputil.NewSingleHostReverseProxy(r.URL).ServeHTTP(w, r)
}
}
}
实现反向代理将解析客户端请求,代理将请求发送到目标服务器。
反向代理转换请求,未测试:
func(w http.ResponseWriter, r *http.Request) {
// set host
r.URL.Scheme = "http"
r.URL.Path = "example.com"
// send
resp,err := http.DefaultClient.Do(r)
if err != nil {
w.WriteHeader(502)
return
}
// write respsonse
defer resp.Body.Close()
w.WriteHeader(resp.StatusCode)
h := w.Header()
for k,v := range resp.Header {
h[k]=v
}
io.Copy(w, resp.Body)
}
但是直接转发请求不处理hop-to-hopheader。 hop-to-hopheader在rfc中写得很清楚。 hop-to-hop header 是两个连接之间的传输信息。比如client到proxy和proxy到server就是两个。服务器的客户端是 end-to-end.
反向代理请直接使用standard library,它已经为您处理了hop-to-hop header和升级
带有过滤器的 NewSingleHostReverseProxy 示例:
package main
import (
"net/http"
"strings"
"net/http/httputil"
"net/url"
)
func main() {
addr, _ := url.Parse("http://localhost:8088")
proxy := httputil.NewSingleHostReverseProxy(addr)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/api/") {
proxy.ServeHTTP(w, r)
} else {
w.WriteHeader(404)
}
})
// Listen Server
}