From 3c16e8c9ee38afdf518c2cab232ddc8d28735b1d Mon Sep 17 00:00:00 2001 From: Lucas Clemente Date: Fri, 15 Apr 2016 14:31:31 +0200 Subject: [PATCH] introduce stream callback in session, move http2 stuff to main.go --- example/main.go | 32 +++++++++++++++++++++++++++++++- session.go | 42 +++++++++++++++++++++--------------------- 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/example/main.go b/example/main.go index df5be28ee..a361d9eb0 100644 --- a/example/main.go +++ b/example/main.go @@ -6,6 +6,9 @@ import ( "net" "os" + "golang.org/x/net/http2" + "golang.org/x/net/http2/hpack" + "github.com/lucas-clemente/quic-go" "github.com/lucas-clemente/quic-go/crypto" "github.com/lucas-clemente/quic-go/protocol" @@ -77,7 +80,7 @@ func main() { session, ok := sessions[publicHeader.ConnectionID] if !ok { - session = quic.NewSession(conn, publicHeader.ConnectionID, serverConfig) + session = quic.NewSession(conn, publicHeader.ConnectionID, serverConfig, handleStream) sessions[publicHeader.ConnectionID] = session } err = session.HandlePacket(remoteAddr, data[0:n-r.Len()], publicHeader, r) @@ -86,3 +89,30 @@ func main() { } } } + +func handleStream(frame *quic.StreamFrame) *quic.StreamFrame { + h2r := bytes.NewReader(frame.Data) + var reply bytes.Buffer + h2framer := http2.NewFramer(&reply, h2r) + h2framer.ReadMetaHeaders = hpack.NewDecoder(1024, nil) + h2frame, err := h2framer.ReadFrame() + if err != nil { + return nil + } + h2headersFrame := h2frame.(*http2.MetaHeadersFrame) + fmt.Printf("%#v\n", h2headersFrame) + + var replyHeaders bytes.Buffer + enc := hpack.NewEncoder(&replyHeaders) + enc.WriteField(hpack.HeaderField{Name: ":status", Value: "204"}) + h2framer.WriteHeaders(http2.HeadersFrameParam{ + StreamID: h2frame.Header().StreamID, + EndHeaders: true, + BlockFragment: replyHeaders.Bytes(), + }) + + return &quic.StreamFrame{ + StreamID: frame.StreamID, + Data: reply.Bytes(), + } +} diff --git a/session.go b/session.go index 5a692ff12..452845ad6 100644 --- a/session.go +++ b/session.go @@ -6,14 +6,14 @@ import ( "fmt" "net" - "golang.org/x/net/http2" - "golang.org/x/net/http2/hpack" - "github.com/lucas-clemente/quic-go/crypto" "github.com/lucas-clemente/quic-go/handshake" "github.com/lucas-clemente/quic-go/protocol" ) +// StreamCallback gets a stream frame and returns a reply frame +type StreamCallback func(*StreamFrame) *StreamFrame + // A Session is a QUIC session type Session struct { ConnectionID protocol.ConnectionID @@ -27,15 +27,18 @@ type Session struct { Entropy EntropyAccumulator lastSentPacketNumber protocol.PacketNumber + + streamCallback StreamCallback } // NewSession makes a new session -func NewSession(conn *net.UDPConn, connectionID protocol.ConnectionID, sCfg *ServerConfig) *Session { +func NewSession(conn *net.UDPConn, connectionID protocol.ConnectionID, sCfg *ServerConfig, streamCallback StreamCallback) *Session { return &Session{ - Connection: conn, - ConnectionID: connectionID, - ServerConfig: sCfg, - aead: &crypto.NullAEAD{}, + Connection: conn, + ConnectionID: connectionID, + ServerConfig: sCfg, + aead: &crypto.NullAEAD{}, + streamCallback: streamCallback, } } @@ -70,7 +73,7 @@ func (s *Session) HandlePacket(addr *net.UDPAddr, publicHeaderBinary []byte, pub frameCounter++ fmt.Printf("Reading frame %d\n", frameCounter) - if typeByte&0x80 == 0x80 { // STREAM + if typeByte&0x80 > 0 { // STREAM fmt.Println("Detected STREAM") frame, err := ParseStreamFrame(r, typeByte) if err != nil { @@ -82,21 +85,17 @@ func (s *Session) HandlePacket(addr *net.UDPAddr, publicHeaderBinary []byte, pub return errors.New("Session: 0 is not a valid Stream ID") } - // TODO: Switch stream here if frame.StreamID == 1 { s.HandleCryptoHandshake(frame) } else { - h2r := bytes.NewReader(frame.Data) - h2framer := http2.NewFramer(nil, h2r) - h2framer.ReadMetaHeaders = hpack.NewDecoder(1024, nil) - h2frame, err := h2framer.ReadFrame() - if err != nil { - return err + replyFrame := s.streamCallback(frame) + replyFrames := []Frame{&AckFrame{Entropy: s.Entropy.Get(), LargestObserved: 3}} + if replyFrame != nil { + replyFrames = append(replyFrames, replyFrame) } - h2headersFrame := h2frame.(*http2.MetaHeadersFrame) - fmt.Printf("%#v\n", h2headersFrame) - panic("streamid not 1") + s.SendFrames(replyFrames) } + continue } else if typeByte&0xC0 == 0x40 { // ACK fmt.Println("Detected ACK") frame, err := ParseAckFrame(r, typeByte) @@ -106,18 +105,19 @@ func (s *Session) HandlePacket(addr *net.UDPAddr, publicHeaderBinary []byte, pub fmt.Printf("%#v\n", frame) - continue // not yet implemented + continue } else if typeByte&0xE0 == 0x20 { // CONGESTION_FEEDBACK return errors.New("Detected CONGESTION_FEEDBACK") } else if typeByte&0x06 == 0x06 { // STOP_WAITING fmt.Println("Detected STOP_WAITING") r.ReadByte() r.ReadByte() + continue } else if typeByte == 0 { // PAD return nil } - return errors.New("Session: invalid Frame Type Field") + return fmt.Errorf("Session: invalid frame type %x", typeByte) } return nil }