diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 2ddac960..42813b1a 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -1607,12 +1607,22 @@ func TestMediaProxyHTTPClientTimeout(t *testing.T) { t.Fatalf(`Parsing failure: %v`, err) } - expected := 24 + expected := 24 * time.Second result := opts.MediaProxyHTTPClientTimeout() if result != expected { t.Fatalf(`Unexpected MEDIA_PROXY_HTTP_CLIENT_TIMEOUT value, got %d instead of %d`, result, expected) } + + sorted := opts.SortedOptions(false) + i := slices.IndexFunc(sorted, func(opt *option) bool { + return opt.Key == "MEDIA_PROXY_HTTP_CLIENT_TIMEOUT" + }) + + expectedSerialized := 24 + if got := sorted[i].Value; got != expectedSerialized { + t.Fatalf(`Unexpected value in option output, got %q instead of %q`, got, expectedSerialized) + } } func TestDefaultMediaProxyHTTPClientTimeoutValue(t *testing.T) { @@ -1630,6 +1640,16 @@ func TestDefaultMediaProxyHTTPClientTimeoutValue(t *testing.T) { if result != expected { t.Fatalf(`Unexpected MEDIA_PROXY_HTTP_CLIENT_TIMEOUT value, got %d instead of %d`, result, expected) } + + sorted := opts.SortedOptions(false) + i := slices.IndexFunc(sorted, func(opt *option) bool { + return opt.Key == "MEDIA_PROXY_HTTP_CLIENT_TIMEOUT" + }) + + expectedSerialized := int(defaultMediaProxyHTTPClientTimeout / time.Second) + if got := sorted[i].Value; got != expectedSerialized { + t.Fatalf(`Unexpected value in option output, got %q instead of %q`, got, expectedSerialized) + } } func TestMediaProxyCustomURL(t *testing.T) { @@ -1706,12 +1726,22 @@ func TestHTTPClientTimeout(t *testing.T) { t.Fatalf(`Parsing failure: %v`, err) } - expected := 42 + expected := 42 * time.Second result := opts.HTTPClientTimeout() if result != expected { t.Fatalf(`Unexpected HTTP_CLIENT_TIMEOUT value, got %d instead of %d`, result, expected) } + + sorted := opts.SortedOptions(false) + i := slices.IndexFunc(sorted, func(opt *option) bool { + return opt.Key == "HTTP_CLIENT_TIMEOUT" + }) + + expectedSerialized := 42 + if got := sorted[i].Value; got != expectedSerialized { + t.Fatalf(`Unexpected value in option output, got %q instead of %q`, got, expectedSerialized) + } } func TestDefaultHTTPClientTimeoutValue(t *testing.T) { diff --git a/internal/config/options.go b/internal/config/options.go index 594f5286..626d0000 100644 --- a/internal/config/options.go +++ b/internal/config/options.go @@ -52,7 +52,7 @@ const ( defaultCleanupArchiveUnreadDays = 180 defaultCleanupArchiveBatchSize = 10000 defaultCleanupRemoveSessionsDays = 30 - defaultMediaProxyHTTPClientTimeout = 120 + defaultMediaProxyHTTPClientTimeout = 120 * time.Second defaultMediaProxyMode = "http-only" defaultMediaResourceTypes = "image" defaultMediaProxyURL = "" @@ -74,7 +74,7 @@ const ( defaultOauth2OidcProviderName = "OpenID Connect" defaultOAuth2Provider = "" defaultDisableLocalAuth = false - defaultHTTPClientTimeout = 20 + defaultHTTPClientTimeout = 20 * time.Second defaultHTTPClientMaxBodySize = 15 defaultHTTPClientProxy = "" defaultHTTPServerTimeout = 300 * time.Second @@ -145,7 +145,7 @@ type options struct { createAdmin bool adminUsername string adminPassword string - mediaProxyHTTPClientTimeout int + mediaProxyHTTPClientTimeout time.Duration mediaProxyMode string mediaProxyResourceTypes []string mediaProxyCustomURL *url.URL @@ -165,7 +165,7 @@ type options struct { oidcProviderName string oauth2Provider string disableLocalAuth bool - httpClientTimeout int + httpClientTimeout time.Duration httpClientMaxBodySize int64 httpClientProxyURL *url.URL httpClientProxies []string @@ -567,8 +567,8 @@ func (o *options) MediaCustomProxyURL() *url.URL { return o.mediaProxyCustomURL } -// MediaProxyHTTPClientTimeout returns the time limit in seconds before the proxy HTTP client cancel the request. -func (o *options) MediaProxyHTTPClientTimeout() int { +// MediaProxyHTTPClientTimeout returns the time limit before the proxy HTTP client cancel the request. +func (o *options) MediaProxyHTTPClientTimeout() time.Duration { return o.mediaProxyHTTPClientTimeout } @@ -588,7 +588,7 @@ func (o *options) HasSchedulerService() bool { } // HTTPClientTimeout returns the time limit in seconds before the HTTP client cancel the request. -func (o *options) HTTPClientTimeout() int { +func (o *options) HTTPClientTimeout() time.Duration { return o.httpClientTimeout } @@ -743,7 +743,7 @@ func (o *options) SortedOptions(redactSecret bool) []*option { "HTTP_CLIENT_MAX_BODY_SIZE": o.httpClientMaxBodySize, "HTTP_CLIENT_PROXIES": clientProxyURLsRedacted, "HTTP_CLIENT_PROXY": clientProxyURLRedacted, - "HTTP_CLIENT_TIMEOUT": o.httpClientTimeout, + "HTTP_CLIENT_TIMEOUT": int(o.httpClientTimeout.Seconds()), "HTTP_CLIENT_USER_AGENT": o.httpClientUserAgent, "HTTP_SERVER_TIMEOUT": int(o.httpServerTimeout.Seconds()), "HTTP_SERVICE": o.httpService, @@ -774,7 +774,7 @@ func (o *options) SortedOptions(redactSecret bool) []*option { "POLLING_LIMIT_PER_HOST": o.pollingLimitPerHost, "POLLING_PARSING_ERROR_LIMIT": o.pollingParsingErrorLimit, "POLLING_SCHEDULER": o.pollingScheduler, - "MEDIA_PROXY_HTTP_CLIENT_TIMEOUT": o.mediaProxyHTTPClientTimeout, + "MEDIA_PROXY_HTTP_CLIENT_TIMEOUT": int(o.mediaProxyHTTPClientTimeout.Seconds()), "MEDIA_PROXY_RESOURCE_TYPES": o.mediaProxyResourceTypes, "MEDIA_PROXY_MODE": o.mediaProxyMode, "MEDIA_PROXY_PRIVATE_KEY": mediaProxyPrivateKeyValue, diff --git a/internal/config/parser.go b/internal/config/parser.go index 71a207c2..3f913ff5 100644 --- a/internal/config/parser.go +++ b/internal/config/parser.go @@ -161,7 +161,7 @@ func (p *parser) parseLines(lines []string) (err error) { case "SCHEDULER_ROUND_ROBIN_MAX_INTERVAL": p.opts.schedulerRoundRobinMaxInterval = parseInterval(value, time.Minute, defaultSchedulerRoundRobinMaxInterval) case "MEDIA_PROXY_HTTP_CLIENT_TIMEOUT": - p.opts.mediaProxyHTTPClientTimeout = parseInt(value, defaultMediaProxyHTTPClientTimeout) + p.opts.mediaProxyHTTPClientTimeout = parseInterval(value, time.Second, defaultMediaProxyHTTPClientTimeout) case "MEDIA_PROXY_MODE": p.opts.mediaProxyMode = parseString(value, defaultMediaProxyMode) case "MEDIA_PROXY_RESOURCE_TYPES": @@ -206,7 +206,7 @@ func (p *parser) parseLines(lines []string) (err error) { case "DISABLE_LOCAL_AUTH": p.opts.disableLocalAuth = parseBool(value, defaultDisableLocalAuth) case "HTTP_CLIENT_TIMEOUT": - p.opts.httpClientTimeout = parseInt(value, defaultHTTPClientTimeout) + p.opts.httpClientTimeout = parseInterval(value, time.Second, defaultHTTPClientTimeout) case "HTTP_CLIENT_MAX_BODY_SIZE": p.opts.httpClientMaxBodySize = int64(parseInt(value, defaultHTTPClientMaxBodySize) * 1024 * 1024) case "HTTP_CLIENT_PROXY": diff --git a/internal/reader/fetcher/request_builder.go b/internal/reader/fetcher/request_builder.go index 4a602d56..a05d7edf 100644 --- a/internal/reader/fetcher/request_builder.go +++ b/internal/reader/fetcher/request_builder.go @@ -18,14 +18,14 @@ import ( ) const ( - defaultHTTPClientTimeout = 20 + defaultHTTPClientTimeout = 20 * time.Second defaultAcceptHeader = "application/xml, application/atom+xml, application/rss+xml, application/rdf+xml, application/feed+json, text/html, */*;q=0.9" ) type RequestBuilder struct { headers http.Header clientProxyURL *url.URL - clientTimeout int + clientTimeout time.Duration useClientProxy bool withoutRedirects bool ignoreTLSErrors bool @@ -104,7 +104,7 @@ func (r *RequestBuilder) WithCustomFeedProxyURL(proxyURL string) *RequestBuilder return r } -func (r *RequestBuilder) WithTimeout(timeout int) *RequestBuilder { +func (r *RequestBuilder) WithTimeout(timeout time.Duration) *RequestBuilder { r.clientTimeout = timeout return r } @@ -185,7 +185,7 @@ func (r *RequestBuilder) ExecuteRequest(requestURL string) (*http.Response, erro } client := &http.Client{ - Timeout: time.Duration(r.clientTimeout) * time.Second, + Timeout: r.clientTimeout, } if r.withoutRedirects { diff --git a/internal/reader/fetcher/request_builder_test.go b/internal/reader/fetcher/request_builder_test.go index 229383f3..675e2f11 100644 --- a/internal/reader/fetcher/request_builder_test.go +++ b/internal/reader/fetcher/request_builder_test.go @@ -232,9 +232,9 @@ func TestRequestBuilder_CustomAcceptHeaderNotOverridden(t *testing.T) { func TestRequestBuilder_WithTimeout(t *testing.T) { builder := NewRequestBuilder() - builder = builder.WithTimeout(30) + builder = builder.WithTimeout(30 * time.Second) - if builder.clientTimeout != 30 { + if builder.clientTimeout != 30*time.Second { t.Errorf("Expected timeout to be 30, got %d", builder.clientTimeout) } } @@ -382,9 +382,8 @@ func TestRequestBuilder_ChainedMethods(t *testing.T) { WithUserAgent("TestAgent/1.0", "DefaultAgent/1.0"). WithCookie("test=value"). WithETag("etag123"). - WithTimeout(10). + WithTimeout(10 * time.Second). ExecuteRequest(server.URL) - if err != nil { t.Fatalf("Expected no error, got %v", err) } @@ -409,7 +408,7 @@ func TestRequestBuilder_TimeoutConfiguration(t *testing.T) { builder := NewRequestBuilder() start := time.Now() - _, err := builder.WithTimeout(1).ExecuteRequest(server.URL) + _, err := builder.WithTimeout(1 * time.Second).ExecuteRequest(server.URL) duration := time.Since(start) if err == nil {