带有域阻止的 http 转发

我正在尝试实现一个支持域阻止的 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

}

不幸的是,它根本不起作用。请求可以打印出来,但不能用于响应。我一直卡在这里,不知道出了什么问题。


三国纷争
浏览 106回答 1
1回答

慕码人2483693

TCP转发就是实现隧道代理不需要解析数据。反向代理可以使用标准库。实现隧道代理以分离 http 和 https 协议。客户端一般使用隧道发送https,发送Connect方法。发送http是Get方法。对于https请求服务,只有dail创建连接tcp转换,http请求使用反向代理实现。func(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; // check url host&nbsp; &nbsp; if r.URL.Host != "" {&nbsp; &nbsp; &nbsp; &nbsp; if r.Method == eudore.MethodConnect {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // tunnel proxy&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conn, err := net.Dial("tcp", r.URL.Host)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; w.WriteHeader(502)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; client, _, err := w.Hijack()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; w.WriteHeader(502)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conn.Close()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; client.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; io.Copy(client, conn)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; client.Close()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conn.Close()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; io.Copy(conn, client)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; client.Close()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conn.Close()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }()&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // reverse proxy&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; httputil.NewSingleHostReverseProxy(r.URL).ServeHTTP(w, r)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}实现反向代理会解析客户端请求,代理会将请求发送到目标服务器。反向代理转换请求,未经测试:func(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; // set host&nbsp; &nbsp; r.URL.Scheme = "http"&nbsp; &nbsp; r.URL.Path = "example.com"&nbsp; &nbsp; // send&nbsp; &nbsp; resp,err := http.DefaultClient.Do(r)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; w.WriteHeader(502)&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp; // write respsonse&nbsp; &nbsp; defer resp.Body.Close()&nbsp; &nbsp; w.WriteHeader(resp.StatusCode)&nbsp; &nbsp; h := w.Header()&nbsp; &nbsp; for k,v := range resp.Header {&nbsp; &nbsp; &nbsp; &nbsp; h[k]=v&nbsp; &nbsp; }&nbsp; &nbsp; io.Copy(w, resp.Body)}但是,直接转发请求不处理跳到跳标头。跳到跳标头在rfc中明确说明。hop-to-hop header是两个连接之间的传输信息。例如,客户端到代理和代理到服务器是两个。客户端到服务器是端到端的。反向代理请直接使用标准库,它已经为您处理了跳到跳标头和升级。带有过滤器的示例 NewSingleHostReverseProxy:package mainimport (&nbsp; &nbsp; "net/http"&nbsp; &nbsp; "strings"&nbsp; &nbsp; "net/http/httputil"&nbsp; &nbsp; "net/url")func main() {&nbsp; &nbsp; addr, _ := url.Parse("http://localhost:8088")&nbsp; &nbsp; proxy := httputil.NewSingleHostReverseProxy(addr)&nbsp; &nbsp; http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; &nbsp; &nbsp; if strings.HasPrefix(r.URL.Path, "/api/") {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; proxy.ServeHTTP(w, r)&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; w.WriteHeader(404)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; })&nbsp; &nbsp; // Listen Server}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go