chore: move app URL parsing to its own package (#11651)

* chore: move app url parsing to it's own package
This commit is contained in:
Steven Masley
2024-01-17 10:41:42 -06:00
committed by GitHub
parent 1aee8da4b6
commit b246f08d84
32 changed files with 165 additions and 133 deletions
+13 -12
View File
@@ -24,6 +24,7 @@ import (
"github.com/coder/coder/v2/coderd/httpmw"
"github.com/coder/coder/v2/coderd/tracing"
"github.com/coder/coder/v2/coderd/util/slice"
"github.com/coder/coder/v2/coderd/workspaceapps/appurl"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/site"
)
@@ -96,7 +97,7 @@ type Server struct {
// E.g. "*.apps.coder.com" or "*-apps.coder.com".
Hostname string
// HostnameRegex contains the regex version of Hostname as generated by
// httpapi.CompileHostnamePattern(). It MUST be set if Hostname is set.
// appurl.CompileHostnamePattern(). It MUST be set if Hostname is set.
HostnameRegex *regexp.Regexp
RealIPConfig *httpmw.RealIPConfig
@@ -329,7 +330,7 @@ func (s *Server) workspaceAppsProxyPath(rw http.ResponseWriter, r *http.Request)
// 3. If the request hostname matches api.AccessURL then we pass on.
// 5. We split the subdomain into the subdomain and the "rest". If there are no
// periods in the hostname then we pass on.
// 5. We parse the subdomain into a httpapi.ApplicationURL struct. If we
// 5. We parse the subdomain into a appurl.ApplicationURL struct. If we
// encounter an error:
// a. If the "rest" does not match api.Hostname then we pass on;
// b. Otherwise, we return a 400.
@@ -428,43 +429,43 @@ func (s *Server) HandleSubdomain(middlewares ...func(http.Handler) http.Handler)
// parseHostname will return if a given request is attempting to access a
// workspace app via a subdomain. If it is, the hostname of the request is parsed
// into an httpapi.ApplicationURL and true is returned. If the request is not
// into an appurl.ApplicationURL and true is returned. If the request is not
// accessing a workspace app, then the next handler is called and false is
// returned.
func (s *Server) parseHostname(rw http.ResponseWriter, r *http.Request, next http.Handler, host string) (httpapi.ApplicationURL, bool) {
func (s *Server) parseHostname(rw http.ResponseWriter, r *http.Request, next http.Handler, host string) (appurl.ApplicationURL, bool) {
// Check if the hostname matches either of the access URLs. If it does, the
// user was definitely trying to connect to the dashboard/API or a
// path-based app.
if httpapi.HostnamesMatch(s.DashboardURL.Hostname(), host) || httpapi.HostnamesMatch(s.AccessURL.Hostname(), host) {
if appurl.HostnamesMatch(s.DashboardURL.Hostname(), host) || appurl.HostnamesMatch(s.AccessURL.Hostname(), host) {
next.ServeHTTP(rw, r)
return httpapi.ApplicationURL{}, false
return appurl.ApplicationURL{}, false
}
// If there are no periods in the hostname, then it can't be a valid
// application URL.
if !strings.Contains(host, ".") {
next.ServeHTTP(rw, r)
return httpapi.ApplicationURL{}, false
return appurl.ApplicationURL{}, false
}
// Split the subdomain so we can parse the application details and verify it
// matches the configured app hostname later.
subdomain, ok := httpapi.ExecuteHostnamePattern(s.HostnameRegex, host)
subdomain, ok := appurl.ExecuteHostnamePattern(s.HostnameRegex, host)
if !ok {
// Doesn't match the regex, so it's not a valid application URL.
next.ServeHTTP(rw, r)
return httpapi.ApplicationURL{}, false
return appurl.ApplicationURL{}, false
}
// Check if the request is part of the deprecated logout flow. If so, we
// just redirect to the main access URL.
if subdomain == appLogoutHostname {
http.Redirect(rw, r, s.AccessURL.String(), http.StatusSeeOther)
return httpapi.ApplicationURL{}, false
return appurl.ApplicationURL{}, false
}
// Parse the application URL from the subdomain.
app, err := httpapi.ParseSubdomainAppURL(subdomain)
app, err := appurl.ParseSubdomainAppURL(subdomain)
if err != nil {
site.RenderStaticErrorPage(rw, r, site.ErrorPageData{
Status: http.StatusBadRequest,
@@ -473,7 +474,7 @@ func (s *Server) parseHostname(rw http.ResponseWriter, r *http.Request, next htt
RetryEnabled: false,
DashboardURL: s.DashboardURL.String(),
})
return httpapi.ApplicationURL{}, false
return appurl.ApplicationURL{}, false
}
return app, true