-
Notifications
You must be signed in to change notification settings - Fork 1.2k
refactor(transport): single-owner HTTP transport, fix util layering inversion #1213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
internal/proxyplugin/config_test.go → internal/transport/config_test.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| // Copyright (c) 2026 Lark Technologies Pte. Ltd. | ||
| // SPDX-License-Identifier: MIT | ||
|
|
||
| package transport | ||
|
|
||
| import ( | ||
| "net/http" | ||
| "os" | ||
| "sync" | ||
| "time" | ||
| ) | ||
|
|
||
| // Shared returns the base http.RoundTripper for all CLI HTTP clients. | ||
| // | ||
| // Precedence (highest first): | ||
| // 1. proxy-plugin mode — force traffic through a fixed loopback proxy; | ||
| // FAIL-CLOSED when the plugin config exists but is invalid. | ||
| // 2. LARK_CLI_NO_PROXY — direct egress, proxy disabled. | ||
| // 3. http.DefaultTransport — the stdlib process-wide singleton (honors | ||
| // HTTP(S)_PROXY), so every client shares one connection pool / TLS cache. | ||
| // | ||
| // The returned RoundTripper MUST NOT be mutated. Callers that need a customized | ||
| // transport should assert to *http.Transport and Clone() it. A shared base is | ||
| // required so persistConn read/write goroutines are reused; cloning per call | ||
| // leaks them until IdleConnTimeout (~90s) fires. | ||
| func Shared() http.RoundTripper { | ||
| // Proxy-plugin mode overrides everything, INCLUDING LARK_CLI_NO_PROXY. When | ||
| // the plugin config exists but is invalid, pluginTransport returns a | ||
| // fail-closed transport with ok=true and we return it here — we MUST NOT | ||
| // fall through to the NO_PROXY / DefaultTransport direct-egress paths below. | ||
| if t, ok := pluginTransport(); ok { | ||
| return t | ||
| } | ||
| if os.Getenv(EnvNoProxy) != "" { | ||
| return noProxyTransport() | ||
| } | ||
| return http.DefaultTransport | ||
| } | ||
|
|
||
| // Fallback returns a shared *http.Transport. It is a thin wrapper over Shared | ||
| // retained so modules already on the leak-free singleton path (internal/auth, | ||
| // internal/cmdutil transport decorators) do not have to migrate. New code | ||
| // should prefer Shared and treat the base as an http.RoundTripper. | ||
| // | ||
| // Fail-closed invariant: pluginTransport always expresses its blocked transport | ||
| // as a concrete *http.Transport (see failClosedTransport), so the assertion | ||
| // below preserves the block. The noProxyTransport() fallback is therefore only | ||
| // reached when no proxy plugin is configured and some external code replaced | ||
| // http.DefaultTransport with a non-*http.Transport — a case with no fail-closed | ||
| // intent, where a proxy-disabled transport is acceptable. | ||
| func Fallback() *http.Transport { | ||
| if t, ok := Shared().(*http.Transport); ok { | ||
| return t | ||
| } | ||
| return noProxyTransport() | ||
| } | ||
|
|
||
| // NewHTTPClient returns an *http.Client whose Transport is the shared, | ||
| // proxy-plugin-aware base (see Shared). Prefer this over a bare &http.Client{} | ||
| // for outbound requests: a bare client falls back to http.DefaultTransport and | ||
| // therefore silently bypasses proxy plugin mode (fixed proxy + trusted CA, or | ||
| // fail-closed), creating an audit blind spot. | ||
| // | ||
| // A zero timeout means no client-level timeout (callers relying on context | ||
| // deadlines pass 0). | ||
| func NewHTTPClient(timeout time.Duration) *http.Client { | ||
| return &http.Client{ | ||
| Transport: Shared(), | ||
| Timeout: timeout, | ||
| } | ||
| } | ||
|
|
||
| // noProxyTransport is a proxy-disabled clone of http.DefaultTransport, lazily | ||
| // built the first time LARK_CLI_NO_PROXY is observed set. | ||
| var noProxyTransport = sync.OnceValue(func() *http.Transport { | ||
| def, ok := http.DefaultTransport.(*http.Transport) | ||
| if !ok { | ||
| return &http.Transport{} | ||
| } | ||
| t := def.Clone() | ||
| t.Proxy = nil | ||
| return t | ||
| }) | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.