diff options
Diffstat (limited to 'src/cmd/go/internal/vcweb/vcstest/vcstest.go')
-rw-r--r-- | src/cmd/go/internal/vcweb/vcstest/vcstest.go | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/src/cmd/go/internal/vcweb/vcstest/vcstest.go b/src/cmd/go/internal/vcweb/vcstest/vcstest.go new file mode 100644 index 0000000..d460259 --- /dev/null +++ b/src/cmd/go/internal/vcweb/vcstest/vcstest.go @@ -0,0 +1,169 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package vcstest serves the repository scripts in cmd/go/testdata/vcstest +// using the [vcweb] script engine. +package vcstest + +import ( + "cmd/go/internal/vcs" + "cmd/go/internal/vcweb" + "cmd/go/internal/web" + "crypto/tls" + "crypto/x509" + "encoding/pem" + "fmt" + "internal/testenv" + "io" + "log" + "net/http" + "net/http/httptest" + "net/url" + "os" + "path/filepath" + "testing" +) + +var Hosts = []string{ + "vcs-test.golang.org", +} + +type Server struct { + vcweb *vcweb.Server + workDir string + HTTP *httptest.Server + HTTPS *httptest.Server +} + +// NewServer returns a new test-local vcweb server that serves VCS requests +// for modules with paths that begin with "vcs-test.golang.org" using the +// scripts in cmd/go/testdata/vcstest. +func NewServer() (srv *Server, err error) { + if vcs.VCSTestRepoURL != "" { + panic("vcs URL hooks already set") + } + + scriptDir := filepath.Join(testenv.GOROOT(nil), "src/cmd/go/testdata/vcstest") + + workDir, err := os.MkdirTemp("", "vcstest") + if err != nil { + return nil, err + } + defer func() { + if err != nil { + os.RemoveAll(workDir) + } + }() + + logger := log.Default() + if !testing.Verbose() { + logger = log.New(io.Discard, "", log.LstdFlags) + } + handler, err := vcweb.NewServer(scriptDir, workDir, logger) + if err != nil { + return nil, err + } + defer func() { + if err != nil { + handler.Close() + } + }() + + srvHTTP := httptest.NewServer(handler) + httpURL, err := url.Parse(srvHTTP.URL) + if err != nil { + return nil, err + } + defer func() { + if err != nil { + srvHTTP.Close() + } + }() + + srvHTTPS := httptest.NewTLSServer(handler) + httpsURL, err := url.Parse(srvHTTPS.URL) + if err != nil { + return nil, err + } + defer func() { + if err != nil { + srvHTTPS.Close() + } + }() + + srv = &Server{ + vcweb: handler, + workDir: workDir, + HTTP: srvHTTP, + HTTPS: srvHTTPS, + } + vcs.VCSTestRepoURL = srv.HTTP.URL + vcs.VCSTestHosts = Hosts + + var interceptors []web.Interceptor + for _, host := range Hosts { + interceptors = append(interceptors, + web.Interceptor{Scheme: "http", FromHost: host, ToHost: httpURL.Host, Client: srv.HTTP.Client()}, + web.Interceptor{Scheme: "https", FromHost: host, ToHost: httpsURL.Host, Client: srv.HTTPS.Client()}) + } + web.EnableTestHooks(interceptors) + + fmt.Fprintln(os.Stderr, "vcs-test.golang.org rerouted to "+srv.HTTP.URL) + fmt.Fprintln(os.Stderr, "https://vcs-test.golang.org rerouted to "+srv.HTTPS.URL) + + return srv, nil +} + +func (srv *Server) Close() error { + if vcs.VCSTestRepoURL != srv.HTTP.URL { + panic("vcs URL hooks modified before Close") + } + vcs.VCSTestRepoURL = "" + vcs.VCSTestHosts = nil + web.DisableTestHooks() + + srv.HTTP.Close() + srv.HTTPS.Close() + err := srv.vcweb.Close() + if rmErr := os.RemoveAll(srv.workDir); err == nil { + err = rmErr + } + return err +} + +func (srv *Server) WriteCertificateFile() (string, error) { + b := pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: srv.HTTPS.Certificate().Raw, + }) + + filename := filepath.Join(srv.workDir, "cert.pem") + if err := os.WriteFile(filename, b, 0644); err != nil { + return "", err + } + return filename, nil +} + +// TLSClient returns an http.Client that can talk to the httptest.Server +// whose certificate is written to the given file path. +func TLSClient(certFile string) (*http.Client, error) { + client := &http.Client{ + Transport: http.DefaultTransport.(*http.Transport).Clone(), + } + + pemBytes, err := os.ReadFile(certFile) + if err != nil { + return nil, err + } + + certpool := x509.NewCertPool() + if !certpool.AppendCertsFromPEM(pemBytes) { + return nil, fmt.Errorf("no certificates found in %s", certFile) + } + client.Transport.(*http.Transport).TLSClientConfig = &tls.Config{ + RootCAs: certpool, + } + + return client, nil +} |