检查Go服务器中的HTTP连接是否被劫持。

huangapple go评论81阅读模式
英文:

check whether http connection is hijacked in go server

问题

我正在使用Go语言编写一个HTTP服务器,使用以下模式来处理API输出:

func handler(w http.ResponseWriter, r *http.Request) {
    defer reply(w, r, L)() // L是一个Logger
    // 做一些事情...
}

func reply(w http.ResponseWriter, r *http.Request, log Logger) func() {
    cid := []byte{0, 0, 0, 0}
    if log != nil {
        rand.Read(cid)
        log.Debug("[%x] %s %s", cid, r.Method, r.URL.String())
    }
    entry := time.Now()
    return func() {
        if log != nil {
            defer log.Debug("[%x] elapsed %d millis", cid, time.Since(entry).Milliseconds())
        }
        _, err := w.Write(nil)
        if err == http.ErrHijacked {
            return // API是一个WEBSOCKET入口点,不做任何操作
        }
        // 处理普通HTTP API的通用输出逻辑...
    }
}

我这样做的原因是,我在标准库中找到了这样的注释:

// ErrHijacked是在ResponseWriter.Write调用时返回的,
// 当底层连接使用Hijacker接口被劫持时。在被劫持的连接上进行零字节写入将返回ErrHijacked而没有其他副作用。
ErrHijacked = errors.New("http: connection has been hijacked")

然而,在Write()方法之后,我找到了这样的注释:

// Write将数据作为HTTP回复的一部分写入连接。
//
// 如果尚未调用WriteHeader,Write在写入数据之前调用WriteHeader(http.StatusOK)。
// 如果Header不包含Content-Type行,Write会将Content-Type设置为将前512个字节的写入数据传递给...
Write([]byte) (int, error)

我的问题是:

1)使用我的代码来安全地检测HTTP连接是否被劫持是否可以?我只想检查连接是否被劫持,而希望它为我添加标头!

2)由于ResponseWriter是一个接口,我无法通过源代码找出标准库是如何实现该方法的。一般来说,我如何深入到标准库(或任何开源代码)中,以找出接口的实现方式?

英文:

I am writing an HTTP server in Go, which uses the following pattern to handle API output:

func handler(w http.ResponsWriter, r *http.Request) {
    defer reply(w, r, L)() //L is a Logger
    //do things...
}

func reply(w http.ResponseWriter, r *http.Request, log Logger) func() {
	cid := []byte{0, 0, 0, 0}
	if log != nil {
		rand.Read(cid)
		log.Debug("[%x] %s %s", cid, r.Method, r.URL.String())
	}
	entry := time.Now()
	return func() {
		if log != nil {
			defer log.Debug("[%x] elapsed %d millis", cid, time.Since(entry).Milliseconds())
		}
		_, err := w.Write(nil)
		if err == http.ErrHijacked {
			return //API is a WEBSOCKET entry point, do nothing
		}
        //handle common output logic for normal HTTP APIs...
	}
}

The reason I do this, is that I found this comment in the standard library:

// ErrHijacked is returned by ResponseWriter.Write calls when
// the underlying connection has been hijacked using the
// Hijacker interface. A zero-byte write on a hijacked
// connection will return ErrHijacked without any other side
// effects.
ErrHijacked = errors.New("http: connection has been hijacked")

However following the Write() method, I got this comment:

// Write writes the data to the connection as part of an HTTP reply.
//
// If WriteHeader has not yet been called, Write calls
// WriteHeader(http.StatusOK) before writing the data. If the Header
// does not contain a Content-Type line, Write adds a Content-Type set
// to the result of passing the initial 512 bytes of written data to
// ...
Write([]byte) (int, error)

My questions are:

  1. Is it OK to use my code to safely detect if a HTTP connection is hijacked? I only want to check the connection is hijacked or not, but do NOT want it to add headers for me!

  2. Since the ResponseWriter is an interface, I cannot click through the source code to find out how the standard library implements that method. In general, how can I drill down to the standard library (or any open source code) to find out the implementation of an interface?

答案1

得分: 1

感谢Cerise,我找到了标准response.Writer的源代码:

func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err error) {
	if w.conn.hijacked() {
		if lenData > 0 {
			caller := relevantCaller()
			w.conn.server.logf("http: response.Write on hijacked connection from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line)
		}
		return 0, ErrHijacked
	}
    ... ....

所以,正如文档中所说,没有副作用。

英文:

Thanks to Cerise, I found the source code of the standard response.Writer:

func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err error) {
	if w.conn.hijacked() {
		if lenData > 0 {
			caller := relevantCaller()
			w.conn.server.logf("http: response.Write on hijacked connection from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line)
		}
		return 0, ErrHijacked
	}
    ... ....

So, as said in the document, there is NO side effect.

huangapple
  • 本文由 发表于 2022年9月30日 16:05:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/73905718.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定