forked from quic-go/quic-go
94 lines
2.2 KiB
Go
94 lines
2.2 KiB
Go
package h2quic
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/lucas-clemente/quic-go"
|
|
"github.com/lucas-clemente/quic-go/protocol"
|
|
"github.com/lucas-clemente/quic-go/utils"
|
|
"golang.org/x/net/http2"
|
|
"golang.org/x/net/http2/hpack"
|
|
)
|
|
|
|
// Server is a HTTP2 server listening for QUIC connections
|
|
type Server struct {
|
|
server *quic.Server
|
|
handler http.Handler
|
|
}
|
|
|
|
// NewServer creates a new server instance
|
|
func NewServer(certPath string) (*Server, error) {
|
|
s := &Server{}
|
|
var err error
|
|
s.server, err = quic.NewServer(certPath+"cert.der", certPath+"key.der", s.handleStream)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return s, nil
|
|
}
|
|
|
|
// ListenAndServe listens on the network address and calls the handler.
|
|
func (s *Server) ListenAndServe(addr string, handler http.Handler) error {
|
|
if handler != nil {
|
|
s.handler = handler
|
|
} else {
|
|
s.handler = http.DefaultServeMux
|
|
}
|
|
return s.server.ListenAndServe(addr)
|
|
}
|
|
|
|
func (s *Server) handleStream(session *quic.Session, headerStream utils.Stream) {
|
|
hpackDecoder := hpack.NewDecoder(4096, nil)
|
|
h2framer := http2.NewFramer(nil, headerStream)
|
|
|
|
go func() {
|
|
for {
|
|
if err := s.handleRequest(session, headerStream, hpackDecoder, h2framer); err != nil {
|
|
fmt.Printf("error handling h2 request: %s\n", err.Error())
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (s *Server) handleRequest(session *quic.Session, headerStream utils.Stream, hpackDecoder *hpack.Decoder, h2framer *http2.Framer) error {
|
|
h2frame, err := h2framer.ReadFrame()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
h2headersFrame := h2frame.(*http2.HeadersFrame)
|
|
if !h2headersFrame.HeadersEnded() {
|
|
return errors.New("http2 header continuation not implemented")
|
|
}
|
|
headers, err := hpackDecoder.DecodeFull(h2headersFrame.HeaderBlockFragment())
|
|
if err != nil {
|
|
fmt.Printf("invalid http2 headers encoding: %s\n", err.Error())
|
|
return err
|
|
}
|
|
|
|
req, err := requestFromHeaders(headers)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("Request: %#v\n", req)
|
|
|
|
responseWriter := &responseWriter{
|
|
header: http.Header{},
|
|
headerStream: headerStream,
|
|
dataStreamID: protocol.StreamID(h2headersFrame.StreamID),
|
|
session: session,
|
|
}
|
|
|
|
go func() {
|
|
s.handler.ServeHTTP(responseWriter, req)
|
|
if responseWriter.dataStream != nil {
|
|
responseWriter.dataStream.Close()
|
|
}
|
|
}()
|
|
|
|
return nil
|
|
}
|