为了账号安全,请及时绑定邮箱和手机立即绑定

带有域阻止的 http 转发

带有域阻止的 http 转发

Go
三国纷争 2022-07-11 17:33:49
我正在尝试实现一个支持域阻止的 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}不幸的是,它根本不起作用。请求可以打印出来,但不能用于响应。我一直卡在这里,不知道出了什么问题。
查看完整描述

1 回答

?
慕码人2483693

TA贡献1860条经验 获得超9个赞

TCP转发就是实现隧道代理不需要解析数据。反向代理可以使用标准库。


实现隧道代理以分离 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)

}

但是,直接转发请求不处理跳到跳标头。跳到跳标头在rfc中明确说明。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

}


查看完整回答
反对 回复 2022-07-11
  • 1 回答
  • 0 关注
  • 105 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信