Ctrl K
ComunidadGuías…

internal/server/fallback_status_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// SPDX-License-Identifier: Apache-2.0

package server

import (
	"encoding/json"
	"net/http"
	"net/url"
	"strings"
	"testing"

	"github.com/X4Applegate/caddyui/internal/models"
)

// v2.60.0 (issue #123): the fallback status for unmatched requests is
// configurable (4xx/5xx), consistent on HTTP, HTTPS and the wildcard route.

func TestParseFallbackStatus(t *testing.T) {
	for in, want := range map[string]int{"404": 404, " 403 ": 403, "418": 418, "421": 421, "400": 400, "599": 599, "503": 503} {
		if got, ok := parseFallbackStatus(in); !ok || got != want {
			t.Errorf("%q -> %d,%v want %d,true", in, got, ok, want)
		}
	}
	for _, bad := range []string{"", "200", "301", "399", "600", "0", "-404", "abc", "40 4", "4040"} {
		if _, ok := parseFallbackStatus(bad); ok {
			t.Errorf("%q was accepted", bad)
		}
	}
}

func TestFallbackStatusDefaultsTo404AndIgnoresGarbage(t *testing.T) {
	s := newHTTPOnlyTestServer(t)
	if got := s.fallbackStatusCode(); got != 404 {
		t.Errorf("default = %d", got)
	}
	for _, stored := range []string{"abc", "200", "700"} {
		_ = models.SetSetting(s.DB, settingFallbackStatus, stored)
		if got := s.fallbackStatusCode(); got != 404 {
			t.Errorf("stored %q -> %d, want the 404 default", stored, got)
		}
	}
	_ = models.SetSetting(s.DB, settingFallbackStatus, "421")
	if got := s.fallbackStatusCode(); got != 421 {
		t.Errorf("stored 421 -> %d", got)
	}
}

func TestConfiguredFallbackStatusIsUsedEverywhere(t *testing.T) {
	s := newHTTPOnlyTestServer(t)
	_ = models.SetSetting(s.DB, settingFallbackStatus, "418")
	hosts := []models.ProxyHost{proxyRow("app.example.com", false)}

	// Default (no custom HTML): Caddy's error handler with the chosen status,
	// on both listeners.
	for name, routes := range map[string][]any{
		"HTTPS": s.withFallbackRoute(s.buildMergedRoutes(hosts, nil, nil)),
		"HTTP":  s.buildHTTPRoutes(hosts, nil, nil),
	} {
		last := lastRouteJSON(t, routes)
		if !strings.Contains(last, `"handler":"error"`) || !strings.Contains(last, `"status_code":418`) {
			t.Errorf("%s: fallback is not an error handler with 418: %s", name, last)
		}
	}

	// With custom HTML the same status is sent with the page.
	_ = models.SetSetting(s.DB, settingCatchAll404HTML, "<p>teapot</p>")
	last := lastRouteJSON(t, s.buildHTTPRoutes(hosts, nil, nil))
	if !strings.Contains(last, "static_response") || !strings.Contains(last, `"status_code":418`) || !strings.Contains(last, "teapot") {
		t.Errorf("custom page not sent with the configured status: %s", last)
	}

	// The managed wildcard-certificate route answers exactly like every other
	// unknown host, instead of a hardcoded 404.
	certs := []models.Certificate{{ID: 2, Source: models.CertSourceManaged, Domains: "*.example.com"}}
	routes := buildManagedCertificateRoutes(certs, s.fallbackRoute()["handle"].([]any))
	b, _ := json.Marshal(routes)
	if !strings.Contains(string(b), `"status_code":418`) || strings.Contains(string(b), `"status_code":404`) {
		t.Errorf("wildcard-certificate route does not follow the fallback: %s", b)
	}
}

func TestSettingsSavesAndValidatesTheFallbackStatus(t *testing.T) {
	s, _ := newPreflightTestServer(t)
	rec := postSettingsPage(t, s, url.Values{"settings_section": {"general"}, "fallback_status_code": {"403"}, "catch_all_404_html": {"<p>nope</p>"}})
	if rec.Code != http.StatusSeeOther {
		t.Fatalf("save -> %d: %s", rec.Code, rec.Body.String())
	}
	if got := setting(t, s, settingFallbackStatus); got != "403" {
		t.Errorf("stored %q, want 403", got)
	}
	// Another section's save must not touch it.
	_ = postSettingsPage(t, s, url.Values{"settings_section": {"security"}})
	if got := setting(t, s, settingFallbackStatus); got != "403" {
		t.Errorf("a different section's save changed it to %q", got)
	}
	// Invalid values are refused and nothing is changed.
	for _, bad := range []string{"200", "302", "700", "abc"} {
		rec := postSettingsPage(t, s, url.Values{"settings_section": {"general"}, "fallback_status_code": {bad}})
		if rec.Code != http.StatusBadRequest {
			t.Errorf("%q -> %d, want 400", bad, rec.Code)
		}
	}
	if got := setting(t, s, settingFallbackStatus); got != "403" {
		t.Errorf("an invalid save changed it to %q", got)
	}
	// Blank resets to the default.
	_ = postSettingsPage(t, s, url.Values{"settings_section": {"general"}, "fallback_status_code": {""}})
	if got := setting(t, s, settingFallbackStatus); got != "" {
		t.Errorf("blank stored %q, want empty (= 404)", got)
	}
}