github.com/danielpfeifer02/quic-go-prio-packs@v0.41.0-28/interop/http09/server.go (about) 1 package http09 2 3 import ( 4 "context" 5 "errors" 6 "io" 7 "log" 8 "net" 9 "net/http" 10 "net/url" 11 "runtime" 12 "strings" 13 "sync" 14 15 "github.com/danielpfeifer02/quic-go-prio-packs" 16 ) 17 18 const h09alpn = "hq-interop" 19 20 type responseWriter struct { 21 io.Writer 22 headers http.Header 23 } 24 25 var _ http.ResponseWriter = &responseWriter{} 26 27 func (w *responseWriter) Header() http.Header { 28 if w.headers == nil { 29 w.headers = make(http.Header) 30 } 31 return w.headers 32 } 33 34 func (w *responseWriter) WriteHeader(int) {} 35 36 // Server is a HTTP/0.9 server listening for QUIC connections. 37 type Server struct { 38 *http.Server 39 40 ForceRetry bool 41 QuicConfig *quic.Config 42 43 mutex sync.Mutex 44 listener *quic.EarlyListener 45 } 46 47 // Close closes the server. 48 func (s *Server) Close() error { 49 s.mutex.Lock() 50 defer s.mutex.Unlock() 51 52 return s.listener.Close() 53 } 54 55 // ListenAndServe listens and serves HTTP/0.9 over QUIC. 56 func (s *Server) ListenAndServe() error { 57 if s.Server == nil { 58 return errors.New("use of http3.Server without http.Server") 59 } 60 61 udpAddr, err := net.ResolveUDPAddr("udp", s.Addr) 62 if err != nil { 63 return err 64 } 65 conn, err := net.ListenUDP("udp", udpAddr) 66 if err != nil { 67 return err 68 } 69 70 tlsConf := s.TLSConfig.Clone() 71 tlsConf.NextProtos = []string{h09alpn} 72 tr := quic.Transport{Conn: conn} 73 if s.ForceRetry { 74 tr.MaxUnvalidatedHandshakes = -1 75 } 76 ln, err := tr.ListenEarly(tlsConf, s.QuicConfig) 77 if err != nil { 78 return err 79 } 80 s.mutex.Lock() 81 s.listener = ln 82 s.mutex.Unlock() 83 84 for { 85 conn, err := ln.Accept(context.Background()) 86 if err != nil { 87 return err 88 } 89 go s.handleConn(conn) 90 } 91 } 92 93 func (s *Server) handleConn(conn quic.Connection) { 94 for { 95 str, err := conn.AcceptStream(context.Background()) 96 if err != nil { 97 log.Printf("Error accepting stream: %s\n", err.Error()) 98 return 99 } 100 go func() { 101 if err := s.handleStream(str); err != nil { 102 log.Printf("Handling stream failed: %s\n", err.Error()) 103 } 104 }() 105 } 106 } 107 108 func (s *Server) handleStream(str quic.Stream) error { 109 reqBytes, err := io.ReadAll(str) 110 if err != nil { 111 return err 112 } 113 request := string(reqBytes) 114 request = strings.TrimRight(request, "\r\n") 115 request = strings.TrimRight(request, " ") 116 117 log.Printf("Received request: %s\n", request) 118 119 if request[:5] != "GET /" { 120 str.CancelWrite(42) 121 return nil 122 } 123 124 u, err := url.Parse(request[4:]) 125 if err != nil { 126 return err 127 } 128 u.Scheme = "https" 129 130 req := &http.Request{ 131 Method: http.MethodGet, 132 Proto: "HTTP/0.9", 133 ProtoMajor: 0, 134 ProtoMinor: 9, 135 Body: str, 136 URL: u, 137 } 138 139 handler := s.Handler 140 if handler == nil { 141 handler = http.DefaultServeMux 142 } 143 144 var panicked bool 145 func() { 146 defer func() { 147 if p := recover(); p != nil { 148 // Copied from net/http/server.go 149 const size = 64 << 10 150 buf := make([]byte, size) 151 buf = buf[:runtime.Stack(buf, false)] 152 log.Printf("http: panic serving: %v\n%s", p, buf) 153 panicked = true 154 } 155 }() 156 handler.ServeHTTP(&responseWriter{Writer: str}, req) 157 }() 158 159 if panicked { 160 if _, err := str.Write([]byte("500")); err != nil { 161 return err 162 } 163 } 164 return str.Close() 165 }