Search code examples
gotcp

Transform http.Response into array of bytes


I am trying to develop a tcp proxy, in this tcp proxy I will have to manipulate both http and tcp requests.

At the moment for the incoming request I detect if it is an http or tcp request, if it is an http then I parse it into an http.Request:


func (s *TcpProxy) OnMessage(c *connection.Connection, ctx interface{}, data []byte) interface{} {
    reader := bytes.NewReader(data)
    newReader := bufio.NewReader(reader)
    req, err := http.ReadRequest(newReader)
    // This is an http request
}

Now I manipulate the request conveniently since I can use the methods exposed from that interface, then eventually I will send the response back from my proxy to the service that received the inbound request.


func (s *TcpProxy) OnMessage(c *connection.Connection, ctx interface{}, data []byte) interface{} {
    reader := bytes.NewReader(data)
    newReader := bufio.NewReader(reader)
    req, err := http.ReadRequest(newReader)
    // Manipulate http request
    // ...
    // Proxy the request
    proxyReq, err := http.NewRequest(req.Method, proxyUrl, req.Body)

    // Capture the duration while making a request to the destination service.
    res, err := httpClient.Do(proxyReq)
    
    buf := res.ToBuffer() // <= How can I achieve this
   
    c.Send(buf)

    c.Close()
    return nil
}

However I cannot find a way to convert back the response into an array of bytes or string, am I missing something?


Solution

  • An http.Request object has a Write method:

    func (r *Request) Write(w io.Writer) error
    

    Write writes an HTTP/1.1 request, which is the header and body, in wire format.

    You can use this to write the bytes into a buffer object. For example:

    package main
    
    import (
        "bytes"
        "fmt"
        "net/http"
    )
    
    func main() {
        var buf bytes.Buffer
    
        req, err := http.NewRequest("GET", "http://google.com", nil)
        if err != nil {
            panic(err)
        }
    
        client := &http.Client{}
        res, err := client.Do(req)
        if err != nil {
            panic(err)
        }
        defer res.Body.Close()
    
        if err := res.Write(&buf); err != nil {
            panic(err)
        }
    
        // ...do whatever you want with the buffer here...
        fmt.Println(buf.String())
    }
    

    A Buffer object has a Bytes method that will return a byte array, if that's what you want.