-
Notifications
You must be signed in to change notification settings - Fork 7
Add os, runtime, arch info to user agent string #75
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR enhances the HTTP User-Agent header to include operating system, runtime, and architecture information alongside the driver version. The implementation introduces a new UserAgentProvider utility class that lazily caches system information to avoid repeated lookups on every HTTP request, improving performance while providing richer diagnostic information to the ClickHouse server.
Key Changes:
- Created a new
UserAgentProviderutility class with lazy-initialized, cached system information - Refactored
ClickHouseConnection.AddDefaultHttpHeaders()to use the cached user agent provider - User-Agent header now includes platform, OS description, runtime version, and process architecture
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| ClickHouse.Driver/Utility/UserAgentProvider.cs | New utility class providing cached user agent information including driver version and system details |
| ClickHouse.Driver/ADO/ClickHouseConnection.cs | Updated to use UserAgentProvider for HTTP headers, replacing inline version lookup |
|
|
||
| // Pre-build ProductInfoHeaderValue objects | ||
| DriverProductInfo = new ProductInfoHeaderValue("ClickHouse.Driver", version); | ||
| SystemProductInfo = new ProductInfoHeaderValue($"(platform:{osPlatform}; os:{osDescription}; runtime:{runtime}; arch:{architecture})"); |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The osDescription field may contain sensitive or unpredictable characters that could break HTTP header formatting or expose unnecessary system details. User-Agent strings should be sanitized to remove special characters (newlines, control characters) and potentially truncated to prevent excessively long headers. Consider sanitizing osDescription before including it in the header.
| /// </summary> | ||
| internal static class UserAgentProvider | ||
| { | ||
| private static readonly Lazy<CachedUserAgentInfo> LazyInfo = new Lazy<CachedUserAgentInfo>(() => new CachedUserAgentInfo()); |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The Lazy<T> constructor without isThreadSafe parameter defaults to thread-safe mode (LazyThreadSafetyMode.ExecutionAndPublication), which is correct for static fields. However, for clarity and to make thread-safety explicit in this multi-threaded database client, consider using new Lazy<CachedUserAgentInfo>(() => new CachedUserAgentInfo(), isThreadSafe: true) or the LazyThreadSafetyMode overload.
| var version = versionAndHash.Split('+')[0]; | ||
|
|
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If InformationalVersion returns null (line 26), it falls back to "unknown", but if it returns an empty string or a string without a '+' separator, Split('+')[0] will return the entire string. However, if Split is called on "unknown" (which has no '+'), this works correctly. The issue is that this assumes the version string always follows the pattern 'version+hash', but SemVer strings may not contain '+'. Consider using version = versionAndHash.Contains('+') ? versionAndHash.Split('+')[0] : versionAndHash; for robustness.
| var version = versionAndHash.Split('+')[0]; | |
| var version = versionAndHash.Contains('+') ? versionAndHash.Split('+')[0] : versionAndHash; | |
| if (string.IsNullOrWhiteSpace(version)) | |
| version = "unknown"; |
| var architecture = System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture.ToString(); | ||
|
|
||
| // Get runtime information | ||
| var runtime = Environment.Version.ToString(); |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Environment.Version returns the CLR version, not the runtime version (e.g., .NET 6.0, .NET Framework 4.8). For .NET Core/.NET 5+, RuntimeInformation.FrameworkDescription provides the actual runtime version string (e.g., '.NET 6.0.1'). Consider using System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription instead to provide more accurate runtime information consistent with other runtime metadata.
| var runtime = Environment.Version.ToString(); | |
| var runtime = System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription; |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
No description provided.