Example #1
0
// 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")
	}
}
Example #2
0
// Creates a Goji *web.Mux that can act as the http muxer for the frontend app.
func NewMux() *web.Mux {
	m := web.New()

	m.Use(log.NewHTTPLogger("webapp"))
	m.Get("/sock", openSocket)
	m.Get("/message/:mid", getMessage)
	m.Get("/*", http.StripPrefix("/", http.FileServer(http.Dir(publicDir))))

	return m
}
Example #3
0
func TestNoCache(t *testing.T) {

	rr := httptest.NewRecorder()
	s := web.New()

	s.Use(NoCache)
	r, err := http.NewRequest("GET", "/", nil)
	if err != nil {
		t.Fatal(err)
	}

	s.ServeHTTP(rr, r)

	for k, v := range noCacheHeaders {
		if rr.HeaderMap[k][0] != v {
			t.Errorf("%s header not set by middleware.", k)
		}
	}
}
Example #4
0
// 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")
	}
}
Example #5
0
// 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
}