Hi,

first, two points on the more obvious aspects:

   - The ContentLength header is just a hint for the server. Nothing 
   prevents you from setting the content length to some value (like 1896240) 
   and then sending a request body with a different size. The resulting 
   request might not be a valid HTTP request, but if you explicitly set the 
   ContentLength to an invalid value, there is nothing to prevent this.
   - The Read() function should return EOF to signal that all bytes are 
   read. As long as the reader does not return EOF, the caller must assume 
   that there are more bytes to be read.

Taking these two points into account, the code basically sends an 
infinitely long HTTP request with a false ContentLength header of 1896240. 
As the request is infinitely long, the code will never finish sending this 
request.

The less obvious aspect of your question is: Why do you receive a response 
when the request is never finished?

The answer is found in a small comment in the implementation of Go's http 
transport 
(https://github.com/golang/go/blob/master/src/net/http/transport.go#L1768-L1770):

// Write the request concurrently with waiting for a response,
// in case the server decides to reply before reading our full
// request body.

Because of this optimisation, you receive a response while you are still 
sending the request.

The server interprets the ContentLength header and stops reading after 
1896240 bytes, and sends you the response. http.DefaultClient.Do(req) 
returns the response, but in the background you continue sending your 
infinitely long request.

Hope this helps,
Fabian

On Monday, July 25, 2016 at 2:49:30 PM UTC+2, Feng Liyuan wrote:
>
> Set a io.Reader in http.NewRequest and do a http request, I found that 
> someone reads the io.Reader even after the http request done.
>
> Is it a correct behaviour? And is it documented?
>
> My client code is
>
> package main
> import (
>     "log"
>     "net/http"
>     "time")
> type reader struct{}
> func (r reader) Read(p []byte) (int, error) {
>     log.Println("READ")
>     return len(p), nil}
> func (r reader) Close() error {
>     log.Println("CLOSE")
>     return nil}
> func main() {
>     r := reader{}
>     req, _ := http.NewRequest("GET", "http://localhost:12306/";, r)
>     req.ContentLength = 1896240
>     resp, err := http.DefaultClient.Do(req)
>     if resp != nil {
>         resp.Body.Close()
>     }
>     log.Println("http.DefaultClient.Do", err)
>     time.Sleep(1e9)}
>
> and the server localhost:12306 simple write an http code and do nothing.
>
> This is the output of the program.
>
> [sunrunaway:/tmp]$ go run test.go 
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 READ
> 2016/07/25 13:04:32 http.DefaultClient.Do <nil>
> 2016/07/25 13:04:32 READ
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to