{"record":{"id":"2f18b522829af2a2","repo":"fish2018/pansou","slug":"s-d-2f18b5","errorCode":null,"errorMessage":"[%s] 搜索响应超过 %d 字节","messagePattern":"\\[(.+?)\\] 搜索响应超过 (.+?) 字节","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"plugin/haitunsou/haitunsou.go","lineNumber":108,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建搜索请求失败: %w\", p.Name(), err)\n\t}\n\tsetRequestHeaders(req, p.baseURL)\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求返回 HTTP %d\", p.Name(), resp.StatusCode)\n\t}\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize+1))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 读取搜索响应失败: %w\", p.Name(), err)\n\t}\n\tif len(body) > maxResponseSize {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索响应超过 %d 字节\", p.Name(), maxResponseSize)\n\t}\n\n\titems, err := parseEmbeddedList(body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解析搜索结果失败: %w\", p.Name(), err)\n\t}\n\tresults := make([]model.SearchResult, 0, len(items))\n\tseen := make(map[string]struct{}, len(items))\n\tfor _, item := range items {\n\t\tresult, ok := convertItem(item)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tkey := result.Links[0].URL + \"\\x00\" + result.Links[0].Password\n\t\tif _, exists := seen[key]; exists {\n\t\t\tcontinue\n\t\t}\n\t\tseen[key] = struct{}{}","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/haitunsou/haitunsou.go#L90-L126","documentation":"Returned by searchImpl when the response body exceeds maxResponseSize (3 MiB, 3 << 20 bytes). The body is read through a LimitReader of maxResponseSize+1 bytes; if more than maxResponseSize bytes were actually read, the plugin rejects the response instead of processing an unexpectedly huge page. This is a defensive guard against the upstream site returning garbage, error pages with huge payloads, or being redirected to a different site.","triggerScenarios":"len(body) > maxResponseSize after reading: the site returns an unusually large page, a redirect to unrelated content (parked domain, ad interstitial), or an HTML error page bloated with scripts.","commonSituations":"The haitunsou domain expires or is taken over and the plugin is silently redirected to an unrelated large page; upstream begins embedding much more data in pages; misconfigured baseURL points at a mirror returning huge pages.","solutions":["Verify the effective final URL (resp.Request.URL) — a redirect to an unexpected domain indicates baseURL/domain takeover; update baseURL","Check what the site actually returns with curl to confirm the page legitimately grew","Raise maxResponseSize deliberately if the upstream page size grew","Keep the guard but alert on it, since it usually signals a changed or hijacked upstream"],"exampleFix":"// before\nbody, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize+1))\n// after\nbody, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseSize+1))\nif len(body) > maxResponseSize {\n    return nil, fmt.Errorf(\"[%s] 搜索响应超过 %d 字节 (final URL: %s)\", p.Name(), maxResponseSize, resp.Request.URL)\n}","handlingStrategy":"fallback","validationCode":"// cannot be pre-validated; size only known after reading","typeGuard":null,"tryCatchPattern":"if strings.Contains(err.Error(), \"搜索响应超过\") {\n    // treat as upstream anomaly: log resp.Request.URL and skip this source,\n    // don't crash the whole search\n}","preventionTips":["Log the final redirected URL when this fires — often domain takeover","Alert rather than raise maxResponseSize blindly","Periodically curl the search endpoint to track normal page sizes","Verify configured baseURL points at the legitimate domain"],"tags":["http","response-size","guard"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}