Skip to content

Conversation

leijiru1994
Copy link

@leijiru1994 leijiru1994 commented Jul 21, 2025

功能描述

1、复用http client

  • 通过 sync.Map 基于不同的代理复用对应的http client,避免高并发下频繁创建、销毁对象带来的消耗
    • 同时支持一定的http client参数设置

Summary by CodeRabbit

  • New Features

    • Added enhanced HTTP client support with proxy configuration, including HTTP, HTTPS, and SOCKS5 proxies.
    • Proxy settings can now be set via environment variables, and connection pool parameters are configurable.
  • Bug Fixes

    • Improved reliability of AWS client initialization when using proxies.
  • Chores

    • Updated AWS SDK and related dependencies to newer versions for improved compatibility and performance.

Copy link
Contributor

coderabbitai bot commented Jul 21, 2025

Walkthrough

The changes update AWS SDK dependencies in go.mod, integrate a custom HTTP client with proxy support into the AWS client initialization, and introduce a new utility for HTTP client creation supporting various proxy types. The HTTP client logic is refactored to use this utility, with connection pooling and timeout parameters configurable via environment variables.

Changes

File(s) Change Summary
go.mod Updated AWS SDK dependencies; added golang.org/x/sync; added new AWS SDK submodules and config dependency.
relay/channel/aws/relay-aws.go Refactored AWS client initialization to use a custom HTTP client with proxy support.
service/http_client.go Refactored HTTP client creation to delegate to new utility; added internal helper; reordered imports.
util/http_client.go Added new utility package for HTTP client creation with proxy and connection pooling support.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Service as service/http_client.go
    participant Util as util/http_client.go
    participant AWS as AWS Client

    Caller->>Service: NewProxyHttpClient(proxyURL)
    Service->>Util: GetHttpClient(proxyURL)
    Util-->>Service: *http.Client or error
    alt Success
        Service-->>Caller: *http.Client
    else Fallback
        Service->>Service: Fallback to legacy logic
        Service-->>Caller: *http.Client
    end

    Caller->>AWS: Initialize AWS client with custom *http.Client
Loading

Estimated code review effort

3 (90–240 minutes)

Poem

In the warren where code does hop,
New clients burrow, proxy on top.
AWS gets a shiny new shoe,
With SOCKS and HTTP running through!
Dependencies pruned, connections pool,
Rabbits rejoice—reviewing is cool!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e0b28e6 and e91c8d7.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (2)
  • go.mod (2 hunks)
  • relay/channel/aws/relay-aws.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • relay/channel/aws/relay-aws.go
  • go.mod
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
util/http_client.go (2)

17-21: Consider using more descriptive constant names.

The constant names could be more explicit about their purpose in the HTTP client context.

-const (
-	KeyOfMaxIdleConnsPerHost = "MAX_IDLE_CONNS_PER_HOST"
-	KeyOfMaxIdleConns        = "MAX_IDLE_CONNS"
-	KeyOfIdleConnTimeout     = "IDLE_CONN_TIMEOUT"
-)
+const (
+	KeyOfMaxIdleConnsPerHost = "HTTP_MAX_IDLE_CONNS_PER_HOST"
+	KeyOfMaxIdleConns        = "HTTP_MAX_IDLE_CONNS"
+	KeyOfIdleConnTimeout     = "HTTP_IDLE_CONN_TIMEOUT"
+)

41-43: Potential type assertion panic risk.

The type assertion client.(*http.Client) could panic if the stored value is not of the expected type, though this should be impossible given the current implementation.

Consider using a type-safe approach:

-	if client, ok := innerHttpClients.Load(proxyURL); ok {
-		return client.(*http.Client), nil
-	}
+	if client, ok := innerHttpClients.Load(proxyURL); ok {
+		if httpClient, ok := client.(*http.Client); ok {
+			return httpClient, nil
+		}
+	}
service/http_client.go (1)

31-31: Consider using English comments for international codebases.

The Chinese comments may not be accessible to all developers working on the codebase.

-	// 2025-07-17 兼容模式,当获取不到 httpClient 时,使用默认业务逻辑返回的 httpClient
+	// Compatibility mode: fallback to original httpClient logic if new implementation fails
-	// 2025-07-17 兼容模式,当获取不到 httpClient 时,使用默认业务逻辑返回的 httpClient  
+	// Compatibility mode: fallback to original httpClient logic if new implementation fails

Also applies to: 46-46

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78fb457 and e0b28e6.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (4)
  • go.mod (3 hunks)
  • relay/channel/aws/relay-aws.go (2 hunks)
  • service/http_client.go (2 hunks)
  • util/http_client.go (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
relay/channel/aws/relay-aws.go (1)
service/http_client.go (1)
  • NewProxyHttpClient (44-99)
service/http_client.go (1)
util/http_client.go (1)
  • GetHttpClient (31-113)
🔇 Additional comments (11)
util/http_client.go (2)

23-29: LGTM! Good choice of data structures and defaults.

The sync.Map is appropriate for concurrent access patterns and the default connection pool values are reasonable for most use cases.


64-71: Password extraction logic is correct.

The authentication handling properly extracts username and password from the URL, with appropriate fallback for missing password.

relay/channel/aws/relay-aws.go (3)

7-8: LGTM! Good import organization.

The import reordering improves readability by grouping standard library imports separately from third-party imports.

Also applies to: 13-13, 19-20


32-35: Excellent error handling for HTTP client creation.

The early return on HTTP client creation failure prevents the AWS client from being created with invalid configuration, which is the correct approach.


40-40: Clean integration with new HTTP client infrastructure.

The HTTP client is now properly configured with proxy support while maintaining the existing AWS SDK configuration pattern.

go.mod (3)

35-35: Good addition of golang.org/x/sync dependency.

The explicit addition of golang.org/x/sync v0.11.0 as a direct dependency is appropriate since it's now used directly in the util package for sync.Map functionality.


44-53: New AWS SDK indirect dependencies are expected.

The addition of new indirect dependencies like ec2/imds, internal modules, and service modules is normal when upgrading AWS SDK to newer versions that have better modularization.


10-12: AWS SDK v2 Core Upgrade Safe—but Verify Service-Specific Changelogs

No breaking changes were introduced in the AWS SDK for Go v2 core modules between v1.26.1 and v1.36.5. All top-level updates in that range are feature additions, new service API support, and dependency bumps.

• No core-level breaking changes identified (v1.26.1 → v1.36.5)
• Ensure your project’s Go version meets any new minimums (e.g. some service clients now require Go 1.19+)
• Manually review the CHANGELOG.md for each AWS service you use—especially service/bedrockruntime—to catch any module-specific breaking changes

service/http_client.go (3)

39-41: Clean delegation to the new HTTP client utility.

The helper function provides a clean abstraction layer for integrating with the new util.GetHttpClient functionality.


30-36: Good fallback strategy for backward compatibility.

The fallback to the original httpClient when the new implementation fails ensures system stability during the transition period.


45-49: Consistent fallback pattern in NewProxyHttpClient.

The same fallback approach is consistently applied in NewProxyHttpClient, maintaining reliability while enabling the new functionality.

Comment on lines +60 to +87
case "socks5", "socks5h":
// 获取认证信息
var auth *proxy.Auth
if parsedURL.User != nil {
auth = &proxy.Auth{
User: parsedURL.User.Username(),
Password: "",
}
if password, ok := parsedURL.User.Password(); ok {
auth.Password = password
}
}

// 创建 SOCKS5 代理拨号器
// proxy.SOCKS5 使用 tcp 参数,所有 TCP 连接包括 DNS 查询都将通过代理进行。行为与 socks5h 相同
dialer, err := proxy.SOCKS5("tcp", parsedURL.Host, auth, proxy.Direct)
if err != nil {
return nil, err
}

transport = &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return dialer.Dial(network, addr)
},
MaxIdleConns: maxIdleConns,
MaxIdleConnsPerHost: maxIdleConnsPerHost,
IdleConnTimeout: idleConnTimeout,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify SOCKS5 proxy implementation behavior.

The comment on lines 74-75 states that proxy.SOCKS5 with "tcp" makes all connections including DNS queries go through the proxy (socks5h behavior), but this needs verification as the distinction between socks5 and socks5h schemes might not be properly handled.


🌐 Web query:

What is the difference between SOCKS5 and SOCKS5H proxy schemes and how does golang.org/x/net/proxy handle DNS resolution for each?

💡 Result:

The key difference between SOCKS5 and SOCKS5H proxy schemes centers on how DNS resolution is performed when making a proxied connection:

  • SOCKS5: The client (your local machine or application) performs DNS resolution. When you connect through a SOCKS5 proxy and provide a hostname, your client resolves that hostname to an IP address before sending the connection request to the proxy. The proxy then establishes a connection to the resolved IP. This method may expose your DNS queries locally, potentially leaking your intended targets[1][7].

  • SOCKS5H: The 'h' stands for hostname resolution by the proxy. When using SOCKS5H, your client sends the hostname (not the resolved IP address) to the proxy, which then performs the DNS lookup on your behalf and connects to the target host. This approach helps prevent DNS leaks and can be important for privacy and accessing geo-restricted content[1][7].

Here’s a table summarizing the difference:

Scheme DNS Resolution Location Risk of Local DNS Leak Use Case Example
SOCKS5 Client-side Yes General proxying, but less privacy for DNS
SOCKS5H Proxy-side No Privacy-sensitive tasks, geo-sensitive DNS

How does golang.org/x/net/proxy handle each?

  • The golang.org/x/net/proxy package only supports the socks5:// (SOCKS5) scheme and does not explicitly support the socks5h:// (SOCKS5H) scheme. When you provide a hostname, it is resolved locally before dialing through the proxy—consistent with standard SOCKS5 behavior[6].
    • For example, if you use the package’s proxy.SOCKS5() function and pass a hostname, the Go DNS resolver is used, so DNS requests go out locally, not through the proxy[3][2].
    • There is an open and longstanding issue where users have asked for support of socks5h:// so that hostname resolution can happen at the proxy. As of now, the package does not offer this functionality[6].

Summary:

  • SOCKS5 resolves DNS locally (potential leaks).
  • SOCKS5H resolves DNS at the proxy (no DNS leaks).
  • golang.org/x/net/proxy does not currently support SOCKS5H: DNS will always be resolved locally by the client, regardless of the scheme[2][3][6][7].
  • To avoid DNS leaks in Go, you would need to implement or use a library that specifically supports proxy-side DNS resolution or use a workaround to ensure DNS queries are sent through the proxy.

Citations:


Correct SOCKS5 proxy DNS behavior comment

The current comment implying that proxy.SOCKS5 over “tcp” will proxy DNS lookups (i.e. socks5h behavior) is inaccurate. The golang.org/x/net/proxy package only implements standard SOCKS5, which always resolves hostnames locally before dialing. It does not support remote (proxy-side) DNS resolution (socks5h).

Please update the comment in util/http_client.go (around lines 74–75) accordingly. For example:

-   // proxy.SOCKS5 使用 tcp 参数,所有 TCP 连接包括 DNS 查询都将通过代理进行。行为与 socks5h 相同
+   // proxy.SOCKS5 使用 tcp 参数代理 TCP 连接,但主机名解析仍在本地完成(无 socks5h 支持)

If you need DNS resolution by the proxy, you’ll have to implement or use a library that explicitly supports SOCKS5H.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case "socks5", "socks5h":
// 获取认证信息
var auth *proxy.Auth
if parsedURL.User != nil {
auth = &proxy.Auth{
User: parsedURL.User.Username(),
Password: "",
}
if password, ok := parsedURL.User.Password(); ok {
auth.Password = password
}
}
// 创建 SOCKS5 代理拨号器
// proxy.SOCKS5 使用 tcp 参数,所有 TCP 连接包括 DNS 查询都将通过代理进行。行为与 socks5h 相同
dialer, err := proxy.SOCKS5("tcp", parsedURL.Host, auth, proxy.Direct)
if err != nil {
return nil, err
}
transport = &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return dialer.Dial(network, addr)
},
MaxIdleConns: maxIdleConns,
MaxIdleConnsPerHost: maxIdleConnsPerHost,
IdleConnTimeout: idleConnTimeout,
}
case "socks5", "socks5h":
// 获取认证信息
var auth *proxy.Auth
if parsedURL.User != nil {
auth = &proxy.Auth{
User: parsedURL.User.Username(),
Password: "",
}
if password, ok := parsedURL.User.Password(); ok {
auth.Password = password
}
}
// 创建 SOCKS5 代理拨号器
// proxy.SOCKS5 使用 tcp 参数代理 TCP 连接,但主机名解析仍在本地完成(无 socks5h 支持)
dialer, err := proxy.SOCKS5("tcp", parsedURL.Host, auth, proxy.Direct)
if err != nil {
return nil, err
}
transport = &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return dialer.Dial(network, addr)
},
MaxIdleConns: maxIdleConns,
MaxIdleConnsPerHost: maxIdleConnsPerHost,
IdleConnTimeout: idleConnTimeout,
}
🤖 Prompt for AI Agents
In util/http_client.go around lines 74 to 75, the comment incorrectly states
that proxy.SOCKS5 with "tcp" proxies DNS lookups like socks5h, but the
golang.org/x/net/proxy package only performs local DNS resolution before
dialing. Update the comment to clarify that DNS resolution is done locally and
that this implementation does not support remote DNS resolution (socks5h).
Mention that to achieve proxy-side DNS resolution, a different implementation or
library supporting SOCKS5H is required.

Comment on lines +111 to +112
innerHttpClients.Store(proxyURL, tmpClient)
return tmpClient, nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider memory management for the client cache.

The current implementation stores clients indefinitely in the sync.Map, which could lead to memory leaks if many different proxy URLs are used over time. Consider implementing a cleanup mechanism or LRU eviction.

Potential solutions:

  1. Add a periodic cleanup goroutine to remove unused clients
  2. Implement an LRU cache with size limits
  3. Add client reference counting with automatic cleanup

Do you want me to generate an implementation for any of these approaches?

🤖 Prompt for AI Agents
In util/http_client.go around lines 111 to 112, the current code stores HTTP
clients indefinitely in a sync.Map, risking memory leaks with many proxy URLs.
To fix this, implement a cache eviction strategy such as adding a periodic
cleanup goroutine to remove unused clients, or replace the sync.Map with an LRU
cache that limits size, or add reference counting to track client usage and
clean up when no longer needed. Choose one approach and modify the client
storage logic accordingly to prevent unbounded memory growth.

@Calcium-Ion Calcium-Ion changed the base branch from main to alpha August 9, 2025 03:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant