package goxy import ( "crypto/tls" "net/http" "net/http/httputil" "net/url" "strings" ) type Server struct { DataFile string SNI Route httpServer http.Server tlsServer http.Server } func NewServer(dataFile string) (*Server, error) { sni := make(SNI) server := &Server{ DataFile: dataFile, SNI: sni, Route: make(Route), httpServer: http.Server{ Addr: ":http", }, tlsServer: http.Server{ Addr: ":https", TLSConfig: &tls.Config{ GetCertificate: sni.GetCertificate, }, }, } if dataFile != "" { server.Load(dataFile) } RegisterRPC(server) http.Handle("/debug/route", server.Route) return server, server.Update() } // Update routes from in-memory state func (s *Server) Update() error { httpMux := http.NewServeMux() for k, v := range s.Route { if v.Cert != nil && v.Key != nil { cert, err := tls.X509KeyPair(v.Cert, v.Key) if err != nil { return err } s.SNI[k] = &cert } up, err := url.Parse(v.Upstream) if err != nil { return err } if !strings.Contains(v.Host, "/") { v.Host += "/" } switch up.Scheme { case "ws": httpMux.Handle(v.Host, NewWebSocketProxy(up)) default: httpMux.Handle(v.Host, httputil.NewSingleHostReverseProxy(up)) } } s.httpServer.Handler = httpMux return nil } func (s *Server) Start() error { errc := make(chan error) go func() { errc <- s.httpServer.ListenAndServe() }() go func() { errc <- s.tlsServer.ListenAndServeTLS("", "") }() go func() { errc <- http.ListenAndServe(":http-alt", nil) }() return <-errc }