fix(scan): stop one over-long url from dropping the wayback feed (#321)

the wayback line scanner capped each line at 1mb, so a single archived
url with a huge query string made scanner.Err return ErrTooLong and the
whole feed was discarded. read lines without a per-line cap, still bounded
by the passiveMaxBytes read limit.
This commit is contained in:
Tigah
2026-07-22 12:51:57 -07:00
committed by GitHub
parent fa84b3f7a5
commit 22935328b5
2 changed files with 39 additions and 10 deletions
+14 -10
View File
@@ -181,17 +181,21 @@ func fetchWayback(ctx context.Context, client *http.Client, domain string) ([]st
}
var urls []string
scanner := bufio.NewScanner(strings.NewReader(string(body)))
// historical urls can be long; give the scanner a generous line buffer.
scanner.Buffer(make([]byte, 0, 64*1024), 1024*1024)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line != "" {
urls = append(urls, line)
// read line by line without a per-line cap: a single archived url with a
// huge query string must not abort the whole feed. overall size is already
// bounded by the passiveMaxBytes read limit.
reader := bufio.NewReader(strings.NewReader(string(body)))
for {
line, err := reader.ReadString('\n')
if trimmed := strings.TrimSpace(line); trimmed != "" {
urls = append(urls, trimmed)
}
if err != nil {
if err == io.EOF {
break
}
return nil, fmt.Errorf("read wayback lines: %w", err)
}
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("read wayback lines: %w", err)
}
return urls, nil
}
+25
View File
@@ -15,6 +15,7 @@ package scan
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
)
@@ -168,6 +169,30 @@ func TestPassive_ScopesSubdomainsToTarget(t *testing.T) {
}
}
func TestPassive_WaybackLongLineKeepsFeed(t *testing.T) {
// a single archived url with a huge query string (data:/base64 blobs do
// occur) must not discard every other harvested url.
longURL := "http://example.com/?blob=" + strings.Repeat("a", 2*1024*1024)
wayback := longURL + "\n" +
"http://example.com/keep-one\n" +
"http://example.com/keep-two\n"
fixtureServer(t, "[]", "[]", wayback)
result, err := Passive("https://example.com", 5*time.Second, "")
if err != nil {
t.Fatalf("Passive: %v", err)
}
for _, want := range []string{"http://example.com/keep-one", "http://example.com/keep-two"} {
if !urlsContain(result.URLs, want) {
t.Errorf("over-long wayback line dropped the feed; missing %q, got %d urls", want, len(result.URLs))
}
}
if !urlsContain(result.URLs, longURL) {
t.Errorf("the over-long url itself was dropped, got %d urls", len(result.URLs))
}
}
func TestNormalizeHost(t *testing.T) {
tests := []struct {
in string