Skip to content

Commit 973f90d

Browse files
committed
pr feedback adjustments [not tested yet]
Signed-off-by: malpou <malthe@grundtvigsvej.dk>
1 parent 7d8d97d commit 973f90d

File tree

5 files changed

+109
-95
lines changed

5 files changed

+109
-95
lines changed

interceptor/handler/placeholder.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,11 @@ type cacheEntry struct {
108108

109109
// PlaceholderHandler handles serving placeholder pages during scale-from-zero
110110
type PlaceholderHandler struct {
111-
templateCache map[string]*cacheEntry
112-
cacheMutex sync.RWMutex
113-
defaultTmpl *template.Template
114-
servingCfg *config.Serving
115-
enableScript bool
111+
templateCache map[string]*cacheEntry
112+
cacheMutex sync.RWMutex
113+
defaultTmpl *template.Template
114+
servingCfg *config.Serving
115+
enableScript bool
116116
}
117117

118118
// PlaceholderData contains data for rendering placeholder templates
@@ -127,27 +127,27 @@ type PlaceholderData struct {
127127
// NewPlaceholderHandler creates a new placeholder handler
128128
func NewPlaceholderHandler(servingCfg *config.Serving) (*PlaceholderHandler, error) {
129129
var defaultTemplate string
130-
130+
131131
// Try to load template from configured path
132132
if servingCfg.PlaceholderDefaultTemplatePath != "" {
133133
content, err := os.ReadFile(servingCfg.PlaceholderDefaultTemplatePath)
134134
if err == nil {
135135
defaultTemplate = string(content)
136136
} else {
137137
// Fall back to built-in template if file cannot be read
138-
fmt.Printf("Warning: Could not read placeholder template from %s: %v. Using built-in template.\n",
138+
fmt.Printf("Warning: Could not read placeholder template from %s: %v. Using built-in template.\n",
139139
servingCfg.PlaceholderDefaultTemplatePath, err)
140140
defaultTemplate = defaultPlaceholderTemplateWithoutScript
141141
}
142142
} else {
143143
defaultTemplate = defaultPlaceholderTemplateWithoutScript
144144
}
145-
145+
146146
// Inject script if enabled
147147
if servingCfg.PlaceholderEnableScript {
148148
defaultTemplate = injectPlaceholderScript(defaultTemplate)
149149
}
150-
150+
151151
defaultTmpl, err := template.New("default").Parse(defaultTemplate)
152152
if err != nil {
153153
return nil, fmt.Errorf("failed to parse default template: %w", err)
@@ -201,19 +201,19 @@ func detectContentType(acceptHeader string, content string) string {
201201
if strings.Contains(acceptHeader, "text/plain") {
202202
return "text/plain"
203203
}
204-
204+
205205
// Default to HTML for browser requests or when HTML is accepted
206206
if strings.Contains(acceptHeader, "text/html") || strings.Contains(acceptHeader, "*/*") || acceptHeader == "" {
207207
// Check if content looks like HTML
208208
if strings.Contains(content, "<") && strings.Contains(content, ">") {
209209
return "text/html; charset=utf-8"
210210
}
211211
}
212-
212+
213213
// Try to detect based on content
214214
trimmed := strings.TrimSpace(content)
215215
if (strings.HasPrefix(trimmed, "{") && strings.HasSuffix(trimmed, "}")) ||
216-
(strings.HasPrefix(trimmed, "[") && strings.HasSuffix(trimmed, "]")) {
216+
(strings.HasPrefix(trimmed, "[") && strings.HasSuffix(trimmed, "]")) {
217217
return "application/json"
218218
}
219219
if strings.HasPrefix(trimmed, "<") {
@@ -222,7 +222,7 @@ func detectContentType(acceptHeader string, content string) string {
222222
}
223223
return "text/html; charset=utf-8"
224224
}
225-
225+
226226
return "text/plain; charset=utf-8"
227227
}
228228

@@ -275,17 +275,17 @@ func (h *PlaceholderHandler) ServePlaceholder(w http.ResponseWriter, r *http.Req
275275
}
276276

277277
content := buf.String()
278-
278+
279279
// Detect and set content type based on Accept header and content
280280
contentType := detectContentType(r.Header.Get("Accept"), content)
281-
281+
282282
// For non-HTML content, don't inject script even if enabled
283283
isHTML := strings.Contains(contentType, "text/html")
284284
if !isHTML && h.enableScript && strings.Contains(content, placeholderScript) {
285285
// Remove script from non-HTML content
286286
content = strings.ReplaceAll(content, placeholderScript, "")
287287
}
288-
288+
289289
w.Header().Set("Content-Type", contentType)
290290
w.Header().Set("X-KEDA-HTTP-Placeholder-Served", "true")
291291
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")

interceptor/handler/placeholder_test.go

Lines changed: 78 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -329,47 +329,47 @@ func TestGetTemplate_CacheInvalidation_ConfigMapVersion_REMOVED(t *testing.T) {
329329
return
330330
// The code below is kept for reference but won't be executed
331331
/*
332-
cm := &v1.ConfigMap{
333-
ObjectMeta: metav1.ObjectMeta{
334-
Name: "placeholder-cm",
335-
Namespace: "default",
336-
ResourceVersion: "1",
337-
},
338-
Data: map[string]string{
339-
"template.html": `<html><body>Version 1: {{.ServiceName}}</body></html>`,
340-
},
341-
}
342-
k8sClient := fake.NewSimpleClientset(cm)
343-
routingTable := test.NewTable()
344-
handler, _ := NewPlaceholderHandler(k8sClient, routingTable)
345-
346-
hso := &v1alpha1.HTTPScaledObject{
347-
ObjectMeta: metav1.ObjectMeta{
348-
Name: "test-app",
349-
Namespace: "default",
350-
Generation: 1,
351-
},
352-
Spec: v1alpha1.HTTPScaledObjectSpec{
353-
PlaceholderConfig: &v1alpha1.PlaceholderConfig{
354-
ContentConfigMap: "placeholder-cm",
332+
cm := &v1.ConfigMap{
333+
ObjectMeta: metav1.ObjectMeta{
334+
Name: "placeholder-cm",
335+
Namespace: "default",
336+
ResourceVersion: "1",
355337
},
356-
},
357-
}
338+
Data: map[string]string{
339+
"template.html": `<html><body>Version 1: {{.ServiceName}}</body></html>`,
340+
},
341+
}
342+
k8sClient := fake.NewSimpleClientset(cm)
343+
routingTable := test.NewTable()
344+
handler, _ := NewPlaceholderHandler(k8sClient, routingTable)
345+
346+
hso := &v1alpha1.HTTPScaledObject{
347+
ObjectMeta: metav1.ObjectMeta{
348+
Name: "test-app",
349+
Namespace: "default",
350+
Generation: 1,
351+
},
352+
Spec: v1alpha1.HTTPScaledObjectSpec{
353+
PlaceholderConfig: &v1alpha1.PlaceholderConfig{
354+
ContentConfigMap: "placeholder-cm",
355+
},
356+
},
357+
}
358358
359-
ctx := context.Background()
359+
ctx := context.Background()
360360
361-
tmpl1, err := handler.getTemplate(ctx, hso)
362-
require.NoError(t, err)
363-
assert.NotNil(t, tmpl1)
361+
tmpl1, err := handler.getTemplate(ctx, hso)
362+
require.NoError(t, err)
363+
assert.NotNil(t, tmpl1)
364364
365-
cm.ResourceVersion = "2"
366-
cm.Data["template.html"] = `<html><body>Version 2: {{.ServiceName}}</body></html>`
367-
_, err = k8sClient.CoreV1().ConfigMaps("default").Update(ctx, cm, metav1.UpdateOptions{})
368-
require.NoError(t, err)
365+
cm.ResourceVersion = "2"
366+
cm.Data["template.html"] = `<html><body>Version 2: {{.ServiceName}}</body></html>`
367+
_, err = k8sClient.CoreV1().ConfigMaps("default").Update(ctx, cm, metav1.UpdateOptions{})
368+
require.NoError(t, err)
369369
370-
tmpl2, err := handler.getTemplate(ctx, hso)
371-
require.NoError(t, err)
372-
assert.NotNil(t, tmpl2)
370+
tmpl2, err := handler.getTemplate(ctx, hso)
371+
require.NoError(t, err)
372+
assert.NotNil(t, tmpl2)
373373
*/
374374
}
375375

@@ -646,52 +646,52 @@ func TestServePlaceholder_ConfigMapContentWithScriptInjection_REMOVED(t *testing
646646
return
647647
// The code below is kept for reference but won't be executed
648648
/*
649-
configMapContent := `<html><body><h1>ConfigMap placeholder for {{.ServiceName}}</h1></body></html>`
650-
cm := &v1.ConfigMap{
651-
ObjectMeta: metav1.ObjectMeta{
652-
Name: "placeholder-cm",
653-
Namespace: "default",
654-
},
655-
Data: map[string]string{
656-
"template.html": configMapContent,
657-
},
658-
}
659-
k8sClient := fake.NewSimpleClientset(cm)
660-
routingTable := test.NewTable()
661-
handler, _ := NewPlaceholderHandler(k8sClient, routingTable)
662-
663-
hso := &v1alpha1.HTTPScaledObject{
664-
ObjectMeta: metav1.ObjectMeta{
665-
Name: "test-app",
666-
Namespace: "default",
667-
},
668-
Spec: v1alpha1.HTTPScaledObjectSpec{
669-
ScaleTargetRef: v1alpha1.ScaleTargetRef{
670-
Service: "test-service",
649+
configMapContent := `<html><body><h1>ConfigMap placeholder for {{.ServiceName}}</h1></body></html>`
650+
cm := &v1.ConfigMap{
651+
ObjectMeta: metav1.ObjectMeta{
652+
Name: "placeholder-cm",
653+
Namespace: "default",
671654
},
672-
PlaceholderConfig: &v1alpha1.PlaceholderConfig{
673-
Enabled: true,
674-
StatusCode: 503,
675-
RefreshInterval: 15,
676-
ContentConfigMap: "placeholder-cm",
655+
Data: map[string]string{
656+
"template.html": configMapContent,
677657
},
678-
},
679-
}
658+
}
659+
k8sClient := fake.NewSimpleClientset(cm)
660+
routingTable := test.NewTable()
661+
handler, _ := NewPlaceholderHandler(k8sClient, routingTable)
662+
663+
hso := &v1alpha1.HTTPScaledObject{
664+
ObjectMeta: metav1.ObjectMeta{
665+
Name: "test-app",
666+
Namespace: "default",
667+
},
668+
Spec: v1alpha1.HTTPScaledObjectSpec{
669+
ScaleTargetRef: v1alpha1.ScaleTargetRef{
670+
Service: "test-service",
671+
},
672+
PlaceholderConfig: &v1alpha1.PlaceholderConfig{
673+
Enabled: true,
674+
StatusCode: 503,
675+
RefreshInterval: 15,
676+
ContentConfigMap: "placeholder-cm",
677+
},
678+
},
679+
}
680680
681-
req := httptest.NewRequest("GET", "http://example.com", nil)
682-
w := httptest.NewRecorder()
681+
req := httptest.NewRequest("GET", "http://example.com", nil)
682+
w := httptest.NewRecorder()
683683
684-
err := handler.ServePlaceholder(w, req, hso)
685-
assert.NoError(t, err)
686-
assert.Equal(t, http.StatusServiceUnavailable, w.Code)
684+
err := handler.ServePlaceholder(w, req, hso)
685+
assert.NoError(t, err)
686+
assert.Equal(t, http.StatusServiceUnavailable, w.Code)
687687
688-
// Check that custom content is there
689-
assert.Contains(t, w.Body.String(), "ConfigMap placeholder for test-service")
688+
// Check that custom content is there
689+
assert.Contains(t, w.Body.String(), "ConfigMap placeholder for test-service")
690690
691-
// Check that script was injected
692-
assert.Contains(t, w.Body.String(), "checkServiceStatus")
693-
assert.Contains(t, w.Body.String(), "X-KEDA-HTTP-Placeholder-Served")
694-
assert.Contains(t, w.Body.String(), "checkInterval = 15 * 1000")
691+
// Check that script was injected
692+
assert.Contains(t, w.Body.String(), "checkServiceStatus")
693+
assert.Contains(t, w.Body.String(), "X-KEDA-HTTP-Placeholder-Served")
694+
assert.Contains(t, w.Body.String(), "checkInterval = 15 * 1000")
695695
*/
696696
}
697697

@@ -777,14 +777,14 @@ Please wait a moment...`
777777
assert.NotContains(t, body, "<!DOCTYPE html>")
778778
assert.NotContains(t, body, "<html>")
779779
assert.NotContains(t, body, "<body>")
780-
780+
781781
// Check that original content is preserved as-is
782782
assert.Contains(t, body, "Welcome! Your service is starting up.")
783783
assert.Contains(t, body, "Please wait a moment...")
784784

785785
// Check that script was NOT injected into plain text
786786
assert.NotContains(t, body, "checkServiceStatus")
787-
787+
788788
// Check content type is plain text
789789
assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
790790
}

interceptor/main_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ func TestRunProxyServerCountMiddleware(t *testing.T) {
8181
fmt.Println(err, "Error setting up tracer")
8282
}
8383

84+
servingCfg := &config.Serving{
85+
PlaceholderEnableScript: true,
86+
}
8487
g.Go(func() error {
8588
return runProxyServer(
8689
ctx,
@@ -90,6 +93,7 @@ func TestRunProxyServerCountMiddleware(t *testing.T) {
9093
routingTable,
9194
svcCache,
9295
timeouts,
96+
servingCfg,
9397
port,
9498
false,
9599
map[string]interface{}{},
@@ -222,6 +226,9 @@ func TestRunProxyServerWithTLSCountMiddleware(t *testing.T) {
222226
return false, nil
223227
}
224228
tracingCfg := config.Tracing{Enabled: true, Exporter: "otlphttp"}
229+
servingCfg := &config.Serving{
230+
PlaceholderEnableScript: true,
231+
}
225232

226233
g.Go(func() error {
227234
return runProxyServer(
@@ -232,6 +239,7 @@ func TestRunProxyServerWithTLSCountMiddleware(t *testing.T) {
232239
routingTable,
233240
svcCache,
234241
timeouts,
242+
servingCfg,
235243
port,
236244
true,
237245
map[string]interface{}{"certificatePath": "../certs/tls.crt", "keyPath": "../certs/tls.key", "skipVerify": true},
@@ -374,6 +382,9 @@ func TestRunProxyServerWithMultipleCertsTLSCountMiddleware(t *testing.T) {
374382
}
375383

376384
tracingCfg := config.Tracing{Enabled: true, Exporter: "otlphttp"}
385+
servingCfg := &config.Serving{
386+
PlaceholderEnableScript: true,
387+
}
377388

378389
g.Go(func() error {
379390
return runProxyServer(
@@ -384,6 +395,7 @@ func TestRunProxyServerWithMultipleCertsTLSCountMiddleware(t *testing.T) {
384395
routingTable,
385396
svcCache,
386397
timeouts,
398+
servingCfg,
387399
port,
388400
true,
389401
map[string]interface{}{"certstorePaths": "../certs"},

interceptor/proxy_handlers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func newForwardingHandler(
7676
}
7777
return
7878
}
79-
79+
8080
if workloadActiveEndpoints(endpoints) == 0 {
8181
if placeholderErr := placeholderHandler.ServePlaceholder(w, r, httpso); placeholderErr != nil {
8282
lggr.Error(placeholderErr, "failed to serve placeholder page")

interceptor/proxy_handlers_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ func TestImmediatelySuccessfulFailoverProxy(t *testing.T) {
192192
},
193193
&tls.Config{},
194194
&config.Tracing{},
195+
nil, // placeholderHandler
196+
nil, // endpointsCache
195197
)
196198
const path = "/testfwd"
197199
res, req, err := reqAndRes(path)

0 commit comments

Comments
 (0)