Repository: go
Issue: net/http: first byte of second request in hijack mode is lost
Labels: NeedsInvestigation

Please answer these questions before submitting your issue. Thanks!


### What version of Go are you using (`go version`)?

go version go1.11 darwin/amd64

### Does this issue reproduce with the latest release?
Yes

### What operating system and processor architecture are you using (`go env`)?
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/jjz/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/jjz/go"
GOPROXY=""
GORACE=""
GOROOT="/opt/go"
GOTMPDIR=""
GOTOOLDIR="/opt/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/x2/t219h_ks1wl4gjwnz82xc17h0000gn/T/go-build513787949=/tmp/go-build -gno-record-gcc-switches -fno-common"

### What did you do?

Hijack client http request to backend server in go http server.  If the underlay connection is reused which means more than one http request is send over the connection, when first request has body size >0, first byte of the second request will be eat. 

To reproduce this issue, I wrote a simple testcase. Client send requests to a transparent proxy who forward requests to backend server in hijack mode. The backend server is a simple echo server, response request method and body to its client. Below are the codes:

#### Proxy & Server

```
package main

import (
	"net/http"
	"net"
	"sync"
	"io"
	"fmt"
	"bytes"
)

func echo(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(200)
	var buf bytes.Buffer
	io.Copy(&buf, r.Body)
	resp := fmt.Sprintf("method: %s, body: %s", r.Method, buf.String())
	w.Write([]byte(resp))
}

type Proxy struct {
	Backend string
}

func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Printf("Receive a request from %v\n", r.RemoteAddr)
	hj, ok := w.(http.Hijacker)
	if !ok {
		http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError)
		return
	}

	backendConn, err := net.Dial("tcp", p.Backend)
	if err != nil {
		fmt.Printf("err: %v\n", err)
		return
	}
	defer backendConn.Close()

	clientConn, bufrw, err := hj.Hijack()
	if err != nil {
		return
	}

	defer clientConn.Close()

	if err := r.Write(backendConn); err != nil {
		return
	}

	var wg = sync.WaitGroup{}
	wg.Add(2)
	copy := func(dst io.Writer, src io.Reader) {
		io.Copy(dst, src)
		if conn, ok := dst.(interface {
			CloseWrite() error
		}); ok {
			conn.CloseWrite()
		}
		wg.Done()
	}

	bufferedReader := io.LimitReader(bufrw, int64(bufrw.Reader.Buffered()))
	mr := io.MultiReader(bufferedReader, clientConn)

	go copy(clientConn, backendConn)
	go copy(backendConn, mr)
	wg.Wait()
}

func main() {
	go http.ListenAndServe(":8081", http.HandlerFunc(echo))

	p := &Proxy{Backend: "localhost:8081"}
	http.ListenAndServe(":8080", p)
}
```

#### Client:

```
package main

import (
	"net/http"
	"bytes"
	"io"
	"os"
	"fmt"
)

func req(client *http.Client, msg string) {
	body := bytes.NewBufferString(msg)
	r, err := http.NewRequest("POST", "http://localhost:8080/", body)
	if err != nil {
		panic(err)
	}
	resp, err := client.Do(r)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	if _, err := io.Copy(os.Stdout, resp.Body); err != nil {
		panic(err)
	}
}

func main() {
	c := &http.Client{}
	fmt.Println("Send 'Hello'")
	req(c, "Hello")
	fmt.Println()

	fmt.Println("Send 'World'")
	req(c, "World")
}
```

1. Run the server in terminal: `go run server.go`
2. Open another terminal, run `go run client.go`

Output show that the letter P (of word POST) POST is lost.

### What did you expect to see?

```
go run client.go
Send 'Hello'
method: POST, body: Hello
Send 'World'
method: POST, body: World
```

### What did you see instead?

```
go run client.go
Send 'Hello'
method: POST, body: Hello
Send 'World'
method: OST, body: World
```