package middlewares import ( "bytes" "context" "fmt" "html/template" "io" "net/http" "path/filepath" "go.uber.org/zap" ) const ( backendNameQueryParam = "connector_id" backendCtxKeyName = "backendName" ) type BackendFromRequestMiddleware struct { l *zap.SugaredLogger h http.Handler baseDir string } func (m *BackendFromRequestMiddleware) serveBackendSelector(w http.ResponseWriter, r *http.Request) (int, error) { lp := filepath.Join(m.baseDir, "templates", "login.html") hdrTpl := filepath.Join(m.baseDir, "templates", "header.html") footTpl := filepath.Join(m.baseDir, "templates", "footer.html") tmpl, err := template.New("login.html").ParseFiles(hdrTpl, footTpl, lp) if err != nil { return http.StatusInternalServerError, fmt.Errorf("failed to init template: %w", err) } buf := new(bytes.Buffer) if err := tmpl.Execute(buf, nil); err != nil { return http.StatusInternalServerError, fmt.Errorf("failed to execute template: %w", err) } _, err = io.Copy(w, buf) if err != nil { return http.StatusInternalServerError, fmt.Errorf("failed to write response; %w", err) } return http.StatusOK, nil } func (m *BackendFromRequestMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/authorize" { m.h.ServeHTTP(w, r) return } if err := r.ParseForm(); err != nil { // TODO: handle this better w.WriteHeader(http.StatusBadRequest) return } backendName := r.Form.Get(backendNameQueryParam) if backendName == "" { statusCode, err := m.serveBackendSelector(w, r) if err != nil { m.l.Errorf("Failed to serve backend selector page: %s", err) } w.WriteHeader(statusCode) return } ctx := context.WithValue(r.Context(), backendCtxKeyName, backendName) m.h.ServeHTTP(w, r.WithContext(ctx)) } func WithBackendFromRequestMiddleware(input http.Handler) http.Handler { return &BackendFromRequestMiddleware{h: input} }