Proper way to mux an HTTP server in Go that can handle non-HTTP protocols

时间:2019-02-18 00:37:17

标签: http go

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 个答案:

答案 0 :(得分:0)

为了帮助他人,我想回答我的问题。我上面建议的方法实际上是有效的,并且是执行此操作的正确方法。总结:

  • 实施ListenAndServe()
  • 用TeeReader或其他多路复用连接包装器包装传入的网络Conn
  • 记录请求
  • 拨打原始目的地并连接入站连接,必要时重播原始请求。

升级Websockets服务器的连接请求时,需要类似的用例。一个不错的文章可以在这里找到:

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