Extracts the HTTP fetcher concern out of internal/imgcache/ into its own internal/httpfetcher/ package, per the plan in issue #39.
This is one of four planned extractions; only the fetcher is moved here so the diff stays reviewable. The remaining three (signature, magic, urlparser) will land in separate PRs.
What moved
From internal/imgcache/fetcher.go and internal/imgcache/mock_fetcher.go into internal/httpfetcher/:
HTTPFetcher type, its New constructor, and Config (formerly FetcherConfig) with DefaultConfig
Extracts the HTTP fetcher concern out of `internal/imgcache/` into its own `internal/httpfetcher/` package, per the plan in [issue #39](https://git.eeqj.de/sneak/pixa/issues/39).
This is one of four planned extractions; only the fetcher is moved here so the diff stays reviewable. The remaining three (signature, magic, urlparser) will land in separate PRs.
## What moved
From `internal/imgcache/fetcher.go` and `internal/imgcache/mock_fetcher.go` into `internal/httpfetcher/`:
- `HTTPFetcher` type, its `New` constructor, and `Config` (formerly `FetcherConfig`) with `DefaultConfig`
- SSRF-safe dialer, `validateURL`, `isPrivateIP`, `isLocalhost`, `extractHost`
- Per-host connection semaphore (rate limiting) and `limitedReader`
- Content-type validation (`isAllowedContentType`, `detectContentTypeFromPath`)
- All related error values (`ErrSSRFBlocked`, `ErrUpstreamError`, `ErrUpstreamTimeout`, `ErrPayloadTooLarge`, `ErrDisallowedContentType`)
- All related constants (`DefaultFetchTimeout`, `DefaultMaxPayloadBytes`, `DefaultMaxConnectionsPerHost`, etc.)
- The `Fetcher` interface and `FetchResult` type (moved here to keep the import edge one-way: `imgcache` depends on `httpfetcher`, never the reverse)
- `MockFetcher` test helper
## Renames (no stuttering)
- `NewHTTPFetcher` → `httpfetcher.New`
- `FetcherConfig` → `httpfetcher.Config`
- `DefaultFetcherConfig` → `httpfetcher.DefaultConfig`
- `NewMockFetcher` → `httpfetcher.NewMock`
The `ServiceConfig.FetcherConfig` field name is retained — it describes what kind of config the field holds (not a stutter).
## Behavior
Pure refactor. No behavior changes. All existing tests pass; unit tests for the new package are included.
`docker build .` passes (fmt-check, lint, test, build).
refs #39
Move HTTPFetcher, Config (was FetcherConfig), SSRF-safe dialer, rate
limiting, content-type validation, and related error vars from
internal/imgcache/fetcher.go into new internal/httpfetcher/ package.
The Fetcher interface and FetchResult type also move to httpfetcher
to avoid circular imports (imgcache imports httpfetcher, not the other
way around).
Renames to avoid stuttering:
NewHTTPFetcher -> httpfetcher.New
FetcherConfig -> httpfetcher.Config
NewMockFetcher -> httpfetcher.NewMock
The ServiceConfig.FetcherConfig field is retained (it describes what
kind of config it holds, not a stutter).
Pure refactor - no behavior changes. Unit tests for the httpfetcher
package are included.
refs #39
All new exported types/functions have godoc comments.
Scope of this PR
This PR refs (does not close) issue #39; it is one of four planned extractions (httpfetcher only here; signature/magic/urlparser land in separate PRs per the issue plan).
Move all related error values (ErrSSRFBlocked, ErrUpstreamError, ErrUpstreamTimeout, ErrResponseTooLarge, ErrInvalidContentType, ErrInvalidHost, ErrUnsupportedScheme)
Move Fetcher interface and FetchResult type into httpfetcher/ (confirmed removed from imgcache/imgcache.go, removed lines verified via diff)
Move MockFetcher and rename NewMockFetcher → NewMock
Naming convention compliance — constructors are New/NewMock, not stuttering
Update all import sites: internal/handlers/{handlers,image,imageenc,handlers_test}.go, internal/imgcache/{cache,cache_test,service,testutil_test}.go
No remaining references to imgcache.Fetcher/FetchResult/NewHTTPFetcher/DefaultFetcherConfig/FetcherConfig/NewMockFetcher/MockFetcher or relocated Err* values (grep confirmed zero matches)
Import edge is one-way: imgcache imports httpfetcher; httpfetcher does NOT import imgcache (confirmed by reading httpfetcher.go imports)
docker build . passes — fmt-check, lint, test, build all green
Pre-existing integration coverage of HTTPFetcher.Fetch (via imgcache service tests and handlers tests) is preserved. Coverage of internal helpers is strictly improved; no coverage regressed.
Diff integrity (pure refactor verification)
Compared main:internal/imgcache/fetcher.go (445 lines) and main:internal/imgcache/mock_fetcher.go against the new package files. Only changes are:
Package clause: imgcache → httpfetcher
Renames documented in the PR description (NewHTTPFetcher → New, FetcherConfig → Config, DefaultFetcherConfig → DefaultConfig, NewMockFetcher → NewMock)
Cosmetic doc comment tweaks (trailing periods; "whitelist" → "allow list" in the AllowedContentTypes comment on isAllowedContentType)
Package doc comment added
No behavior changes. No removed functionality. ServiceConfig.FetcherConfig field retained as stated.
Minor (non-blocking) description nits
The PR description lists some error/constant names that don't exist verbatim in the code (e.g. ErrPayloadTooLarge, ErrDisallowedContentType, DefaultMaxPayloadBytes). The actual names (retained from main) are ErrResponseTooLarge, ErrInvalidContentType, DefaultMaxResponseSize. Code is correct; the PR description is slightly imprecise but this is not a code defect.
Build result
docker build .
PASSED locally (fmt-check, lint, all tests, binary build, runtime image all succeed).
Final verdict
PASS — clean, reviewable pure-refactor extraction. Import edge is correctly one-way, naming follows the project's no-stutter convention, exports are documented, tests are additive (improved coverage for internal helpers), no linter/CI/test integrity violations, docker build . is green, and the PR branch applies cleanly on top of current main (already up-to-date, no rebase needed).
## Review: PR #43 (reviewer:pixa)
### Policy divergences
No policy violations found.
Verified:
- No changes to `.golangci.yml`, `Makefile`, `Dockerfile`, or `.gitea/` workflows (no cheating).
- New package lives under `internal/` per canonical subdirectory layout.
- `New` constructor is not stuttering (no `NewHTTPFetcher`).
- `ServiceConfig.FetcherConfig` field name retained — describes what kind of config the field holds, not a stutter.
- Package comment present on [`httpfetcher.go:1-2`](https://git.eeqj.de/sneak/pixa/src/branch/refactor/extract-httpfetcher/internal/httpfetcher/httpfetcher.go).
- All new exported types/functions have godoc comments.
### Scope of this PR
This PR refs (does not close) [issue #39](https://git.eeqj.de/sneak/pixa/issues/39); it is one of four planned extractions (httpfetcher only here; signature/magic/urlparser land in separate PRs per the issue plan).
### Itemized requirements checklist (issue #39, httpfetcher only)
- [x] Create `internal/httpfetcher/` package — [`internal/httpfetcher/httpfetcher.go`](https://git.eeqj.de/sneak/pixa/src/branch/refactor/extract-httpfetcher/internal/httpfetcher/httpfetcher.go)
- [x] Move `HTTPFetcher`, `FetcherConfig`→`Config`, `DefaultFetcherConfig`→`DefaultConfig`
- [x] Move SSRF-safe dialer (`ssrfSafeDialer`, `validateURL`, `isPrivateIP`, `isLocalhost`, `extractHost`)
- [x] Move per-host connection semaphore and `limitedReader`
- [x] Move content-type validation (`isAllowedContentType`, `detectContentTypeFromPath`)
- [x] Move all related error values (`ErrSSRFBlocked`, `ErrUpstreamError`, `ErrUpstreamTimeout`, `ErrResponseTooLarge`, `ErrInvalidContentType`, `ErrInvalidHost`, `ErrUnsupportedScheme`)
- [x] Move `Fetcher` interface and `FetchResult` type into `httpfetcher/` (confirmed removed from `imgcache/imgcache.go`, removed lines verified via diff)
- [x] Move `MockFetcher` and rename `NewMockFetcher` → `NewMock`
- [x] Naming convention compliance — constructors are `New`/`NewMock`, not stuttering
- [x] Update all import sites: `internal/handlers/{handlers,image,imageenc,handlers_test}.go`, `internal/imgcache/{cache,cache_test,service,testutil_test}.go`
- [x] No remaining references to `imgcache.Fetcher`/`FetchResult`/`NewHTTPFetcher`/`DefaultFetcherConfig`/`FetcherConfig`/`NewMockFetcher`/`MockFetcher` or relocated `Err*` values (grep confirmed zero matches)
- [x] Import edge is one-way: `imgcache` imports `httpfetcher`; `httpfetcher` does NOT import `imgcache` (confirmed by reading `httpfetcher.go` imports)
- [x] `docker build .` passes — fmt-check, lint, test, build all green
### Tests
New unit tests in [`internal/httpfetcher/httpfetcher_test.go`](https://git.eeqj.de/sneak/pixa/src/branch/refactor/extract-httpfetcher/internal/httpfetcher/httpfetcher_test.go) cover:
- `DefaultConfig` defaults
- `New(nil)` falls back to defaults (constructor happy path)
- `isAllowedContentType` (table test, 8 cases)
- `extractHost` (table test, 6 cases)
- `isLocalhost` (table test, 9 cases)
- `isPrivateIP` (table test, 11 cases + nil)
- `validateURL` (HTTP reject, AllowHTTP override, localhost, empty host)
- `MockFetcher` + `NewMock` (file fetch, missing file, context cancel)
- `detectContentTypeFromPath` (table test, 10 cases)
- `limitedReader` limit enforcement
Pre-existing integration coverage of `HTTPFetcher.Fetch` (via `imgcache` service tests and `handlers` tests) is preserved. Coverage of internal helpers is strictly improved; no coverage regressed.
### Diff integrity (pure refactor verification)
Compared `main:internal/imgcache/fetcher.go` (445 lines) and `main:internal/imgcache/mock_fetcher.go` against the new package files. Only changes are:
- Package clause: `imgcache` → `httpfetcher`
- Renames documented in the PR description (`NewHTTPFetcher` → `New`, `FetcherConfig` → `Config`, `DefaultFetcherConfig` → `DefaultConfig`, `NewMockFetcher` → `NewMock`)
- Cosmetic doc comment tweaks (trailing periods; "whitelist" → "allow list" in the `AllowedContentTypes` comment on `isAllowedContentType`)
- Package doc comment added
No behavior changes. No removed functionality. `ServiceConfig.FetcherConfig` field retained as stated.
### Minor (non-blocking) description nits
The PR description lists some error/constant names that don't exist verbatim in the code (e.g. `ErrPayloadTooLarge`, `ErrDisallowedContentType`, `DefaultMaxPayloadBytes`). The actual names (retained from `main`) are `ErrResponseTooLarge`, `ErrInvalidContentType`, `DefaultMaxResponseSize`. Code is correct; the PR description is slightly imprecise but this is not a code defect.
### Build result
```
docker build .
```
**PASSED** locally (fmt-check, lint, all tests, binary build, runtime image all succeed).
### Final verdict
**PASS** — clean, reviewable pure-refactor extraction. Import edge is correctly one-way, naming follows the project's no-stutter convention, exports are documented, tests are additive (improved coverage for internal helpers), no linter/CI/test integrity violations, `docker build .` is green, and the PR branch applies cleanly on top of current `main` (already up-to-date, no rebase needed).
Review: PR #43 — extract httpfetcher from imgcache
Verdict: Merge-ready.
Independent re-review of head a853fe7. This is a clean, behavior-preserving package extraction — the first of four planned in issue #39 (httpfetcher only here; signature/magic/urlparser to follow in separate PRs). Verified against REPO_POLICIES.md and the issue's extraction plan by reading the head sources directly.
Findings
Policy compliance: No changes to .golangci.yml, Makefile, Dockerfile, or .gitea/workflows/ — the checks are not weakened. The new package lives under internal/httpfetcher/ per the canonical subdirectory layout. Package doc comment present; all exported identifiers carry godoc. No new external dependencies, so the hash-pinning rule is not engaged.
Import edge (one-way): Confirmed by reading the head sources, not just the description. internal/httpfetcher/httpfetcher.go and internal/httpfetcher/mock.go import only the standard library — neither imports imgcache. imgcache imports httpfetcher (cache.go, service.go, and the tests). The edge is imgcache → httpfetcher, never the reverse, exactly as intended.
Naming (no stutter): Constructors are New, NewMock, and DefaultConfig — not NewHTTPFetcher/DefaultFetcherConfig. ServiceConfig.FetcherConfig is correctly retained (it names the kind of config the field holds, not a stutter).
Behavior-preserving: The moved code is identical apart from the package clause, the documented renames (FetcherConfig→Config, DefaultFetcherConfig→DefaultConfig, NewHTTPFetcher→New, NewMockFetcher→NewMock), and cosmetic doc-comment tweaks (trailing periods, "whitelist"→"allow list"). The Fetcher interface and FetchResult type were relocated out of imgcache.go into the new package (removal confirmed in the diff) to keep the edge one-way. All call sites updated: handlers/{handlers,image,imageenc,handlers_test}.go and imgcache/{cache,cache_test,service,testutil_test}.go.
Tests: New internal/httpfetcher/httpfetcher_test.go adds table-driven unit coverage for DefaultConfig, New(nil), isAllowedContentType, extractHost, isLocalhost, isPrivateIP, validateURL, detectContentTypeFromPath, limitedReader, and the MockFetcher/NewMock path. HTTPFetcher.Fetch's full HTTP path remains covered by the existing imgcache/handlers integration tests. Coverage of internal helpers is improved; none regressed.
CI status:check / check (push) is green on head a853fe7 (success, 57s). Since the Dockerfile runs make check (fmt-check, lint, test, build), a passing docker build . implies all checks pass.
Mergeability:mergeable = true; the branch applies on top of current main (504afea) with no conflict. Not a draft.
Non-blocking note
The PR description lists a few error/constant names that do not appear verbatim in the code (ErrPayloadTooLarge, ErrDisallowedContentType, DefaultMaxPayloadBytes); the actual retained names are ErrResponseTooLarge, ErrInvalidContentType, and DefaultMaxResponseSize. This is a description imprecision only — the code and every call site are internally consistent and correct. Worth tidying the description, but not a merge blocker.
Applied label merge-ready (id 48); assigned to sneak.
## Review: PR #43 — extract `httpfetcher` from `imgcache`
**Verdict: Merge-ready.**
Independent re-review of head `a853fe7`. This is a clean, behavior-preserving package extraction — the first of four planned in [issue #39](https://git.eeqj.de/sneak/pixa/issues/39) (`httpfetcher` only here; `signature`/`magic`/`urlparser` to follow in separate PRs). Verified against `REPO_POLICIES.md` and the issue's extraction plan by reading the head sources directly.
### Findings
- **Policy compliance:** No changes to `.golangci.yml`, `Makefile`, `Dockerfile`, or `.gitea/workflows/` — the checks are not weakened. The new package lives under `internal/httpfetcher/` per the canonical subdirectory layout. Package doc comment present; all exported identifiers carry godoc. No new external dependencies, so the hash-pinning rule is not engaged.
- **Import edge (one-way):** Confirmed by reading the head sources, not just the description. `internal/httpfetcher/httpfetcher.go` and `internal/httpfetcher/mock.go` import only the standard library — neither imports `imgcache`. `imgcache` imports `httpfetcher` (`cache.go`, `service.go`, and the tests). The edge is `imgcache → httpfetcher`, never the reverse, exactly as intended.
- **Naming (no stutter):** Constructors are `New`, `NewMock`, and `DefaultConfig` — not `NewHTTPFetcher`/`DefaultFetcherConfig`. `ServiceConfig.FetcherConfig` is correctly retained (it names the kind of config the field holds, not a stutter).
- **Behavior-preserving:** The moved code is identical apart from the package clause, the documented renames (`FetcherConfig`→`Config`, `DefaultFetcherConfig`→`DefaultConfig`, `NewHTTPFetcher`→`New`, `NewMockFetcher`→`NewMock`), and cosmetic doc-comment tweaks (trailing periods, "whitelist"→"allow list"). The `Fetcher` interface and `FetchResult` type were relocated out of `imgcache.go` into the new package (removal confirmed in the diff) to keep the edge one-way. All call sites updated: `handlers/{handlers,image,imageenc,handlers_test}.go` and `imgcache/{cache,cache_test,service,testutil_test}.go`.
- **Tests:** New `internal/httpfetcher/httpfetcher_test.go` adds table-driven unit coverage for `DefaultConfig`, `New(nil)`, `isAllowedContentType`, `extractHost`, `isLocalhost`, `isPrivateIP`, `validateURL`, `detectContentTypeFromPath`, `limitedReader`, and the `MockFetcher`/`NewMock` path. `HTTPFetcher.Fetch`'s full HTTP path remains covered by the existing `imgcache`/`handlers` integration tests. Coverage of internal helpers is improved; none regressed.
- **CI status:** `check / check (push)` is green on head `a853fe7` (success, 57s). Since the `Dockerfile` runs `make check` (fmt-check, lint, test, build), a passing `docker build .` implies all checks pass.
- **Mergeability:** `mergeable = true`; the branch applies on top of current `main` (`504afea`) with no conflict. Not a draft.
### Non-blocking note
The PR description lists a few error/constant names that do not appear verbatim in the code (`ErrPayloadTooLarge`, `ErrDisallowedContentType`, `DefaultMaxPayloadBytes`); the actual retained names are `ErrResponseTooLarge`, `ErrInvalidContentType`, and `DefaultMaxResponseSize`. This is a description imprecision only — the code and every call site are internally consistent and correct. Worth tidying the description, but not a merge blocker.
---
Applied label `merge-ready` (id 48); assigned to `sneak`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Extracts the HTTP fetcher concern out of
internal/imgcache/into its owninternal/httpfetcher/package, per the plan in issue #39.This is one of four planned extractions; only the fetcher is moved here so the diff stays reviewable. The remaining three (signature, magic, urlparser) will land in separate PRs.
What moved
From
internal/imgcache/fetcher.goandinternal/imgcache/mock_fetcher.gointointernal/httpfetcher/:HTTPFetchertype, itsNewconstructor, andConfig(formerlyFetcherConfig) withDefaultConfigvalidateURL,isPrivateIP,isLocalhost,extractHostlimitedReaderisAllowedContentType,detectContentTypeFromPath)ErrSSRFBlocked,ErrUpstreamError,ErrUpstreamTimeout,ErrPayloadTooLarge,ErrDisallowedContentType)DefaultFetchTimeout,DefaultMaxPayloadBytes,DefaultMaxConnectionsPerHost, etc.)Fetcherinterface andFetchResulttype (moved here to keep the import edge one-way:imgcachedepends onhttpfetcher, never the reverse)MockFetchertest helperRenames (no stuttering)
NewHTTPFetcher→httpfetcher.NewFetcherConfig→httpfetcher.ConfigDefaultFetcherConfig→httpfetcher.DefaultConfigNewMockFetcher→httpfetcher.NewMockThe
ServiceConfig.FetcherConfigfield name is retained — it describes what kind of config the field holds (not a stutter).Behavior
Pure refactor. No behavior changes. All existing tests pass; unit tests for the new package are included.
docker build .passes (fmt-check, lint, test, build).refs #39
Review: PR #43 (reviewer:pixa)
Policy divergences
No policy violations found.
Verified:
.golangci.yml,Makefile,Dockerfile, or.gitea/workflows (no cheating).internal/per canonical subdirectory layout.Newconstructor is not stuttering (noNewHTTPFetcher).ServiceConfig.FetcherConfigfield name retained — describes what kind of config the field holds, not a stutter.httpfetcher.go:1-2.Scope of this PR
This PR refs (does not close) issue #39; it is one of four planned extractions (httpfetcher only here; signature/magic/urlparser land in separate PRs per the issue plan).
Itemized requirements checklist (issue #39, httpfetcher only)
internal/httpfetcher/package —internal/httpfetcher/httpfetcher.goHTTPFetcher,FetcherConfig→Config,DefaultFetcherConfig→DefaultConfigssrfSafeDialer,validateURL,isPrivateIP,isLocalhost,extractHost)limitedReaderisAllowedContentType,detectContentTypeFromPath)ErrSSRFBlocked,ErrUpstreamError,ErrUpstreamTimeout,ErrResponseTooLarge,ErrInvalidContentType,ErrInvalidHost,ErrUnsupportedScheme)Fetcherinterface andFetchResulttype intohttpfetcher/(confirmed removed fromimgcache/imgcache.go, removed lines verified via diff)MockFetcherand renameNewMockFetcher→NewMockNew/NewMock, not stutteringinternal/handlers/{handlers,image,imageenc,handlers_test}.go,internal/imgcache/{cache,cache_test,service,testutil_test}.goimgcache.Fetcher/FetchResult/NewHTTPFetcher/DefaultFetcherConfig/FetcherConfig/NewMockFetcher/MockFetcheror relocatedErr*values (grep confirmed zero matches)imgcacheimportshttpfetcher;httpfetcherdoes NOT importimgcache(confirmed by readinghttpfetcher.goimports)docker build .passes — fmt-check, lint, test, build all greenTests
New unit tests in
internal/httpfetcher/httpfetcher_test.gocover:DefaultConfigdefaultsNew(nil)falls back to defaults (constructor happy path)isAllowedContentType(table test, 8 cases)extractHost(table test, 6 cases)isLocalhost(table test, 9 cases)isPrivateIP(table test, 11 cases + nil)validateURL(HTTP reject, AllowHTTP override, localhost, empty host)MockFetcher+NewMock(file fetch, missing file, context cancel)detectContentTypeFromPath(table test, 10 cases)limitedReaderlimit enforcementPre-existing integration coverage of
HTTPFetcher.Fetch(viaimgcacheservice tests andhandlerstests) is preserved. Coverage of internal helpers is strictly improved; no coverage regressed.Diff integrity (pure refactor verification)
Compared
main:internal/imgcache/fetcher.go(445 lines) andmain:internal/imgcache/mock_fetcher.goagainst the new package files. Only changes are:imgcache→httpfetcherNewHTTPFetcher→New,FetcherConfig→Config,DefaultFetcherConfig→DefaultConfig,NewMockFetcher→NewMock)AllowedContentTypescomment onisAllowedContentType)No behavior changes. No removed functionality.
ServiceConfig.FetcherConfigfield retained as stated.Minor (non-blocking) description nits
The PR description lists some error/constant names that don't exist verbatim in the code (e.g.
ErrPayloadTooLarge,ErrDisallowedContentType,DefaultMaxPayloadBytes). The actual names (retained frommain) areErrResponseTooLarge,ErrInvalidContentType,DefaultMaxResponseSize. Code is correct; the PR description is slightly imprecise but this is not a code defect.Build result
PASSED locally (fmt-check, lint, all tests, binary build, runtime image all succeed).
Final verdict
PASS — clean, reviewable pure-refactor extraction. Import edge is correctly one-way, naming follows the project's no-stutter convention, exports are documented, tests are additive (improved coverage for internal helpers), no linter/CI/test integrity violations,
docker build .is green, and the PR branch applies cleanly on top of currentmain(already up-to-date, no rebase needed).Review: PR #43 — extract
httpfetcherfromimgcacheVerdict: Merge-ready.
Independent re-review of head
a853fe7. This is a clean, behavior-preserving package extraction — the first of four planned in issue #39 (httpfetcheronly here;signature/magic/urlparserto follow in separate PRs). Verified againstREPO_POLICIES.mdand the issue's extraction plan by reading the head sources directly.Findings
.golangci.yml,Makefile,Dockerfile, or.gitea/workflows/— the checks are not weakened. The new package lives underinternal/httpfetcher/per the canonical subdirectory layout. Package doc comment present; all exported identifiers carry godoc. No new external dependencies, so the hash-pinning rule is not engaged.internal/httpfetcher/httpfetcher.goandinternal/httpfetcher/mock.goimport only the standard library — neither importsimgcache.imgcacheimportshttpfetcher(cache.go,service.go, and the tests). The edge isimgcache → httpfetcher, never the reverse, exactly as intended.New,NewMock, andDefaultConfig— notNewHTTPFetcher/DefaultFetcherConfig.ServiceConfig.FetcherConfigis correctly retained (it names the kind of config the field holds, not a stutter).FetcherConfig→Config,DefaultFetcherConfig→DefaultConfig,NewHTTPFetcher→New,NewMockFetcher→NewMock), and cosmetic doc-comment tweaks (trailing periods, "whitelist"→"allow list"). TheFetcherinterface andFetchResulttype were relocated out ofimgcache.gointo the new package (removal confirmed in the diff) to keep the edge one-way. All call sites updated:handlers/{handlers,image,imageenc,handlers_test}.goandimgcache/{cache,cache_test,service,testutil_test}.go.internal/httpfetcher/httpfetcher_test.goadds table-driven unit coverage forDefaultConfig,New(nil),isAllowedContentType,extractHost,isLocalhost,isPrivateIP,validateURL,detectContentTypeFromPath,limitedReader, and theMockFetcher/NewMockpath.HTTPFetcher.Fetch's full HTTP path remains covered by the existingimgcache/handlersintegration tests. Coverage of internal helpers is improved; none regressed.check / check (push)is green on heada853fe7(success, 57s). Since theDockerfilerunsmake check(fmt-check, lint, test, build), a passingdocker build .implies all checks pass.mergeable = true; the branch applies on top of currentmain(504afea) with no conflict. Not a draft.Non-blocking note
The PR description lists a few error/constant names that do not appear verbatim in the code (
ErrPayloadTooLarge,ErrDisallowedContentType,DefaultMaxPayloadBytes); the actual retained names areErrResponseTooLarge,ErrInvalidContentType, andDefaultMaxResponseSize. This is a description imprecision only — the code and every call site are internally consistent and correct. Worth tidying the description, but not a merge blocker.Applied label
merge-ready(id 48); assigned tosneak.