1package httprp
2
3import (
4	"context"
5	"net/http"
6	"net/http/httputil"
7	"net/url"
8)
9
10// RequestFunc may take information from an HTTP request and put it into a
11// request context. BeforeFuncs are executed prior to invoking the
12// endpoint.
13type RequestFunc func(context.Context, *http.Request) context.Context
14
15// Server is a proxying request handler.
16type Server struct {
17	proxy        http.Handler
18	before       []RequestFunc
19	errorEncoder func(w http.ResponseWriter, err error)
20}
21
22// NewServer constructs a new server that implements http.Server and will proxy
23// requests to the given base URL using its scheme, host, and base path.
24// If the target's path is "/base" and the incoming request was for "/dir",
25// the target request will be for /base/dir.
26func NewServer(
27	baseURL *url.URL,
28	options ...ServerOption,
29) *Server {
30	s := &Server{
31		proxy: httputil.NewSingleHostReverseProxy(baseURL),
32	}
33	for _, option := range options {
34		option(s)
35	}
36	return s
37}
38
39// ServerOption sets an optional parameter for servers.
40type ServerOption func(*Server)
41
42// ServerBefore functions are executed on the HTTP request object before the
43// request is decoded.
44func ServerBefore(before ...RequestFunc) ServerOption {
45	return func(s *Server) { s.before = append(s.before, before...) }
46}
47
48// ServeHTTP implements http.Handler.
49func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
50	ctx := r.Context()
51
52	for _, f := range s.before {
53		ctx = f(ctx, r)
54	}
55
56	s.proxy.ServeHTTP(w, r)
57}
58