in main.go [84:190]
func realMain(ctx context.Context) error {
// Quick handle version and help.
for _, v := range os.Args {
if v == "-v" || v == "-version" || v == "--version" {
fmt.Fprintln(os.Stdout, version.HumanVersion)
return nil
}
}
// Parse and validate flags.
flag.Parse()
var merr error
if *flagHost == "" {
merr = errors.Join(merr, fmt.Errorf("missing -host"))
}
if *flagBind == "" {
merr = errors.Join(merr, fmt.Errorf("missing -bind"))
}
if *flagAuthorizationHeader == "" {
merr = errors.Join(merr, fmt.Errorf("missing -authorization-header"))
}
var d time.Duration
if *flagServerUpTime != "" {
var err error
d, err = time.ParseDuration(*flagServerUpTime)
if err != nil {
merr = errors.Join(merr, fmt.Errorf("error parsing -server-up-time: %w", err))
}
}
if merr != nil {
return merr
}
// Build the remote host URL.
host, err := smartBuildHost(*flagHost)
if err != nil {
return fmt.Errorf("failed to parse host URL: %w", err)
}
// Compute the audience, default to the host. However, there might be cases
// where you want to specify a custom aud (such as when accessing through a
// load balancer).
audience := *flagAudience
if audience == "" {
audience = host.String()
}
// Get the best token source. Cloud Run expects the audience parameter to be
// the URL of the service.
tokenSource, err := findTokenSource(ctx, *flagToken, audience)
if err != nil {
return fmt.Errorf("failed to find token source: %w", err)
}
// Build the local bind URL.
bindHost, bindPort, err := net.SplitHostPort(*flagBind)
if err != nil {
return fmt.Errorf("failed to parse bind address: %w", err)
}
bind := &url.URL{
Scheme: "http",
Host: net.JoinHostPort(bindHost, bindPort),
}
// Construct the proxy.
proxy := buildProxy(host, bind, tokenSource, *flagHttp2, nil)
server := createServer(bind, proxy, *flagHttp2)
// Start server in background.
errCh := make(chan error, 1)
go func() {
fmt.Fprintf(os.Stderr, "%s proxies to %s\n", bind, host)
if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
select {
case errCh <- err:
default:
}
}
}()
// Wait for stop
if *flagServerUpTime != "" {
select {
case err := <-errCh:
return fmt.Errorf("server error: %w", err)
case <-time.After(d):
case <-ctx.Done():
fmt.Fprint(os.Stderr, "\nserver is shutting down...\n")
}
} else {
select {
case err := <-errCh:
return fmt.Errorf("server error: %w", err)
case <-ctx.Done():
fmt.Fprint(os.Stderr, "\nserver is shutting down...\n")
}
}
// Attempt graceful shutdown.
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
return fmt.Errorf("failed to shutdown server: %w", err)
}
return nil
}