Skip to content

Commit 4691b66

Browse files
committed
move to embeded
1 parent fae8f3b commit 4691b66

17 files changed

Lines changed: 101 additions & 12876 deletions

File tree

backend/http/handler.go

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ import (
3838
"github.com/kube-bind/kube-bind/backend/kubernetes"
3939
"github.com/kube-bind/kube-bind/backend/session"
4040
"github.com/kube-bind/kube-bind/backend/spaserver"
41-
"github.com/kube-bind/kube-bind/backend/static"
4241
bindversion "github.com/kube-bind/kube-bind/pkg/version"
4342
kubebindv1alpha2 "github.com/kube-bind/kube-bind/sdk/apis/kubebind/v1alpha2"
43+
"github.com/kube-bind/kube-bind/web"
4444
)
4545

4646
// See https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=en
@@ -116,7 +116,6 @@ func (h *handler) AddRoutes(mux *mux.Router) error {
116116
mux.HandleFunc("/api/healthz", h.handleHealthz).Methods(http.MethodGet)
117117
mux.HandleFunc("/api/bindable-resources", h.handleBindableResources).Methods(http.MethodGet)
118118

119-
// CLI redirect routes - must come before SPA handler to intercept CLI requests
120119
// These provide HTTP 302 redirects for CLI tools that can't execute JavaScript
121120
mux.HandleFunc("/clusters/{cluster}/exports", h.handleExportsRedirect).Methods(http.MethodGet)
122121
mux.HandleFunc("/exports", h.handleExportsRedirect).Methods(http.MethodGet)
@@ -129,28 +128,26 @@ func (h *handler) AddRoutes(mux *mux.Router) error {
129128
return err
130129
}
131130
mux.PathPrefix("/").Handler(spaserver)
132-
case h.frontend == "embedded":
133-
// Production mode: serve embedded static files
134-
fileSystem := static.GetFileSystem()
135-
mux.PathPrefix("/").Handler(spaserver.NewSPAFileServer(fileSystem))
136131
default:
137-
// Custom filesystem path
138-
fileSystem := http.Dir(h.frontend)
139-
mux.PathPrefix("/").Handler(spaserver.NewSPAFileServer(fileSystem))
132+
fs := web.GetFileSystem()
133+
mux.PathPrefix("/").Handler(spaserver.NewSPAFileServer(fs))
140134
}
141135
return nil
142136
}
143137

138+
func (h *handler) handleHealthz(w http.ResponseWriter, r *http.Request) {
139+
prepareNoCache(w)
140+
w.WriteHeader(http.StatusOK)
141+
}
142+
144143
func (h *handler) handleExportsRedirect(w http.ResponseWriter, r *http.Request) {
145144
logger := getLogger(r)
146145
cluster := mux.Vars(r)["cluster"]
147146

148147
var redirectURL string
149148
if cluster != "" {
150-
// Multi-cluster route: /clusters/{cluster}/exports -> /api/clusters/{cluster}/exports
151149
redirectURL = fmt.Sprintf("/api/clusters/%s/exports", cluster)
152150
} else {
153-
// Single cluster route: /exports -> /api/exports
154151
redirectURL = "/api/exports"
155152
}
156153

@@ -159,13 +156,8 @@ func (h *handler) handleExportsRedirect(w http.ResponseWriter, r *http.Request)
159156
redirectURL += "?" + r.URL.RawQuery
160157
}
161158

162-
logger.V(1).Info("redirecting CLI exports request", "from", r.URL.Path, "to", redirectURL)
163-
http.Redirect(w, r, redirectURL, http.StatusFound) // 302 redirect
164-
}
165-
166-
func (h *handler) handleHealthz(w http.ResponseWriter, r *http.Request) {
167-
prepareNoCache(w)
168-
w.WriteHeader(http.StatusOK)
159+
logger.Info("redirecting CLI exports request", "from", r.URL.Path, "to", redirectURL)
160+
http.Redirect(w, r, redirectURL, http.StatusFound)
169161
}
170162

171163
func (h *handler) handleServiceExport(w http.ResponseWriter, r *http.Request) {
@@ -176,9 +168,9 @@ func (h *handler) handleServiceExport(w http.ResponseWriter, r *http.Request) {
176168
oidcAuthorizeURL := h.oidcAuthorizeURL
177169
if oidcAuthorizeURL == "" {
178170
if singleClusterScoped {
179-
oidcAuthorizeURL = fmt.Sprintf("http://%s/authorize", r.Host)
171+
oidcAuthorizeURL = fmt.Sprintf("http://%s/api/authorize", r.Host)
180172
} else {
181-
oidcAuthorizeURL = fmt.Sprintf("http://%s/clusters/%s/authorize", r.Host, cluster)
173+
oidcAuthorizeURL = fmt.Sprintf("http://%s/api/clusters/%s/authorize", r.Host, cluster)
182174
}
183175
}
184176

backend/options/options.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func NewOptions() *Options {
9999
ClusterScopedIsolation: string(kubebindv1alpha2.IsolationPrefixed),
100100
ServerURL: "",
101101
SchemaSource: CustomResourceDefinitionSource.String(),
102-
Frontend: "embedded",
102+
Frontend: "/www",
103103
},
104104
}
105105
}

backend/spaserver/spaserver.go

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,31 +44,68 @@ func (s *SPAFileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
4444
return
4545
}
4646

47-
// Check if the requested file exists
47+
// Try to serve the file directly first
4848
if f, err := s.fileSystem.Open(path); err == nil {
4949
if err = f.Close(); err != nil {
50-
http.Error(w, "Internal server error", http.StatusInternalServerError)
50+
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
5151
return
5252
}
53-
// File exists, serve it directly
5453
s.fileServer.ServeHTTP(w, r)
55-
} else if os.IsNotExist(err) {
56-
// For SPA routing: only serve index.html for non-asset requests
57-
// If the path contains /assets/, /api/, or has a file extension, it's likely a static asset
58-
if strings.Contains(path, "/assets/") || strings.Contains(path, "/api/") ||
59-
(strings.Contains(path, ".") && !strings.HasSuffix(path, "/")) {
60-
// This is a static asset or API request that doesn't exist, return 404
61-
http.NotFound(w, r)
54+
return
55+
} else if !os.IsNotExist(err) {
56+
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
57+
return
58+
}
59+
60+
// File not found - check if it's a static asset
61+
if isStaticAsset(path) {
62+
// Try to serve the asset by stripping any /clusters/{id} prefix
63+
cleanPath := stripClustersPrefix(path)
64+
if f, err := s.fileSystem.Open(cleanPath); err == nil {
65+
if err = f.Close(); err != nil {
66+
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
67+
return
68+
}
69+
r.URL.Path = cleanPath
70+
s.fileServer.ServeHTTP(w, r)
6271
return
6372
}
64-
65-
// This is likely a SPA route, serve index.html
66-
r.URL.Path = "/"
67-
s.fileServer.ServeHTTP(w, r)
73+
// Asset not found even with clean path, return 404
74+
http.NotFound(w, r)
6875
return
69-
} else {
70-
http.Error(w, "Internal server error", http.StatusInternalServerError)
7176
}
77+
78+
// For navigation routes, serve index.html
79+
r.URL.Path = "/"
80+
s.fileServer.ServeHTTP(w, r)
81+
}
82+
83+
// isStaticAsset checks if the path is for a static asset
84+
func isStaticAsset(path string) bool {
85+
return strings.Contains(path, "/assets/") ||
86+
strings.HasSuffix(path, ".js") ||
87+
strings.HasSuffix(path, ".css") ||
88+
strings.HasSuffix(path, ".png") ||
89+
strings.HasSuffix(path, ".jpg") ||
90+
strings.HasSuffix(path, ".jpeg") ||
91+
strings.HasSuffix(path, ".gif") ||
92+
strings.HasSuffix(path, ".svg") ||
93+
strings.HasSuffix(path, ".ico") ||
94+
strings.HasSuffix(path, ".woff") ||
95+
strings.HasSuffix(path, ".woff2") ||
96+
strings.HasSuffix(path, ".ttf") ||
97+
strings.HasSuffix(path, ".eot")
98+
}
99+
100+
// stripClustersPrefix removes /clusters/{id} prefix from paths
101+
func stripClustersPrefix(path string) string {
102+
// Match pattern /clusters/{clusterId}/... and extract the part after the clusterId
103+
parts := strings.Split(path, "/")
104+
if len(parts) >= 4 && parts[1] == "clusters" {
105+
// Path like /clusters/1blitmxjy8lczleb/assets/file.js -> /assets/file.js
106+
return "/" + strings.Join(parts[3:], "/")
107+
}
108+
return path
72109
}
73110

74111
// SPAReverseProxyServer is used for local development or in theory it could be used.

0 commit comments

Comments
 (0)