package goxy import ( "crypto/tls" "encoding/json" "errors" "fmt" "net/http" "net/url" "os" ) // Route defines a set of routes including correspondent TLS certificates type Route map[string]route type route struct { ServerName *url.URL Upstream *url.URL Certificate *tls.Certificate } func (r route) String() string { return fmt.Sprintf("%v → %v", r.ServerName, r.Upstream) } // GetCertificate returns certificate for SNI negotiation func (r Route) GetCertificate(h *tls.ClientHelloInfo) (*tls.Certificate, error) { host := h.ServerName if v, ok := r[host]; ok && v.Certificate != nil { return v.Certificate, nil } // HACK search for certs with port speciefied for k, v := range r { if k[:len(host)] == host { return v.Certificate, nil } } return nil, errors.New("no cert for " + host) } // Save routes to persistent file func (r Route) Save(fname string) error { fd, err := os.Create(fname) if err != nil { return err } defer fd.Close() return json.NewEncoder(fd).Encode(r) } // Load routes from persistent file func (r *Route) Load(fname string) error { fd, err := os.Open(fname) if err != nil { return err } defer fd.Close() return json.NewDecoder(fd).Decode(r) } func (r Route) ServeHTTP(w http.ResponseWriter, _ *http.Request) { for _, v := range r { fmt.Fprintln(w, v) } }