Skip to content

x/net/http2: Transport hangs forever if using a pipe that has not been written to yet as req.Body #17480

@luna-duclos

Description

@luna-duclos

### What version of Go are you using (go version)?
Go 1.7.1

### What operating system and processor architecture are you using (go env)?

set GOARCH=amd64                                                                                                                                                
set GOBIN=                                                                                                                                                      
set GOEXE=.exe                                                                                                                                                  
set GOHOSTARCH=amd64                                                                                                                                            
set GOHOSTOS=windows                                                                                                                                            
set GOOS=windows                                                                                                                                                
set GOPATH=D:\src\psg\server;D:\src\psg\server\vendor                                                                                                           
set GORACE=                                                                                                                                                     
set GOROOT=C:\apps\Go                                                                                                                                           
set GOTOOLDIR=C:\apps\Go\pkg\tool\windows_amd64                                                                                                                 
set CC=gcc                                                                                                                                                      
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0 -fdebug-prefix-map=C:\Users\lunad\AppData\Local\Temp\go-build906126950=/tmp/go-build -gno-record-gcc-switches  
set CXX=g++                                                                                                                                                     
set CGO_ENABLED=1                                                                                                                                               

### What did you do?
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.

I ran the following program:

package main

import (
    "crypto/rand"
    "io"
    "log"
    "net/http"
    "runtime/debug"
    "time"

    "golang.org/x/net/http2"
)

func main() {
    // set a 10 second timer for success
    go func() {
        timer := time.NewTimer(10 * time.Second)
        <-timer.C
        debug.SetTraceback("all")
        panic("10 second test period expired")
    }()

    transport := &http2.Transport{}
    c := &http.Client{Transport: transport}

    // Get a set of pipes, we'll use these to send data to the server
    pipeReader, pipeWriter := io.Pipe()

    // Initialize the request
    req, err := http.NewRequest("PUT", "https://http2.golang.org/bidirectional-stream", pipeReader)
    if err != nil {
        pipeWriter.Close()
        log.Fatalf("Error while initializing http request: %v", err)
    }

    // Set the body of the request to the reader end of our pipe, and initiate the request.
    req.Body = pipeReader
    resp, err := c.Do(req)
    if err != nil {
        pipeWriter.Close()
        log.Fatalf("Error during http call: %v", err)
    }

    // Check that we actually got a 200 OK, if not: error out
    if resp.StatusCode != http.StatusOK {
        resp.Body.Close()
        pipeWriter.Close()
        log.Fatalf("http call got non-200 status code %d", resp.StatusCode)
    }

    // Use a 10 byte buffer
    buffer := make([]byte, 10)

    // Read some data
    dataLen, err := resp.Body.Read(buffer)
    if err != nil {
        log.Fatalf("Error while reading data: %v", err)
    }

    log.Printf("Got data: %+v", buffer[:dataLen])

    // Reply
    if _, err := rand.Read(buffer); err != nil {
        log.Fatalf("Error while reading random data: %v", err)
    }

    if _, err := pipeWriter.Write(buffer); err != nil {
        log.Fatalf("Error while writing data: %v", err)
    }
}

### What did you expect to see?
I expected to see a bidirectional http-2 stream, with the server talking first, and the client then replying to the server.

### What did you see instead?
The program hangs within http2/transport.go, in the bodyAndLength function, due to that function doing a Read(), which ofcourse hangs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions