deferInLoop was disabled in .golangci.yml, so CI could not catch defer
statements added inside for loops. Such defers run only at function exit,
not per iteration, leaking file descriptors, connections, or locks under
load.
Re-enable the check and fix the two existing occurrences in test code
instead of excluding test files:
- inmemory listener test: deferred conn.Close() inside the accept loop;
move the per-connection handling into a closure so each connection is
closed when done.
- TestClientManyServers: every server must stay up until the test ends,
so hoist the defer out of the loop and stop all servers in a single
deferred loop.
Fixes#2233
Signed-off-by: Y.Horie <u5.horie@gmail.com>
Per RFC 9110 section 15.4.4, a 303 (See Other) response must be followed
by a body-less GET regardless of the original method. Handle 303
explicitly: change any non-GET/HEAD method to GET and always drop the
body, including when the original request was already a GET/HEAD.
Clear every header that frames the dropped body: Content-Length and
Content-Type, plus Transfer-Encoding and Trailer (per RFC 9112 a body is
signaled by Content-Length or Transfer-Encoding, and a Trailer only
applies to a chunked body). 301/302 keep their POST-to-GET behavior, and
307/308 still preserve the method and body.
Fixes#2240
Signed-off-by: Y.Horie <u5.horie@gmail.com>
Prevent request and response first-line setters from serializing
embedded CR or LF bytes into the start line.
Route SetMethod, SetRequestURI, SetProtocol, and SetStatusMessage
through the existing newline sanitization used by other header-value
setters. This preserves behavior for valid inputs while preventing
header injection through malformed first-line values.
Thanks to @vnykmshr for reporting this issue.
* Add DNS cache management methods for TCPDialer
Resolves#2066
This commit introduces two new methods for managing DNS cache in TCPDialer:
1. FlushDNSCache() - Clears all cached DNS entries, forcing fresh lookups
2. CleanDNSCache() - Removes only expired entries based on DNSCacheDuration
Key changes:
- Add FlushDNSCache() and CleanDNSCache() methods to TCPDialer
- Add global FlushDNSCache() and CleanDNSCache() functions for default dialer
- Refactor tcpAddrsClean() to extract reusable cleanExpiredDNSEntries() method
- Add comprehensive tests with mock resolver to verify caching behavior
Use case: Users can now set longer cache durations (e.g., 30 minutes) and
manually refresh DNS when needed, providing better control over DNS resolution
timing while maintaining performance benefits of caching.
* Remove CleanDNSCache method to reduce the API surface layer and related tests from TCPDialer
* fix: resolve godot linter issue in client_test.go
Add missing period to comment to comply with godot linter rule requiring
comments to end with proper punctuation.
* Support for delayed retry logic
* Support for resetting the request timeout before retrying
* Users can decide whether to retry based on the request error and the number of retries.
Estimating the time required for a request to complete is relatively straightforward, but when retries are factored in, it becomes challenging to gauge this time accurately.
The current client implementation does not immediately return when encountering an RST packet while sending a request, but instead ignores it. This behavior is inconsistent with the net/http package and does not make logical sense.
In some cases, the goroutines started by one test do not terminate smoothly before the next round of tests begins, causing interference between tests.
Performance Impact: This results in test completion times not increasing linearly with the count value.
Correctness Impact: It affects the accuracy of memory allocation test cases.
The `testClientDoTimeoutError` and `testClientGetTimeoutSuccess` test function does not immediately return or fatal when the test fails. Instead, it continues to stringify the byte slice that was passed as the `dst` parameter to the `Client.GetTimeout` method. If the test fails due to a timeout, the request may still be ongoing, and there might be a data race between writing to `dst` and the stringification operation.
* Allow redirect URI path to not be normalized.
* Introduce DisableRedirectPathNormalizing field to Request
* Use field name as start of comment.
Co-authored-by: Erik Dubbelboer <erik@dubbelboer.com>
---------
Co-authored-by: Erik Dubbelboer <erik@dubbelboer.com>
* Abstracts the RoundTripper interface and provides a default implementation for enhanced extensibility (#1601)
* test: Add custom transport test case (#1601)
* Make default RoundTripper implmention none public
Co-authored-by: Erik Dubbelboer <erik@dubbelboer.com>
---------
Co-authored-by: Erik Dubbelboer <erik@dubbelboer.com>
The getClientName() checks if !NoDefaultUserAgentHeader then returns the Client.Name field.
But it also saves it to atomic field clientName. This is not needed and logic can be simplified.
Previously the clientName vas a byte slice that was copied from c.Name and cached. See 02e0722fb7Fix#1458
* client.go Make addMissingPort() public
It's needed for those who creates the instance of the HostClient manually.
* client.go fix AddMissingPort()
Previously for IPv6 addresses the default port wasn't added.
The fix adding a test and optimization that should avoid itoa() call and reduce a memory usage
* Request.SetTimeout
This functionally works the same as e.g. Client.DoTimeout(), but we can
also use it for Client.DoRedirect(). There is no way as far as I can
tell to set a timeout on a DoRedirect call, so this makes it possible.
* tests
* docs
* use timeout insteadof read/writetimeout when timeout lower than read/writetimeout
* use deadtime; fix test timeout;
Co-authored-by: 徐焱 <xuyan4@staff.sina.com.cn>
* Read response when client closes connection #1232
* Fix edge case were client responds with invalid header
* Follow linter suggestions for tests
* Changes after review
* Reafactor error check after review
* Handle connection reset on windows
* Remove format string from test where not needed
* Run connection reset tests not on Windows
* uri_test.go replace xxx.com with example.com
* uri_test.go replace foobar.com with example.com
* uri_test.go use example.com inside of testURIUpdate()
* uri_test.go use example.com instead of google.com
* uri_test.go use example.com instead of google.com
* uri_test.go testURIUpdate() host with port
* Fix scheme check for not yet parsed requests
At this point the request might not be parsed yet and set. In that case uri is empty and isHttps() returns always false. I don't expect this is intended?
Otherwise URL() must be called before actually passing the request to client.Do()
* Add test
* Please linter