Files

98 lines
3.3 KiB
Go

package main
import (
"context"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestHTTPRoutesAndPolicies(t *testing.T) {
dir, m, _ := fixtureArtifact(t, "one")
h := staticSite(dir, m, false)
for _, v := range []struct {
path string
code int
}{{"/", 200}, {"/editor/", 200}, {"/r/one/embed/", 200}, {"/r/other/editor/", 404}, {"/unknown.wasm", 404}, {"/assets/missing.png", 404}, {"/editor/missing.js", 404}, {"/%2e%2e/secret", 404}, {"/manifest.json", 200}} {
r := httptest.NewRecorder()
h.ServeHTTP(r, httptest.NewRequest("GET", v.path, nil))
if r.Code != v.code {
t.Fatalf("%s: %d", v.path, r.Code)
}
if v.code == 404 && (r.Header().Get("Cache-Control") != "no-store" || strings.Contains(r.Header().Get("Content-Type"), "html")) {
t.Fatal("cached HTML fallback for missing asset")
}
}
r := httptest.NewRecorder()
h.ServeHTTP(r, httptest.NewRequest("GET", "/r/one/embed/", nil))
if r.Header().Get("X-Frame-Options") != "" || !strings.Contains(r.Header().Get("Content-Security-Policy"), m.DocsOrigins[0]) {
t.Fatal("iframe blocked or wrong CSP")
}
r = httptest.NewRecorder()
h.ServeHTTP(r, httptest.NewRequest("GET", "/editor/", nil))
if !strings.Contains(r.Header().Get("Content-Security-Policy"), "frame-ancestors 'none'") {
t.Fatal("standalone must not be embeddable")
}
r = httptest.NewRecorder()
h.ServeHTTP(r, httptest.NewRequest("GET", "/"+m.WASM.Path, nil))
if r.Header().Get("Content-Type") != "application/wasm" || !strings.Contains(r.Header().Get("Cache-Control"), "immutable") {
t.Fatal("WASM MIME/cache")
}
r = httptest.NewRecorder()
h.ServeHTTP(r, httptest.NewRequest("POST", "/editor/", strings.NewReader("pixels")))
if r.Code != 405 {
t.Fatal("write endpoint must not exist")
}
}
func TestHTTPReferenceBytes(t *testing.T) {
dir, m, sha := fixtureArtifact(t, "one")
s := httptest.NewServer(staticSite(dir, m, false))
defer s.Close()
result, e := httpCheck(context.Background(), s.URL+"/r/one/", dir, sha)
if e != nil {
t.Fatal(e)
}
if result["status"] != "PASS" {
t.Fatal(result)
}
}
func TestHTTPRejectsRedirect(t *testing.T) {
dir, _, sha := fixtureArtifact(t, "one")
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "https://example.com", http.StatusFound)
}))
defer s.Close()
if _, e := httpCheck(context.Background(), s.URL+"/", dir, sha); e == nil {
t.Fatal("followed redirect")
}
}
func TestDocsPreviewDoesNotExposeEditor(t *testing.T) {
dir, m, _ := fixtureArtifact(t, "one")
h := staticSite(dir, m, true)
w := httptest.NewRecorder()
h.ServeHTTP(w, httptest.NewRequest("GET", "/editor/", nil))
if w.Code != 404 {
t.Fatal(w.Code)
}
policy := csp(m, "docs/ru/export/index.html", true)
if !strings.Contains(policy, "frame-src "+m.AppOrigin+" blob:;") ||
!strings.Contains(policy, "form-action 'none'") ||
!strings.Contains(policy, "frame-ancestors 'none'") || strings.Contains(policy, "*") {
t.Fatalf("docs must support sandboxed local downloads without broadening network or form access: %s", policy)
}
}
func TestGzipQuality(t *testing.T) {
for _, v := range []string{"gzip;q=0", "gzip;q=0.000", "gzip;q=invalid", "br", "gzip;q=1.1"} {
if acceptsGzip(v) {
t.Fatalf("accepted %q", v)
}
}
for _, v := range []string{"gzip", "br, gzip;q=0.5", "gzip;q=1.0"} {
if !acceptsGzip(v) {
t.Fatalf("rejected %q", v)
}
}
}