2

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
    To answer 2: The application calls http.ListenAndServe or one of it friends. Follow the code from there to find the dynamic type passed to the handler. Another approach is to fmt.Printf("the response writer is a %T\n", responseWriter) in a handler. The code is in server.go. Commented Sep 30, 2022 at 8:33

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.