package director import ( "context" "net/http" "forge.cadoles.com/Cadoles/go-proxy" "forge.cadoles.com/Cadoles/go-proxy/wildcard" "forge.cadoles.com/cadoles/bouncer/internal/store" "github.com/davecgh/go-spew/spew" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" ) type Director struct { proxyRepository store.ProxyRepository layerRegistry *LayerRegistry } func (d *Director) rewriteRequest(r *http.Request) (*http.Request, error) { ctx := r.Context() proxies, err := d.getProxies(ctx) if err != nil { return nil, errors.WithStack(err) } var match *store.Proxy MAIN: for _, p := range proxies { for _, from := range p.From { if matches := wildcard.Match(r.Host, from); !matches { continue } match = p break MAIN } } if match == nil { return r, nil } r.URL.Host = match.To.Host r.URL.Scheme = match.To.Scheme ctx = withProxy(ctx, match) r = r.WithContext(ctx) return r, nil } func (d *Director) getProxies(ctx context.Context) ([]*store.Proxy, error) { headers, err := d.proxyRepository.QueryProxy(ctx) if err != nil { return nil, errors.WithStack(err) } proxies := make([]*store.Proxy, len(headers)) for i, h := range headers { proxy, err := d.proxyRepository.GetProxy(ctx, h.Name) if err != nil { return nil, errors.WithStack(err) } proxies[i] = proxy } return proxies, nil } func (d *Director) RequestTransformer() proxy.RequestTransformer { return func(r *http.Request) { ctx := r.Context() proxy, err := ctxProxy(ctx) if err != nil { if errors.Is(err, errContextKeyNotFound) { return } logger.Error(ctx, "could not retrieve proxy from context", logger.E(errors.WithStack(err))) return } spew.Dump(proxy) } } func (d *Director) ResponseTransformer() proxy.ResponseTransformer { return func(r *http.Response) error { return nil } } func (d *Director) Middleware() proxy.Middleware { return func(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { r, err := d.rewriteRequest(r) if err != nil { logger.Error(r.Context(), "could not rewrite request", logger.E(errors.WithStack(err))) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } next.ServeHTTP(w, r) } return http.HandlerFunc(fn) } } func New(repo store.ProxyRepository, layers ...Layer) *Director { registry := NewLayerRegistry(layers...) return &Director{repo, registry} }