Skip to content

Commit e20012a

Browse files
authored
Merge pull request #2 from Rckov/develop
Optimized Http2Client Library Loading
2 parents 757e56f + 66ba595 commit e20012a

File tree

11 files changed

+158
-126
lines changed

11 files changed

+158
-126
lines changed

README.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,16 @@ Http2Client requires the native TLS library from the original [bogdanfinn/tls-cl
3232
**Installation Instructions:**
3333

3434
1. Download the appropriate library file for your platform from the table above
35-
2. Place the native library in your application's output directory, or
36-
3. Specify the custom path using the `WithLibraryPath()` method in your code
35+
2. Place the native library in your application's output directory, or specify a custom path
36+
3. Initialize the library once at application startup using `Http2Client.Initialize()`
3737

3838
**Example for Windows:**
3939
```csharp
40+
// Initialize once at application startup
41+
Http2Client.Initialize("tls-client-windows-64-1.11.0.dll");
42+
43+
// Create clients as needed
4044
using var client = new HttpClientBuilder()
41-
.WithLibraryPath("tls-client-windows-64-1.11.0.dll")
4245
.Build();
4346
```
4447

@@ -56,9 +59,11 @@ using Http2Client.Builders;
5659
using Http2Client.Core.Enums;
5760
using Http2Client.Core.Request;
5861

62+
// Initialize native library once at application startup
63+
Http2Client.Initialize("tls-client-windows-64-1.11.0.dll");
64+
5965
// Create an Http2Client instance using the builder
6066
using var client = new HttpClientBuilder()
61-
.WithLibraryPath("tls-client-windows-64-1.11.0.dll")
6267
.WithBrowserType(BrowserType.Chrome133)
6368
.WithUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
6469
.WithTimeout(TimeSpan.FromSeconds(30))
@@ -118,7 +123,6 @@ using var client = new HttpClientBuilder()
118123

119124
| Method | Description |
120125
|--------|-------------|
121-
| `WithLibraryPath(string)` | Sets the path to the native TLS library. |
122126
| `WithBrowserType(BrowserType)` | Sets the browser fingerprint to mimic. |
123127
| `WithUserAgent(string)` | Sets the User-Agent header. |
124128
| `WithTimeout(TimeSpan)` | Sets the request timeout. |
@@ -142,8 +146,10 @@ using var client = new HttpClientBuilder()
142146
### Advanced Example
143147

144148
```csharp
149+
// Initialize library once at startup
150+
Http2Client.Initialize("tls-client-windows-64-1.11.0.dll");
151+
145152
using var client = new HttpClientBuilder()
146-
.WithLibraryPath("tls-client-windows-64-1.11.0.dll")
147153
.WithBrowserType(BrowserType.Firefox132)
148154
.WithUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
149155
.WithProxy("http://127.0.0.1:8888", isRotating: true)
@@ -228,7 +234,6 @@ var request = new HttpRequest
228234

229235
```csharp
230236
using var client = new HttpClientBuilder()
231-
.WithLibraryPath("tls-client-windows-64-1.11.0.dll")
232237
.WithBrowserType(BrowserType.Chrome133)
233238
.Build();
234239

@@ -265,7 +270,6 @@ var response = client.Send(request);
265270

266271
```csharp
267272
using var client = new HttpClientBuilder()
268-
.WithLibraryPath("tls-client-windows-64-1.11.0.dll")
269273
.WithBrowserType(BrowserType.Chrome133)
270274
.WithProxy("http://proxy.example.com:8080")
271275
.Build();

examples/Program.cs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,22 @@
88

99
internal class Program
1010
{
11-
private const string PATH_LIB = "Native\\tls-client-windows-64-1.11.0.dll";
12-
1311
private static void Main()
1412
{
15-
//BasicGetRequest();
16-
//PostJsonRequest();
17-
//CookieHandling();
18-
//HeadersAndProxy();
19-
ErrorHandlingAndTimeouts();
13+
Http2Client.Http2Client.Initialize("Native\\tls-client-windows-64-1.11.0.dll");
14+
15+
try
16+
{
17+
BasicGetRequest();
18+
PostJsonRequest();
19+
CookieHandling();
20+
HeadersAndProxy();
21+
ErrorHandlingAndTimeouts();
22+
}
23+
finally
24+
{
25+
Http2Client.Http2Client.Cleanup();
26+
}
2027

2128
Console.ReadLine();
2229
}
@@ -27,7 +34,6 @@ private static void BasicGetRequest()
2734

2835
using var client = new HttpClientBuilder()
2936
.WithUserAgent("Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36")
30-
.WithLibraryPath(PATH_LIB)
3137
.WithRandomTlsExtensions()
3238
.Build();
3339

@@ -50,7 +56,6 @@ private static void PostJsonRequest()
5056

5157
using var client = new HttpClientBuilder()
5258
.WithUserAgent("Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36")
53-
.WithLibraryPath(PATH_LIB)
5459
.WithHeader("Content-Type", "application/json")
5560
.WithCookies()
5661
.Build();
@@ -83,7 +88,6 @@ private static void CookieHandling()
8388

8489
using var client = new HttpClientBuilder()
8590
.WithUserAgent("Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36")
86-
.WithLibraryPath(PATH_LIB)
8791
.WithCookies(true)
8892
.Build();
8993

@@ -118,7 +122,6 @@ private static void HeadersAndProxy()
118122

119123
using var client = new HttpClientBuilder()
120124
.WithUserAgent("Custom-Agent/1.0")
121-
.WithLibraryPath(PATH_LIB)
122125
.WithHeader("Accept", "application/json")
123126
.WithHeader("Accept-Language", "en-US,en;q=0.9")
124127
.WithHeader("Accept-Encoding", "gzip, deflate, br")
@@ -150,7 +153,6 @@ private static void ErrorHandlingAndTimeouts()
150153

151154
using var client = new HttpClientBuilder()
152155
.WithUserAgent("Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36")
153-
.WithLibraryPath(PATH_LIB)
154156
.WithTimeout(TimeSpan.FromSeconds(10))
155157
.WithCatchPanics(true)
156158
.WithInsecureSkipVerify(false)

src/Builders/HttpClientBuilder.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -195,17 +195,6 @@ public HttpClientBuilder WithRandomTlsExtensions(bool enable = true)
195195
return this;
196196
}
197197

198-
/// <summary>
199-
/// Sets native library path. Auto-detected if not set.
200-
/// </summary>
201-
public HttpClientBuilder WithLibraryPath(string libraryPath)
202-
{
203-
ThrowException.FileNotExists(libraryPath, nameof(libraryPath));
204-
205-
_options.LibraryPath = libraryPath;
206-
return this;
207-
}
208-
209198
/// <summary>
210199
/// Sets User-Agent header.
211200
/// </summary>

src/Http2Client.cs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ namespace Http2Client;
1515
public sealed class Http2Client : IDisposable
1616
{
1717
private readonly Http2ClientOptions _options;
18-
private readonly NativeWrapper _wrapper;
1918
private bool _disposed;
2019

2120
/// <summary>
@@ -33,6 +32,11 @@ public sealed class Http2Client : IDisposable
3332
/// </summary>
3433
public bool IsDisposed => _disposed;
3534

35+
/// <summary>
36+
/// True if native library is loaded and ready to use.
37+
/// </summary>
38+
public static bool IsInitialized => NativeWrapper.IsInitialized;
39+
3640
/// <summary>
3741
/// Create client with custom options.
3842
/// </summary>
@@ -41,7 +45,6 @@ public Http2Client(Http2ClientOptions options)
4145
{
4246
_options = options ?? throw new ArgumentNullException(nameof(options));
4347
_options.Validate();
44-
_wrapper = NativeWrapper.Load(_options.LibraryPath);
4548
}
4649

4750
/// <summary>
@@ -51,6 +54,23 @@ public Http2Client() : this(new Http2ClientOptions())
5154
{
5255
}
5356

57+
/// <summary>
58+
/// Initialize native library once. Call this before creating any Http2Client instances.
59+
/// </summary>
60+
/// <param name="path">Path to native TLS library</param>
61+
public static void Initialize(string path)
62+
{
63+
NativeWrapper.Initialize(path);
64+
}
65+
66+
/// <summary>
67+
/// Cleanup native library resources. Call at application shutdown.
68+
/// </summary>
69+
public static void Cleanup()
70+
{
71+
NativeWrapper.Cleanup();
72+
}
73+
5474
/// <summary>
5575
/// Send HTTP request. Main method for making requests.
5676
/// </summary>
@@ -67,7 +87,7 @@ public Http2Client() : this(new Http2ClientOptions())
6787

6888
try
6989
{
70-
var responseJson = _wrapper.Request(Serializer.SerializeToBytes(prepared));
90+
var responseJson = NativeWrapper.Request(Serializer.SerializeToBytes(prepared));
7191
response = Serializer.Deserialize<HttpResponse>(responseJson);
7292
return response;
7393
}
@@ -80,7 +100,7 @@ public Http2Client() : this(new Http2ClientOptions())
80100
// Clean up native memory for this response
81101
if (response != null && !string.IsNullOrEmpty(response.Id))
82102
{
83-
_wrapper.FreeMemory(response.Id);
103+
NativeWrapper.FreeMemory(response.Id);
84104
}
85105
}
86106
}
@@ -100,7 +120,7 @@ public Http2Client() : this(new Http2ClientOptions())
100120
SessionId = _options.SessionId,
101121
};
102122

103-
var responseJson = _wrapper.GetCookiesFromSession(Serializer.SerializeToBytes(payload));
123+
var responseJson = NativeWrapper.GetCookiesFromSession(Serializer.SerializeToBytes(payload));
104124
return Serializer.Deserialize<CookiesResponse>(responseJson);
105125
}
106126

@@ -122,7 +142,7 @@ public Http2Client() : this(new Http2ClientOptions())
122142
Cookies = [.. cookies]
123143
};
124144

125-
var responseJson = _wrapper.AddCookiesToSession(Serializer.SerializeToBytes(payload));
145+
var responseJson = NativeWrapper.AddCookiesToSession(Serializer.SerializeToBytes(payload));
126146
return Serializer.Deserialize<CookiesResponse>(responseJson);
127147
}
128148

@@ -135,7 +155,7 @@ public bool DestroySession()
135155
try
136156
{
137157
var payload = new { sessionId = _options.SessionId };
138-
var responseJson = _wrapper.DestroySession(Serializer.SerializeToBytes(payload));
158+
var responseJson = NativeWrapper.DestroySession(Serializer.SerializeToBytes(payload));
139159
return !string.IsNullOrEmpty(responseJson);
140160
}
141161
catch
@@ -153,7 +173,7 @@ public bool DestroyAllSessions()
153173
{
154174
try
155175
{
156-
var responseJson = _wrapper.DestroyAllSessions();
176+
var responseJson = NativeWrapper.DestroyAllSessions();
157177
return !string.IsNullOrEmpty(responseJson);
158178
}
159179
catch
@@ -286,11 +306,9 @@ private void Dispose(bool disposing)
286306
}
287307
catch
288308
{
289-
// If session cleanup fails, we still want to dispose the wrapper
309+
// If session cleanup fails, we still want to continue disposal
290310
// Better to leak a session than crash during disposal
291311
}
292-
293-
_wrapper?.Dispose();
294312
}
295313

296314
_disposed = true;

src/Http2Client.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<Nullable>enable</Nullable>
77
<Platforms>AnyCPU;x64</Platforms>
88
<PackageId>Http2Client</PackageId>
9-
<Version>1.1.3</Version>
9+
<Version>1.1.4</Version>
1010
<Authors>Rckov</Authors>
1111
<Company>Rckov</Company>
1212
<Product>Http2Client</Product>

src/Http2ClientOptions.cs

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,6 @@ public class Http2ClientOptions
103103
/// </summary>
104104
public bool WithRandomTlsExtensionOrder { get; set; }
105105

106-
/// <summary>
107-
/// Path to native TLS library. Auto-detected if not specified.
108-
/// </summary>
109-
public string? LibraryPath { get; set; } = GetDefaultLibraryPath();
110-
111106
/// <summary>
112107
/// User-Agent header value.
113108
/// </summary>
@@ -132,8 +127,6 @@ public string? UserAgent
132127
/// </summary>
133128
public void Validate()
134129
{
135-
ThrowException.FileNotExists(LibraryPath, nameof(LibraryPath));
136-
137130
if (!string.IsNullOrEmpty(ProxyUrl))
138131
{
139132
ThrowException.IsUri(ProxyUrl, nameof(ProxyUrl));
@@ -178,7 +171,6 @@ public Http2ClientOptions Clone()
178171
WithDefaultCookieJar = WithDefaultCookieJar,
179172
WithoutCookieJar = WithoutCookieJar,
180173
WithRandomTlsExtensionOrder = WithRandomTlsExtensionOrder,
181-
LibraryPath = LibraryPath
182174
};
183175

184176
// Deep copy headers so changes to the clone don't mess with the original
@@ -189,14 +181,4 @@ public Http2ClientOptions Clone()
189181

190182
return clone;
191183
}
192-
193-
/// <summary>
194-
/// Gets default native library path for current platform.
195-
/// </summary>
196-
private static string GetDefaultLibraryPath()
197-
{
198-
// .dll / .so / .dylib
199-
var extension = PlatformSupport.GetNativeLibraryExtension();
200-
return PlatformSupport.GetRuntimePath($"tls-client.{extension}");
201-
}
202184
}

0 commit comments

Comments
 (0)