Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

http.Request.Clone() is not deep clone?

Tags:

http

go

i want get a Request , and use ParseForm to check some data , then send the same one to proxy , buy if i do that , we have a problem

error log like this

2020/05/26 15:34:47 http: proxy error: net/http: HTTP/1.x transport connection broken: http: ContentLength=32 with Body length 0

so I finally figured it out , ParseForm () well close Request .body

and this is work proxy code

    url, _ := url.Parse(config.GetGameHost())

    proxy := httputil.NewSingleHostReverseProxy(url)
    r.URL.Host = url.Host
    r.URL.Scheme = url.Scheme
    r.Header.Set("X-Forwarded-Host", r.Header.Get("Host"))
    r.Host = url.Host
    proxy.ServeHTTP(w, r)

so , i think i need clone the deep clone request too get my data and send origin request too proxy i edit my code too this

nr := r.Clone(r.Context())
nr.ParseForm()

url, _ := url.Parse(config.GetGameHost())

proxy := httputil.NewSingleHostReverseProxy(url)

r.URL.Host = url.Host
r.URL.Scheme = url.Scheme
r.Header.Set("X-Forwarded-Host", r.Header.Get("Host"))
r.Host = url.Host

proxy.ServeHTTP(w, r)

and the error log show again

2020/05/26 15:49:29 http: proxy error: net/http: HTTP/1.x transport connection broken: http: ContentLength=32 with Body length 0

is the Clone() are not deep clone or i do wrong?

------------ this work------------

body, err := ioutil.ReadAll(r.Body)
if err != nil {
    // ...
}
url, _ := url.Parse(config.GetGameHost())

r2 := r.Clone(r.Context())

r.Body = ioutil.NopCloser(bytes.NewReader(body))
r2.Body = ioutil.NopCloser(bytes.NewReader(body))

r.ParseForm()

proxy := httputil.NewSingleHostReverseProxy(url)
proxy.ServeHTTP(w, r2)
like image 796
AM031447 Avatar asked Jul 23 '26 09:07

AM031447


1 Answers

http.Request.Body can only be read once, a new body needs to be copied.

body,err := ioutil.ReadAll(r)
if err != nil {
    // ...
}
r2 := r.Clone(r.Context())
// clone body
r.Body = ioutil.NopCloser(bytes.NewReader(body))
r2.Body = ioutil.NopCloser(bytes.NewReader(body))

// parse r1, proxy r2
r.ParseForm()
proxy.ServerHTTP(w, r2)

The body object defaults to net.Conn multi-layer encapsulation. Each time it uses the io.Reader interface to read 4kb, saving memory usage, it is generally used while reading from the network.

Therefore, the body can only be read from the network once. If you want the body object to be read repeatedly, you should read it all, save it, and use it.

like image 175
eudore Avatar answered Jul 25 '26 00:07

eudore