hashicorp/yamux

http.Serve(session, nil) hangs in abortPendingRead() when hijack is used

Closed this issue · 1 comments

hagna commented

This may be a misuse of yamux instead of a yamux issue, but I just wanted to let you know that the following code hangs for me in hijack() (really abortPendingRead() in go/src/net/http/server.go:3341) on go version devel +3067376 Mon Feb 26 22:10:51 2018 +0000 linux/amd64.

package main

import (
	"context"
	"flag"
	"fmt"
	"github.com/hashicorp/yamux"
	"net"
	"net/http"
	"time"
)

var endpoint = flag.String("ep", "127.0.0.1:8000", "endpoint")

func client() {
	// Get a TCP connection
	conn, err := net.Dial("tcp", *endpoint)
	if err != nil {
		panic(err)
	}

	// Setup client side of yamux
	session, err := yamux.Client(conn, nil)
	if err != nil {
		panic(err)
	}
	http.Serve(session, nil)

}

func server() {
	// Accept a TCP connection
	listener, err := net.Listen("tcp", *endpoint)
	if err != nil {
		panic(err)
	}
	conn, err := listener.Accept()
	if err != nil {
		panic(err)
	}

	// Setup server side of yamux
	session, err := yamux.Server(conn, nil)
	if err != nil {
		panic(err)
	}
	tr := &http.Transport{
		DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
			return session.Open()
		},
	}
	client := &http.Client{Transport: tr}
	resp, err := client.Get("http://127.0.0.1:8000/works")
	if err != nil {
		panic(err)
	}
	fmt.Println(resp)
	fmt.Println("hanging in abortPendingRead()...")
	resp, err = client.Get("http://127.0.0.1:8000/bug")
	if err != nil {
		fmt.Println("we should not see this because it should hang in abortPendingRead()")
		fmt.Println(err)
	}
	fmt.Println(resp)

}

func main() {
	flag.Parse()
	http.HandleFunc("/works", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "this works")
	})
	http.HandleFunc("/bug", func(w http.ResponseWriter, r *http.Request) {
		h, ok := w.(http.Hijacker)
		if !ok {
			fmt.Printf("does not support hijack")
		}
		c, _, err := h.Hijack()
		if err != nil {
			panic(err)
		}
		fmt.Fprintf(c, "this works")
		c.Close()
	})

	go server()
	time.Sleep(90 * time.Millisecond)
	client()
}
hagna commented

go version go1.10 linux/amd64 works.
go version devel +0e8b711 Tue Mar 6 18:37:19 2018 +0000 linux/amd64 also works.