// HandleNotFound handles pages not found. In particular, this handler is used // when we have no matching route for a request. This also means it's not // useful to inject the livereload paraphernalia here. func HandleNotFound(templates *template.Template) httpctx.Handler { return httpctx.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) err := templates.Lookup("404.html").Execute(w, nil) if err != nil { logger := termlog.FromContext(ctx) logger.Shout("Could not execute template: %s", err) } }) }
// ServeHTTPContext is like ServeHTTP, but with added context func (fserver *FileServer) ServeHTTPContext( ctx context.Context, w http.ResponseWriter, r *http.Request, ) { logger := termlog.FromContext(ctx) logger.SayAs("debug", "debug fileserver: serving with FileServer...") upath := r.URL.Path if !strings.HasPrefix(upath, "/") { upath = "/" + upath r.URL.Path = upath } fserver.serveFile(logger, w, r, path.Clean(upath), true) }
// ServeHTTPContext serves HTTP with a context func (p *ReverseProxy) ServeHTTPContext( ctx context.Context, rw http.ResponseWriter, req *http.Request, ) { log := termlog.FromContext(ctx) transport := p.Transport if transport == nil { transport = http.DefaultTransport } outreq := new(http.Request) *outreq = *req // includes shallow copies of maps, but okay p.Director(outreq) outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 outreq.ProtoMinor = 1 outreq.Close = false // Remove hop-by-hop headers to the backend. Especially // important is "Connection" because we want a persistent // connection, regardless of what the client sent to us. This // is modifying the same underlying map from req (shallow // copied above) so we only copy it if necessary. copiedHeaders := false for _, h := range hopHeaders { if outreq.Header.Get(h) != "" { if !copiedHeaders { outreq.Header = make(http.Header) copyHeader(outreq.Header, req.Header) copiedHeaders = true } outreq.Header.Del(h) } } if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { // If we aren't the first proxy retain prior // X-Forwarded-For information as a comma+space // separated list and fold multiple headers into one. if prior, ok := outreq.Header["X-Forwarded-For"]; ok { clientIP = strings.Join(prior, ", ") + ", " + clientIP } outreq.Header.Set("X-Forwarded-For", clientIP) } res, err := transport.RoundTrip(outreq) if err != nil { log.Shout("reverse proxy error: %v", err) rw.WriteHeader(http.StatusInternalServerError) return } defer res.Body.Close() inject, err := p.Inject.Sniff(res.Body) if err != nil { log.Shout("reverse proxy error: %v", err) rw.WriteHeader(http.StatusInternalServerError) return } if inject.Found { cl, err := strconv.ParseInt(res.Header.Get("Content-Length"), 10, 32) if err == nil { cl = cl + int64(inject.Extra()) res.Header.Set("Content-Length", strconv.FormatInt(cl, 10)) } } copyHeader(rw.Header(), res.Header) rw.WriteHeader(res.StatusCode) p.copyResponse(rw, inject) }