Skip to content
Snippets Groups Projects
Commit 524e33d1 authored by ale's avatar ale
Browse files

simplify the structure of the http server

parent 04b4f7d7
No related branches found
No related tags found
No related merge requests found
......@@ -99,10 +99,19 @@ func (h *HttpRedirector) serveSource(w http.ResponseWriter, r *http.Request) {
return
}
// Hijack the incoming connection. This is just so that we can
// reset the timeout on the underlying network connection
// (which we have no use for once the stream has been
// established), but then we get to run the two-way proxy...
// Hijack the incoming connection. This is necessary, rather
// than using httputil.ReverseProxy, for two important
// reasons:
//
// 1) So that we can reset the timeout on the underlying
// network connection (which we have no use for once the
// stream has been established).
//
// 2) Because streaming is still mostly a HTTP/1.0 world, the
// HTTP/1.1 features used by Go's net/http package (mostly the
// chunked encoding, I think) will apparently confuse clients
// and servers alike.
//
conn, _, err := w.(http.Hijacker).Hijack()
if err != nil {
log.Printf("source: hijack failed: %v", err)
......@@ -166,50 +175,52 @@ func (h *HttpRedirector) serveStatusPage(w http.ResponseWriter, r *http.Request)
w.Write(buf.Bytes())
}
func (h *HttpRedirector) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "" || r.URL.Path == "/" {
// Serve the status page through a GZIPHandler. Binds
// to h using function closure.
handler := handlers.GZIPHandler(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
h.serveStatusPage(w, r)
}), nil)
handler.ServeHTTP(w, r)
} else if r.Method == "SOURCE" {
h.serveSource(w, r)
} else {
h.serveRelay(w, r)
}
}
// Run starts the HTTP server on the given addr. Does not return.
func (h *HttpRedirector) Run(addr, staticDir, templateDir string) {
h.template = template.Must(
template.ParseGlob(
filepath.Join(templateDir, "*.html")))
// The purpose of the odd usage of GZIPHandler is to bypass it
// on SOURCE and m3u requests. May not be necessary though.
// Create our HTTP handler stack. Passes the /debug/ queries
// along to the global ServeMux (where moodules such as pprof
// install their handlers).
mux := http.NewServeMux()
mux.HandleFunc(
mux.Handle(
"/static/",
handlers.GZIPHandler(
http.StripPrefix(
"/static/",
http.FileServer(http.Dir(staticDir))),
nil))
mux.Handle("/", h)
// It would be nice to add a logging handler on top of
// everything, but we would become unable to hijack the
// connection on SOURCE requests...
//
//logopts := handlers.NewLogOptions(nil, handlers.Lshort)
//logger := handlers.LogHandler(mux, logopts)
http.StripPrefix(
"/static/",
http.FileServer(http.Dir(staticDir))))
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
switch {
case r.URL.Path == "" || r.URL.Path == "/":
h.serveStatusPage(w, r)
case strings.HasPrefix(r.URL.Path, "/debug/"):
http.DefaultServeMux.ServeHTTP(w, r)
default:
h.serveRelay(w, r)
}
})
// Add some handlers to support gzip-encoded responses and
// request logging.
wraph := handlers.GZIPHandler(mux, nil)
logopts := handlers.NewLogOptions(nil, handlers.Lshort)
wraph = handlers.LogHandler(wraph, logopts)
// Serve SOURCE requests bypassing the logging and gzip
// handlers: since they wrap the ResponseWriter, we would be
// unable to hijack the underlying connection for proxying.
rooth := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "SOURCE" {
h.serveSource(w, r)
} else {
wraph.ServeHTTP(w, r)
}
})
httpServer := &http.Server{
Addr: addr,
Handler: mux,
Handler: rooth,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment