diff --git a/.gitignore b/.gitignore index 040b55ac..bb3fe209 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ debug debug.test main +*.qtr diff --git a/example/main.go b/example/main.go index 1fe59b56..007fe77d 100644 --- a/example/main.go +++ b/example/main.go @@ -10,16 +10,19 @@ import ( "log" "mime/multipart" "net/http" + "os" "strconv" "strings" "sync" _ "net/http/pprof" + "github.com/lucas-clemente/quic-go" "github.com/lucas-clemente/quic-go/http3" "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" "github.com/lucas-clemente/quic-go/internal/testdata" "github.com/lucas-clemente/quic-go/internal/utils" + "github.com/lucas-clemente/quic-go/quictrace" ) type binds []string @@ -38,8 +41,49 @@ type Size interface { Size() int64 } +var tracer quictrace.Tracer + func init() { - http.HandleFunc("/demo/tile", func(w http.ResponseWriter, r *http.Request) { + tracer = quictrace.NewTracer() +} + +func exportTraces() error { + traces := tracer.GetAllTraces() + if len(traces) != 1 { + return errors.New("expected exactly one trace") + } + for _, trace := range traces { + f, err := os.Create("trace.qtr") + if err != nil { + return err + } + if _, err := f.Write(trace); err != nil { + return err + } + f.Close() + fmt.Println("Wrote trace to", f.Name()) + } + return nil +} + +type tracingHandler struct { + handler http.Handler +} + +var _ http.Handler = &tracingHandler{} + +func (h *tracingHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + h.handler.ServeHTTP(w, r) + if err := exportTraces(); err != nil { + panic(err) + } +} + +func setupHandler(www string, trace bool) http.Handler { + mux := http.NewServeMux() + + mux.Handle("/", http.FileServer(http.Dir(www))) + mux.HandleFunc("/demo/tile", func(w http.ResponseWriter, r *http.Request) { // Small 40x40 png w.Write([]byte{ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, @@ -52,7 +96,7 @@ func init() { }) }) - http.HandleFunc("/demo/tiles", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/demo/tiles", func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "") for i := 0; i < 200; i++ { fmt.Fprintf(w, ``, i) @@ -60,7 +104,7 @@ func init() { io.WriteString(w, "") }) - http.HandleFunc("/demo/echo", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/demo/echo", func(w http.ResponseWriter, r *http.Request) { body, err := ioutil.ReadAll(r.Body) if err != nil { fmt.Printf("error reading body while handling /echo: %s\n", err.Error()) @@ -70,7 +114,7 @@ func init() { // accept file uploads and return the MD5 of the uploaded file // maximum accepted file size is 1 GB - http.HandleFunc("/demo/upload", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/demo/upload", func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodPost { err := r.ParseMultipartForm(1 << 30) // 1 GB if err == nil { @@ -98,6 +142,21 @@ func init() { `) }) + + http.HandleFunc("/dynamic/", func(w http.ResponseWriter, r *http.Request) { + const maxSize = 1 << 30 // 1 GB + num, err := strconv.ParseInt(strings.ReplaceAll(r.RequestURI, "/dynamic/", ""), 10, 64) + if err != nil || num <= 0 || num > maxSize { + w.WriteHeader(400) + return + } + w.Write(testserver.GeneratePRData(int(num))) + }) + + if !trace { + return mux + } + return &tracingHandler{handler: mux} } func main() { @@ -112,6 +171,7 @@ func main() { flag.Var(&bs, "bind", "bind to") www := flag.String("www", "/var/www", "www data") tcp := flag.Bool("tcp", false, "also listen on TCP") + trace := flag.Bool("trace", false, "enable quic-trace") flag.Parse() logger := utils.DefaultLogger @@ -123,21 +183,16 @@ func main() { } logger.SetLogTimeFormat("") - http.Handle("/", http.FileServer(http.Dir(*www))) - http.HandleFunc("/dynamic/", func(w http.ResponseWriter, r *http.Request) { - const maxSize = 1 << 30 // 1 GB - num, err := strconv.ParseInt(strings.ReplaceAll(r.RequestURI, "/dynamic/", ""), 10, 64) - if err != nil || num <= 0 || num > maxSize { - w.WriteHeader(400) - return - } - w.Write(testserver.GeneratePRData(int(num))) - }) - if len(bs) == 0 { bs = binds{"localhost:6121"} } + handler := setupHandler(*www, *trace) + var quicConf *quic.Config + if *trace { + quicConf = &quic.Config{QuicTracer: tracer} + } + var wg sync.WaitGroup wg.Add(len(bs)) for _, b := range bs { @@ -149,7 +204,8 @@ func main() { err = http3.ListenAndServe(bCap, certFile, keyFile, nil) } else { server := http3.Server{ - Server: &http.Server{Addr: bCap}, + Server: &http.Server{Handler: handler, Addr: bCap}, + QuicConfig: quicConf, } err = server.ListenAndServeTLS(testdata.GetCertificatePaths()) }