// samsa — a privacy-respecting metasearch engine // Copyright (C) 2026-present metamorphosis-dev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . package httpclient import ( "net/http" "sync" "time" ) var ( defaultTransport http.RoundTripper once sync.Once ) // Default returns a shared, pre-configured http.RoundTripper suitable for // outgoing engine requests. It is safe for concurrent use across goroutines. // All fields are tuned for a meta-search engine that makes many concurrent // requests to a fixed set of upstream hosts: // // - MaxIdleConnsPerHost = 20 (vs default of 2; keeps more warm connections // to each host, avoiding repeated TCP+TLS handshakes) // - MaxIdleConns = 100 (total idle connection ceiling) // - IdleConnTimeout = 90s (prunes connections before they go stale) // - DialContext timeout = 5s (fails fast on DNS/connect rather than // holding a goroutine indefinitely) func Default() http.RoundTripper { once.Do(func() { defaultTransport = &http.Transport{ MaxIdleConnsPerHost: 20, MaxIdleConns: 100, IdleConnTimeout: 90 * time.Second, DialContext: dialWithTimeout(5 * time.Second), } }) return defaultTransport } // NewClient returns an http.Client that uses DefaultTransport and the given // request timeout. The returned client reuses the shared connection pool, // so all clients created via this function share the same warm connections. func NewClient(timeout time.Duration) *http.Client { return &http.Client{ Transport: Default(), Timeout: timeout, } }