// Run sets up and runs the proxying HTTP server, then blocks. func (s *srv) Run(cmd *cobra.Command, args []string) { if s.vflag { fmt.Println("pvproxy version", version.Version()) return } setUpLogging(s) mux := web.New() cl := newClient(s.target, 5*time.Second) mux.Use(log.NewHTTPLogger("pvproxy")) if s.key != "" && s.cert == "" { s.cert = s.key + ".crt" } useTLS := s.key != "" && s.cert != "" if useTLS { sec := secure.New(secure.Options{ AllowedHosts: nil, // TODO allow a way to declare these SSLRedirect: false, // we have just one port to work with, so an internal redirect can't work SSLTemporaryRedirect: false, // Use 301, not 302 SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"}, // list of headers that indicate we're using TLS (which would have been set by TLS-terminating proxy) STSSeconds: 315360000, // 1yr HSTS time, as is generally recommended STSIncludeSubdomains: false, // don't include subdomains; it may not be correct in general case TODO allow config STSPreload: false, // can't know if this is correct for general case TODO allow config FrameDeny: true, // proxy is write-only, no reason this should ever happen ContentTypeNosniff: true, // again, write-only BrowserXssFilter: true, // again, write-only }) mux.Use(sec.Handler) } mux.Post("/github/push", githubIngestor(cl, cmd)) var addr string if s.bindAll { addr = ":" + strconv.Itoa(s.port) } else { addr = s.bind + ":" + strconv.Itoa(s.port) } var err error if useTLS { err = graceful.ListenAndServeTLS(addr, s.cert, s.key, mux) } else { err = graceful.ListenAndServe(addr, mux) } if err != nil { logrus.WithFields(logrus.Fields{ "system": "pvproxy", "err": err, }).Fatal("pvproxy httpd terminated") } }
// RunWebapp runs the pipeviz http frontend webapp on the specified address. // // This blocks on the http listening loop, so it should typically be called in its own goroutine. func RunWebapp(addr, key, cert string, f mlog.RecordGetter) { mf := web.New() useTLS := key != "" && cert != "" if useTLS { sec := secure.New(secure.Options{ AllowedHosts: nil, // TODO allow a way to declare these SSLRedirect: false, // we have just one port to work with, so an internal redirect can't work SSLTemporaryRedirect: false, // Use 301, not 302 SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"}, // list of headers that indicate we're using TLS (which would have been set by TLS-terminating proxy) STSSeconds: 315360000, // 1yr HSTS time, as is generally recommended STSIncludeSubdomains: false, // don't include subdomains; it may not be correct in general case TODO allow config STSPreload: false, // can't know if this is correct for general case TODO allow config FrameDeny: false, // pipeviz is exactly the kind of thing where embedding is appropriate ContentTypeNosniff: true, // shouldn't be an issue for pipeviz, but doesn't hurt...probably? BrowserXssFilter: false, // really shouldn't be necessary for pipeviz }) mf.Use(func(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { err := sec.Process(w, r) // If there was an error, do not continue. if err != nil { log.WithFields(log.Fields{ "system": "webapp", "err": err, }).Warn("Error from security middleware, dropping request") return } h.ServeHTTP(w, r) }) }) } // A middleware to attach the mlog-getting func to the env for later use. mf.Use(func(c *web.C, h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if c.Env == nil { c.Env = make(map[interface{}]interface{}) } c.Env["mlogGet"] = f h.ServeHTTP(w, r) }) }) webapp.RegisterToMux(mf) mf.Compile() var err error if useTLS { err = graceful.ListenAndServeTLS(addr, cert, key, mf) } else { err = graceful.ListenAndServe(addr, mf) } if err != nil { log.WithFields(log.Fields{ "system": "webapp", "err": err, }).Fatal("ListenAndServe returned with an error") } }
// ListenAndServe initiates the webapp http listener. // // This blocks on the http listening loop, so it should typically be called in its own goroutine. func (s *WebAppServer) ListenAndServe(addr, pubdir, key, cert string, showVersion bool) { mf := web.New() useTLS := key != "" && cert != "" mf.Use(log.NewHTTPLogger("webapp")) if useTLS { sec := secure.New(secure.Options{ AllowedHosts: nil, // TODO allow a way to declare these SSLRedirect: false, // we have just one port to work with, so an internal redirect can't work SSLTemporaryRedirect: false, // Use 301, not 302 SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"}, // list of headers that indicate we're using TLS (which would have been set by TLS-terminating proxy) STSSeconds: 315360000, // 1yr HSTS time, as is generally recommended STSIncludeSubdomains: false, // don't include subdomains; it may not be correct in general case TODO allow config STSPreload: false, // can't know if this is correct for general case TODO allow config FrameDeny: false, // pipeviz is exactly the kind of thing where embedding is appropriate ContentTypeNosniff: true, // shouldn't be an issue for pipeviz, but doesn't hurt...probably? BrowserXssFilter: false, // really shouldn't be necessary for pipeviz }) mf.Use(func(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { err := sec.Process(w, r) // If there was an error, do not continue. if err != nil { logrus.WithFields(logrus.Fields{ "system": "webapp", "err": err, }).Warn("Error from security middleware, dropping request") return } h.ServeHTTP(w, r) }) }) } // If showing version, add a middleware to do it automatically for everything if showVersion { mf.Use(func(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Server", version.Version()) h.ServeHTTP(w, r) }) }) } mf.Get("/sock", s.openSocket) mf.Get("/message/:mid", s.getMessage) mf.Get("/*", http.StripPrefix("/", http.FileServer(http.Dir(pubdir)))) mf.Compile() // kick off a goroutine to grab the latest graph and listen for cancel go func() { var g system.CoreGraph for { select { case <-s.cancel: s.unsub(s.receiver) return case g = <-s.receiver: s.latest = g } } }() var err error if useTLS { err = graceful.ListenAndServeTLS(addr, cert, key, mf) } else { err = graceful.ListenAndServe(addr, mf) } if err != nil { logrus.WithFields(logrus.Fields{ "system": "webapp", "err": err, }).Fatal("ListenAndServe returned with an error") } // TODO allow returning err }