Redirect HTTP to HTTPS: Regression in 1.10?

Below is some “redirect HTTP to HTTPS” code essentially as taken from several blogs / Q&As.

The issue I experience is that the first protocol to execute its ListenAndServe[TLS]() function blocks or hides the other. I.e. if TLS starts on port 443 first then I see no listener - and no response - on port 80. And vice-versa. The behaviour is the same on both Ubuntu 16.04 and Windows 10. I’m using 1.10.

Any help/advice/suggestions definitely appreciated,
Thanks!

package main

import (
   "crypto/tls"
   "fmt"
   "net/http"
   "log"
   "time"
)



func main() {
   //
   // Entire site is on HTTPS
   //
   smux := &http.ServeMux{}
   smux.HandleFunc( "/", func(w http.ResponseWriter, req *http.Request) { fmt.Fprintf( w, "Hello, world" ) } )

   tlsConfig := &tls.Config{
      // Causes servers to use Go's default ciphersuite preferences,
      // which are tuned to avoid attacks. Does nothing on clients.
      PreferServerCipherSuites: true,
      // Only use curves which have assembly implementations
      CurvePreferences: []tls.CurveID{
         tls.CurveP256,
         tls.X25519,
      },
      MinVersion: tls.VersionTLS12,
      CipherSuites: []uint16{
         tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
         tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
         tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
         tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
         tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
         tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,

         // Best disabled, as they don't provide Forward Secrecy,
         // but might be necessary for some clients
         // tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
         // tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
      },
      NextProtos: []string{"http/1.1"}, //"h2", 
   } // tlsConfig

   cert, err := tls.LoadX509KeyPair( ".\\tiers\\staging\\server.crt",
                                     ".\\tiers\\staging\\server.key" )
   if err != nil {
      log.Fatal( err )
   } // if
   tlsConfig.Certificates = append( tlsConfig.Certificates, cert )
   tlsConfig.BuildNameToCertificate()

   httpsServer := newServer()
   httpsServer.Addr = ":443"
   httpsServer.TLSConfig = tlsConfig
   httpsServer.TLSNextProto = make( map[string]func(*http.Server, *tls.Conn, http.Handler), 0 )
   httpsServer.Handler = smux

   go log.Println( httpsServer.ListenAndServeTLS( "", "" ) )



   //
   // Redirect all HTTP requests to HTTPS
   //
   httpServer := newServer()
   httpServer.Addr = ":80"
   httpServer.TLSConfig = &tls.Config{}
   hmux := &http.ServeMux{}
   hmux.HandleFunc( "/", func( w http.ResponseWriter, req *http.Request ) {
                           w.Header().Set( "Connection", "close" )
                           url := "https://" + req.Host + req.URL.String()
                           http.Redirect( w, req, url, http.StatusMovedPermanently )
                        })
   httpServer.Handler = hmux
   log.Println( httpServer.ListenAndServe() )
} // main



func newServer() *http.Server {
	// set timeouts so that a slow or malicious client doesn't
	// hold resources forever
	return &http.Server{
      ReadTimeout:         5 * time.Second,
      ReadHeaderTimeout:   4 * time.Second,
      WriteTimeout:       10 * time.Second,
      IdleTimeout:       120 * time.Second,
	}
} // newServer

Arguments are evaluated before the goroutine is started and your goroutine then calls log.Println(whatever gets returned by listen and serve). Since listen and serve is blocking, the goroutine is never started.

Try wrapping in a func or remove the log.println.

3 Likes

Thanks, that’s fixed it!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.