dongyin8991 2019-02-18 00:37
浏览 166

在Go中多路复用可以处理非HTTP协议的HTTP服务器的正确方法

I have built a router with extended logging capabilities using Go. It works properly for most use cases. However, it encounters problems when clients send non-standard HTTP messages on port 80.

To date, I have solved this by implementing my own version of ServeHTTP():

func (myproxy *MyProxy) ServeHTTP(w http.ResponseWtier, r *http.Request) {

  // Inspect headers
  // Determine if it is a custom protocol (ie: websockets, CONNECT requests)
  // Implement handlers for each time
} 

In the event that I determine a request is a non-standard HTTP protocol, the request is played back to the original destination (via http.Request.Write()) and everyone is happy.

At least, most of the time. The problem arises with edge cases. Tivo clients do not send "Host" headers and appear to not like all kinds of other standard things that Go does (such as capitalizing header names). The number of possible variations on this is endless so what I would very much like to do is to buffer the original request - exactly as it was sent to me without any modifications - and replay it back to the original destination server.

I could hack this by re-implementing net.Http.Server, but this seems like an extraordinarily difficult and brittle approach. Would I would prefer to do would be to somehow hook into net/http/http/server.go right around the point where it receives a connection, then wrap that in a spy wrapper that logs the request to a buffer.

func (srv *Server) Serve(l net.Listener) error {

        // Lots of listener code...

    c := srv.newConn(rw)
    c.setState(c.rwc, StateNew) // before Serve can return

        // I'd like to wrap c here and save the request for possible reply later.
    go c.serve(ctx)
}

https://golang.org/src/net/http/server.go?s=93229:93284#L2805

Edit: I have looked at httpUtil:DumpRequest but this slightly modifies the original request (changes case and order of headers). If it didn't do that, it would be an ideal solution.

https://godoc.org/net/http/httputil#DumpRequest

Is there a way to hook connections around this point before they are parsed by http.Request?

  • 写回答

1条回答 默认 最新

  • douyue5856 2019-03-14 16:46
    关注

    In the interest of helping others, I wanted to answer my question. The approach I suggested above does in fact work and is the proper way to do this. In summary:

    • Implement ListenAndServe()
    • Wrap the incoming net.Conn in a TeeReader or other multiplexed connection wrapper
    • Record the request
    • Dial the original destination and connect with the inbound connection, replaying the original request if necessary.

    A similar use case is required when upgrading connection requests for websockets servers. A nice writeup can be found here:

    https://medium.freecodecamp.org/million-websockets-and-go-cc58418460bb

    评论

报告相同问题?

悬赏问题

  • ¥20 win11修改中文用户名路径
  • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥70 PlayWright在Java上连接CDP关联本地Chrome启动失败,貌似是Windows端口转发问题
  • ¥15 帮我写一个c++工程
  • ¥30 Eclipse官网打不开,官网首页进不去,显示无法访问此页面,求解决方法
  • ¥15 关于smbclient 库的使用
  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害