package web import ( "context" "net/http" "strings" "testing" "unicode/utf8" "github.com/shadow1ng/fscan/webscan/lib" ) type faviconRoundTripper struct { called bool } func TestExtractTitleTruncatesByRune(t *testing.T) { title := strings.Repeat("界", 105) got := NewWebTitlePlugin().extractTitle("" + title + "") if !utf8.ValidString(got) || len([]rune(got)) != 103 || !strings.HasSuffix(got, "...") { t.Fatalf("extractTitle() = %q", got) } } func (rt *faviconRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { rt.called = true <-req.Context().Done() return nil, req.Context().Err() } func TestFetchFaviconHashHonorsContext(t *testing.T) { previous := lib.Client rt := &faviconRoundTripper{} lib.Client = &http.Client{Transport: rt} defer func() { lib.Client = previous }() ctx, cancel := context.WithCancel(context.Background()) cancel() hashes := NewWebTitlePlugin().fetchFaviconHash(ctx, "http://example.com") if !rt.called { t.Fatal("favicon client was not called") } if len(hashes.MMH3) != 0 || len(hashes.MD5) != 0 { t.Fatalf("fetchFaviconHash returned hashes for canceled context: %#v", hashes) } } func TestWebTitleURLUsesJoinHostPort(t *testing.T) { tests := []struct { name string got string want string }{ {"ipv4", webTitleURL("http", "127.0.0.1", 8080), "http://127.0.0.1:8080"}, {"ipv6", webTitleURL("http", "::1", 8080), "http://[::1]:8080"}, {"ipv6 display with port", webTitleDisplayURL("https", "2001:db8::1", 8443, false), "https://[2001:db8::1]:8443"}, {"ipv6 display omit port", webTitleDisplayURL("https", "2001:db8::1", 443, true), "https://[2001:db8::1]"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.got != tt.want { t.Fatalf("got %q, want %q", tt.got, tt.want) } }) } } func TestWebTitleHTTPClientsFallbackWhenGlobalsNil(t *testing.T) { previousClient, previousNoRedirect := lib.Client, lib.ClientNoRedirect previousGM, previousNoRedirectGM := lib.ClientGM, lib.ClientNoRedirectGM lib.Client, lib.ClientNoRedirect = nil, nil lib.ClientGM, lib.ClientNoRedirectGM = nil, nil defer func() { lib.Client, lib.ClientNoRedirect = previousClient, previousNoRedirect lib.ClientGM, lib.ClientNoRedirectGM = previousGM, previousNoRedirectGM }() clientNR, clientR := webTitleHTTPClients(false) if clientNR == nil || clientR == nil { t.Fatal("webTitleHTTPClients returned nil fallback client") } req, err := http.NewRequest(http.MethodGet, "http://example.com", nil) if err != nil { t.Fatal(err) } if err := clientNR.CheckRedirect(req, []*http.Request{req}); err != http.ErrUseLastResponse { t.Fatalf("no-redirect fallback error = %v, want http.ErrUseLastResponse", err) } } func TestReadWebTitleBodyIsBounded(t *testing.T) { body := strings.NewReader(strings.Repeat("a", maxWebTitleBodyBytes+1024)) got, err := readWebTitleBody(body) if err != nil { t.Fatalf("readWebTitleBody error = %v", err) } if len(got) != maxWebTitleBodyBytes { t.Fatalf("body len = %d, want %d", len(got), maxWebTitleBodyBytes) } }