Пример #1
0
// 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)
		}
	})
}
Пример #2
0
// 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 := stripPrefix(fserver.Prefix, r.URL.Path)
	if !strings.HasPrefix(upath, "/") {
		upath = "/" + upath
	}
	fserver.serveFile(logger, w, r, path.Clean(upath), true)
}
Пример #3
0
func (p *ReverseProxy) copyResponse(ctx context.Context, dst io.Writer, inject *inject.Injector) {
	log := termlog.FromContext(ctx)
	if p.FlushInterval != 0 {
		if wf, ok := dst.(writeFlusher); ok {
			mlw := &maxLatencyWriter{
				dst:     wf,
				latency: p.FlushInterval,
				done:    make(chan bool),
			}
			go mlw.flushLoop()
			defer mlw.stop()
			dst = mlw
		}
	}
	_, err := inject.Copy(dst)
	if err != nil {
		log.Shout("Error forwarding data: %s", err)
	}
}
Пример #4
0
// 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()
	if req.ContentLength > 0 {
		log.Say(fmt.Sprintf("%s uploaded", humanize.Bytes(uint64(req.ContentLength))))
	}

	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(ctx, rw, inject)
}