4 Commits

Author SHA1 Message Date
user
c4368b1541 chore: remove local dev config files
Remove config.yaml and config.dev.yml (local development configs with
hardcoded keys that shouldn't be committed). config.example.yml remains
as the canonical example config. Added removed files to .gitignore.
2026-02-20 02:59:30 -08:00
2fb36c5ccb Merge pull request 'fix: propagate AllowHTTP to SourceURL() scheme selection (closes #1)' (#6) from fix/issue-1 into main
Reviewed-on: #6
2026-02-09 01:41:31 +01:00
clawbot
40c4b53b01 fix: propagate AllowHTTP to SourceURL() scheme selection
SourceURL() previously hardcoded https:// regardless of the AllowHTTP
config setting. This made testing with HTTP-only test servers impossible.

Add AllowHTTP field to ImageRequest and use it to determine the URL
scheme. The Service propagates the config setting to each request.

Fixes #1
2026-02-08 16:34:42 -08:00
b800ef86d8 Merge pull request 'fix: check negative cache in Service.Get() before fetching upstream (closes #3)' (#8) from fix/issue-3 into main
Reviewed-on: #8
2026-02-09 01:32:26 +01:00
6 changed files with 67 additions and 23 deletions

4
.gitignore vendored
View File

@@ -18,3 +18,7 @@ vendor/
# Data
/data/
*.sqlite3
# Local dev configs
config.yaml
config.dev.yml

View File

@@ -1,11 +0,0 @@
# Development config for local Docker testing
signing_key: "dev-signing-key-minimum-32-chars!"
debug: true
allow_http: true
whitelist_hosts:
- localhost
- s3.sneak.cloud
- static.sneak.cloud
- sneak.berlin
- github.com
- user-images.githubusercontent.com

View File

@@ -1,10 +0,0 @@
debug: true
port: 8080
state_dir: ./data
signing_key: "test-signing-key-for-development-only"
whitelist_hosts:
- "*.example.com"
- "images.unsplash.com"
- "picsum.photos"
- "s3.sneak.cloud"
allow_http: false

View File

@@ -79,11 +79,18 @@ type ImageRequest struct {
Signature string
// Expires is the signature expiration timestamp
Expires time.Time
// AllowHTTP indicates whether HTTP (non-TLS) is allowed for this request
AllowHTTP bool
}
// SourceURL returns the full upstream URL to fetch
// SourceURL returns the full upstream URL to fetch.
// Uses http:// scheme when AllowHTTP is true, otherwise https://.
func (r *ImageRequest) SourceURL() string {
url := "https://" + r.SourceHost + r.SourcePath
scheme := "https"
if r.AllowHTTP {
scheme = "http"
}
url := scheme + "://" + r.SourceHost + r.SourcePath
if r.SourceQuery != "" {
url += "?" + r.SourceQuery
}

View File

@@ -21,6 +21,7 @@ type Service struct {
signer *Signer
whitelist *HostWhitelist
log *slog.Logger
allowHTTP bool
}
// ServiceConfig holds configuration for the image service.
@@ -68,6 +69,11 @@ func NewService(cfg *ServiceConfig) (*Service, error) {
log = slog.Default()
}
allowHTTP := false
if cfg.FetcherConfig != nil {
allowHTTP = cfg.FetcherConfig.AllowHTTP
}
return &Service{
cache: cfg.Cache,
fetcher: fetcher,
@@ -75,6 +81,7 @@ func NewService(cfg *ServiceConfig) (*Service, error) {
signer: signer,
whitelist: NewHostWhitelist(cfg.Whitelist),
log: log,
allowHTTP: allowHTTP,
}, nil
}
@@ -83,6 +90,9 @@ var ErrNegativeCached = errors.New("request is in negative cache (recently faile
// Get retrieves a processed image, fetching and processing if necessary.
func (s *Service) Get(ctx context.Context, req *ImageRequest) (*ImageResponse, error) {
// Propagate AllowHTTP setting to the request
req.AllowHTTP = s.allowHTTP
// Check negative cache first - skip fetching for recently-failed URLs
negHit, err := s.cache.checkNegativeCache(ctx, req)
if err != nil {

View File

@@ -0,0 +1,44 @@
package imgcache
import "testing"
func TestImageRequest_SourceURL_DefaultHTTPS(t *testing.T) {
req := &ImageRequest{
SourceHost: "cdn.example.com",
SourcePath: "/photos/cat.jpg",
SourceQuery: "v=2",
}
got := req.SourceURL()
want := "https://cdn.example.com/photos/cat.jpg?v=2"
if got != want {
t.Errorf("SourceURL() = %q, want %q", got, want)
}
}
func TestImageRequest_SourceURL_AllowHTTP(t *testing.T) {
req := &ImageRequest{
SourceHost: "localhost:8080",
SourcePath: "/photos/cat.jpg",
AllowHTTP: true,
}
got := req.SourceURL()
want := "http://localhost:8080/photos/cat.jpg"
if got != want {
t.Errorf("SourceURL() = %q, want %q", got, want)
}
}
func TestImageRequest_SourceURL_AllowHTTPFalse(t *testing.T) {
req := &ImageRequest{
SourceHost: "cdn.example.com",
SourcePath: "/img.jpg",
AllowHTTP: false,
}
got := req.SourceURL()
if got != "https://cdn.example.com/img.jpg" {
t.Errorf("SourceURL() = %q, want https scheme", got)
}
}