77 "net"
88 "net/http"
99 "sync"
10+ "time"
1011
1112 "github.com/int128/listener"
1213 "golang.org/x/sync/errgroup"
@@ -27,34 +28,13 @@ func receiveCodeViaLocalServer(ctx context.Context, c *Config) (string, error) {
2728 respCh : respCh ,
2829 }),
2930 }
31+ shutdownCh := make (chan struct {})
3032 var resp * authorizationResponse
3133 var eg errgroup.Group
32- eg .Go (func () error {
33- select {
34- case gotResp , ok := <- respCh :
35- if ! ok {
36- c .Logf ("oauth2cli: response channel has been closed" )
37- return nil
38- }
39- resp = gotResp
40- c .Logf ("oauth2cli: shutting down the server at %s" , l .Addr ())
41- if err := server .Shutdown (ctx ); err != nil {
42- return fmt .Errorf ("could not shutdown the local server: %w" , err )
43- }
44- return nil
45- case <- ctx .Done ():
46- c .Logf ("oauth2cli: context cancelled: %s" , ctx .Err ())
47- c .Logf ("oauth2cli: shutting down the server at %s" , l .Addr ())
48- if err := server .Shutdown (ctx ); err != nil {
49- return fmt .Errorf ("could not shutdown the local server: %w" , err )
50- }
51- return fmt .Errorf ("context cancelled while waiting for authorization response: %w" , ctx .Err ())
52- }
53- })
5434 eg .Go (func () error {
5535 defer close (respCh )
56- c .Logf ("oauth2cli: starting a local server at %s" , l .Addr ())
57- defer c .Logf ("oauth2cli: stopped the local server at %s" , l . Addr () )
36+ c .Logf ("oauth2cli: starting a server at %s" , l .Addr ())
37+ defer c .Logf ("oauth2cli: stopped the server" )
5838 if c .isLocalServerHTTPS () {
5939 if err := server .ServeTLS (l , c .LocalServerCertFile , c .LocalServerKeyFile ); err != nil && err != http .ErrServerClosed {
6040 return fmt .Errorf ("could not start HTTPS server: %w" , err )
@@ -66,13 +46,39 @@ func receiveCodeViaLocalServer(ctx context.Context, c *Config) (string, error) {
6646 }
6747 return nil
6848 })
49+ eg .Go (func () error {
50+ defer close (shutdownCh )
51+ select {
52+ case gotResp , ok := <- respCh :
53+ if ok {
54+ resp = gotResp
55+ }
56+ return nil
57+ case <- ctx .Done ():
58+ return ctx .Err ()
59+ }
60+ })
61+ eg .Go (func () error {
62+ <- shutdownCh
63+ // Gracefully shutdown the server in the timeout.
64+ // If the server has not started, Shutdown returns nil and this returns immediately.
65+ // If Shutdown has failed, force-close the server.
66+ c .Logf ("oauth2cli: shutting down the server" )
67+ ctx , cancel := context .WithTimeout (ctx , 500 * time .Millisecond )
68+ defer cancel ()
69+ if err := server .Shutdown (ctx ); err != nil {
70+ c .Logf ("oauth2cli: force-closing the server: shutdown failed: %s" , err )
71+ _ = server .Close ()
72+ return nil
73+ }
74+ return nil
75+ })
6976 eg .Go (func () error {
7077 if c .LocalServerReadyChan == nil {
7178 return nil
7279 }
7380 select {
7481 case c .LocalServerReadyChan <- c .OAuth2Config .RedirectURL :
75- c .Logf ("oauth2cli: wrote a URL to LocalServerReadyChan: %s" , c .OAuth2Config .RedirectURL )
7682 return nil
7783 case <- ctx .Done ():
7884 return ctx .Err ()
0 commit comments