Browse Source

Start of server tests not requiring curl.

Brad Fitzpatrick 11 years ago
parent
commit
8aaa0e5e6a
2 changed files with 108 additions and 2 deletions
  1. 33 2
      http2.go
  2. 75 0
      http2_test.go

+ 33 - 2
http2.go

@@ -22,6 +22,7 @@ import (
 	"errors"
 	"errors"
 	"io"
 	"io"
 	"log"
 	"log"
+	"net"
 	"net/http"
 	"net/http"
 	"net/url"
 	"net/url"
 	"strconv"
 	"strconv"
@@ -57,7 +58,7 @@ type Server struct {
 	MaxStreams int
 	MaxStreams int
 }
 }
 
 
-func (srv *Server) handleConn(hs *http.Server, c *tls.Conn, h http.Handler) {
+func (srv *Server) handleConn(hs *http.Server, c net.Conn, h http.Handler) {
 	sc := &serverConn{
 	sc := &serverConn{
 		hs:                hs,
 		hs:                hs,
 		conn:              c,
 		conn:              c,
@@ -87,7 +88,7 @@ type frameAndProcessed struct {
 
 
 type serverConn struct {
 type serverConn struct {
 	hs             *http.Server
 	hs             *http.Server
-	conn           *tls.Conn
+	conn           net.Conn
 	handler        http.Handler
 	handler        http.Handler
 	framer         *Framer
 	framer         *Framer
 	doneServing    chan struct{}          // closed when serverConn.serve ends
 	doneServing    chan struct{}          // closed when serverConn.serve ends
@@ -222,6 +223,36 @@ func (sc *serverConn) serve() {
 	}
 	}
 	log.Printf("client %v said hello", sc.conn.RemoteAddr())
 	log.Printf("client %v said hello", sc.conn.RemoteAddr())
 
 
+	f, err := sc.framer.ReadFrame()
+	if err != nil {
+		sc.logf("error reading initial frame from client: %v", err)
+		return
+	}
+	sf, ok := f.(*SettingsFrame)
+	if !ok {
+		sc.logf("invalid initial frame type %T received from client", f)
+		return
+	}
+	sf.ForeachSetting(func(s Setting) {
+		// TODO: process, record
+	})
+
+	// TODO: don't send two network packets for our SETTINGS + our
+	// ACK of their settings.  But if we make framer write to a
+	// *bufio.Writer, that increases the per-connection memory
+	// overhead, and there could be many idle conns. So maybe some
+	// liveswitchWriter-like thing where we only switch to a
+	// *bufio Writer when we really need one temporarily, else go
+	// back to an unbuffered writes by default.
+	if err := sc.framer.WriteSettings( /* TODO: actual settings */ ); err != nil {
+		sc.logf("error writing server's initial settings: %v", err)
+		return
+	}
+	if err := sc.framer.WriteSettingsAck(); err != nil {
+		sc.logf("error writing server's ack of client's settings: %v", err)
+		return
+	}
+
 	go sc.readFrames()
 	go sc.readFrames()
 
 
 	for {
 	for {

+ 75 - 0
http2_test.go

@@ -8,8 +8,10 @@
 package http2
 package http2
 
 
 import (
 import (
+	"crypto/tls"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"io"
 	"net/http"
 	"net/http"
 	"net/http/httptest"
 	"net/http/httptest"
 	"os/exec"
 	"os/exec"
@@ -21,6 +23,79 @@ import (
 )
 )
 
 
 func TestServer(t *testing.T) {
 func TestServer(t *testing.T) {
+	ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Foo", "Bar")
+	}))
+	ConfigureServer(ts.Config, &Server{})
+	ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config
+	ts.StartTLS()
+	defer ts.Close()
+
+	t.Logf("Running test server at: %s", ts.URL)
+	cc, err := tls.Dial("tcp", ts.Listener.Addr().String(), &tls.Config{
+		InsecureSkipVerify: true,
+		NextProtos:         []string{npnProto},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer cc.Close()
+
+	mustWrite(t, cc, clientPreface)
+	fr := NewFramer(cc, cc)
+	if err := fr.WriteSettings(); err != nil {
+		t.Fatal(err)
+	}
+
+	// Expect first Settings frame.
+	{
+		f, err := fr.ReadFrame()
+		if err != nil {
+			t.Fatal(err)
+		}
+		sf, ok := f.(*SettingsFrame)
+		if !ok {
+			t.Fatalf("Received a %T, not a Settings frame from the server", f)
+		}
+		sf.ForeachSetting(func(s Setting) {
+			t.Logf("Server sent setting %v = %v", s.ID, s.Val)
+		})
+	}
+
+	// And expect an ACK of our settings.
+	{
+		f, err := fr.ReadFrame()
+		if err != nil {
+			t.Fatal(err)
+		}
+		sf, ok := f.(*SettingsFrame)
+		if !ok {
+			t.Fatalf("Received a %T, not a Settings ack frame from the server", f)
+		}
+		if !sf.Header().Flags.Has(FlagSettingsAck) {
+			t.Fatal("Settings Frame didn't have ACK set")
+		}
+	}
+
+	// TODO: table-itize steps, write request (HEADERS frame), read response.
+}
+
+func mustWrite(t *testing.T, w io.Writer, p []byte) {
+	n, err := w.Write(p)
+	const maxLen = 80
+	l := len(p)
+	if len(p) > maxLen {
+		p = p[:maxLen]
+	}
+	if err != nil {
+		t.Fatalf("Error writing %d bytes (%q): %v", l, p, err)
+	}
+	if n != len(p) {
+		t.Fatalf("Only wrote %d of %d bytes (%q)", n, l, p)
+	}
+}
+
+func TestServerWithCurl(t *testing.T) {
 	requireCurl(t)
 	requireCurl(t)
 
 
 	ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 	ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {