package main import ( "bufio" "bytes" "context" "crypto/x509" "flag" "fmt" "io" "log" "net/http" "os" "sync" tls "github.com/refraction-networking/utls" quic "github.com/refraction-networking/uquic" "github.com/refraction-networking/uquic/http3" "github.com/refraction-networking/uquic/internal/testdata" "github.com/refraction-networking/uquic/internal/utils" "github.com/refraction-networking/uquic/logging" "github.com/refraction-networking/uquic/qlog" ) func main() { verbose := flag.Bool("v", false, "verbose") quiet := flag.Bool("q", false, "don't print the data") keyLogFile := flag.String("keylog", "", "key log file") insecure := flag.Bool("insecure", false, "skip certificate verification") enableQlog := flag.Bool("qlog", false, "output a qlog (in the same directory)") flag.Parse() urls := flag.Args() logger := utils.DefaultLogger if *verbose { logger.SetLogLevel(utils.LogLevelDebug) } else { logger.SetLogLevel(utils.LogLevelInfo) } logger.SetLogTimeFormat("") var keyLog io.Writer if len(*keyLogFile) > 0 { f, err := os.Create(*keyLogFile) if err != nil { log.Fatal(err) } defer f.Close() keyLog = f } pool, err := x509.SystemCertPool() if err != nil { log.Fatal(err) } testdata.AddRootCA(pool) var qconf quic.Config if *enableQlog { qconf.Tracer = func(ctx context.Context, p logging.Perspective, connID quic.ConnectionID) *logging.ConnectionTracer { filename := fmt.Sprintf("client_%x.qlog", connID) f, err := os.Create(filename) if err != nil { log.Fatal(err) } log.Printf("Creating qlog file %s.\n", filename) return qlog.NewConnectionTracer(utils.NewBufferedWriteCloser(bufio.NewWriter(f), f), p, connID) } } roundTripper := &http3.RoundTripper{ TLSClientConfig: &tls.Config{ RootCAs: pool, InsecureSkipVerify: *insecure, KeyLogWriter: keyLog, }, QuicConfig: &qconf, } defer roundTripper.Close() hclient := &http.Client{ Transport: roundTripper, } var wg sync.WaitGroup wg.Add(len(urls)) for _, addr := range urls { logger.Infof("GET %s", addr) go func(addr string) { rsp, err := hclient.Get(addr) if err != nil { log.Fatal(err) } logger.Infof("Got response for %s: %#v", addr, rsp) body := &bytes.Buffer{} _, err = io.Copy(body, rsp.Body) if err != nil { log.Fatal(err) } if *quiet { logger.Infof("Response Body: %d bytes", body.Len()) } else { logger.Infof("Response Body:") logger.Infof("%s", body.Bytes()) } wg.Done() }(addr) } wg.Wait() }