|
1 | | -[](https://hmlendea.go.ro/donate) [](https://github.com/hmlendea/nuciweb.http/actions/workflows/dotnet.yml) [](https://github.com/hmlendea/nuciweb.http/releases/latest) |
| 1 | +[](https://hmlendea.go.ro/donate) [](https://github.com/hmlendea/nuciweb.http/actions/workflows/dotnet.yml) [](https://github.com/hmlendea/nuciweb.http/releases/latest) [](https://gnu.org/licenses/gpl-3.0) |
2 | 2 |
|
3 | | -# About |
| 3 | +# NuciWeb.HTTP |
4 | 4 |
|
5 | | -NuGet package for common HTTP operations. |
| 5 | +A lightweight .NET library with utilities for common HTTP and network-related tasks: |
6 | 6 |
|
7 | | -# Installation |
| 7 | +- Creating `HttpClient` instances with a realistic User-Agent |
| 8 | +- Checking internet connectivity with multiple probing strategies |
| 9 | +- Getting the public IP address through fallback providers |
| 10 | +- Performing reverse DNS lookups for hostnames |
| 11 | + |
| 12 | +## Features |
| 13 | + |
| 14 | +- `HttpClientCreator` for easy `HttpClient` construction |
| 15 | +- `UserAgentFetcher` for obtaining a modern Linux Firefox User-Agent |
| 16 | +- `NetworkUtils` helpers for connectivity checks, reverse DNS, and public IP discovery |
| 17 | +- Synchronous and asynchronous connectivity APIs |
| 18 | + |
| 19 | +## Requirements |
| 20 | + |
| 21 | +- .NET (target framework: `net10.0`) |
| 22 | + |
| 23 | +## Installation |
8 | 24 |
|
9 | 25 | [](https://nuget.org/packages/NuciWeb.HTTP) |
10 | 26 |
|
11 | | -**.NET CLI**: |
| 27 | +### .NET CLI |
| 28 | + |
12 | 29 | ```bash |
13 | 30 | dotnet add package NuciWeb.HTTP |
14 | 31 | ``` |
15 | 32 |
|
16 | | -**Package Manager**: |
| 33 | +### Package Manager Console |
| 34 | + |
17 | 35 | ```powershell |
18 | 36 | Install-Package NuciWeb.HTTP |
19 | 37 | ``` |
20 | 38 |
|
21 | | -# Usage |
| 39 | +## Quick Start |
| 40 | + |
| 41 | +```csharp |
| 42 | +using NuciWeb.HTTP; |
| 43 | + |
| 44 | +HttpClient client = await HttpClientCreator.CreateAsync(); |
| 45 | +bool online = await NetworkUtils.HasInternetAccessAsync(); |
| 46 | + |
| 47 | +if (online) |
| 48 | +{ |
| 49 | + string publicIp = NetworkUtils.GetPublicIpAddress(); |
| 50 | +} |
| 51 | +``` |
| 52 | + |
| 53 | +## API Overview |
| 54 | + |
| 55 | +### HttpClientCreator |
| 56 | + |
| 57 | +Creates `HttpClient` instances with a configured User-Agent. |
| 58 | + |
| 59 | +```csharp |
| 60 | +HttpClient a = await HttpClientCreator.CreateAsync(); |
| 61 | +HttpClient b = await HttpClientCreator.CreateAsync(customFetcher); |
| 62 | +HttpClient c = HttpClientCreator.Create("MyApp/1.0"); |
| 63 | +``` |
| 64 | + |
| 65 | +Methods: |
| 66 | + |
| 67 | +- `CreateAsync()` |
| 68 | +- `CreateAsync(IUserAgentFetcher uaFetcher)` |
| 69 | +- `Create()` |
| 70 | +- `Create(string userAgent)` |
| 71 | + |
| 72 | +### IUserAgentFetcher / UserAgentFetcher |
| 73 | + |
| 74 | +`IUserAgentFetcher` allows custom User-Agent provider implementations. |
| 75 | + |
| 76 | +`UserAgentFetcher` implementation: |
| 77 | + |
| 78 | +- Downloads the latest Firefox User-Agent page |
| 79 | +- Extracts a Linux x86_64 Firefox signature |
| 80 | +- Caches the value in-memory |
| 81 | +- Falls back to a hardcoded modern Firefox User-Agent if extraction fails |
| 82 | + |
| 83 | +### NetworkUtils |
| 84 | + |
| 85 | +#### Connectivity |
| 86 | + |
| 87 | +- `HasInternetAccess()` |
| 88 | +- `HasInternetAccessAsync()` |
| 89 | + |
| 90 | +Connectivity detection combines three probing strategies in parallel: |
| 91 | + |
| 92 | +- TCP connect probes |
| 93 | +- HTTP HEAD probes |
| 94 | +- ICMP ping probes |
| 95 | + |
| 96 | +The first successful strategy short-circuits the result to `true`. |
| 97 | + |
| 98 | +#### Public IP |
| 99 | + |
| 100 | +- `GetPublicIpAddress()` |
| 101 | + |
| 102 | +Behavior: |
| 103 | + |
| 104 | +- Requires internet connectivity (`HasInternetAccess`) |
| 105 | +- Randomizes provider order on each call |
| 106 | +- Returns the first non-empty response |
| 107 | +- Throws `InvalidOperationException` if internet is unavailable or all providers fail |
| 108 | + |
| 109 | +#### Reverse DNS |
| 110 | + |
| 111 | +- `GetHostnames(IPAddress ipAddress)` |
| 112 | +- `GetHostnames(string ipAddress)` |
| 113 | + |
| 114 | +Behavior: |
| 115 | + |
| 116 | +- Returns a de-duplicated list containing primary hostname and aliases |
| 117 | +- Returns an empty list when reverse DNS is unavailable for the IP |
| 118 | +- Throws: |
| 119 | + - `ArgumentNullException` for null `IPAddress` |
| 120 | + - `ArgumentException` for invalid IP string input |
| 121 | + |
| 122 | +#### Wait for connectivity |
| 123 | + |
| 124 | +- `WaitForInternetAccess()` |
| 125 | +- `WaitForInternetAccess(TimeSpan timeout)` |
| 126 | + |
| 127 | +Behavior: |
| 128 | + |
| 129 | +- Polls connectivity once per second |
| 130 | +- Throws `TimeoutException` when the timeout is exceeded |
| 131 | + |
| 132 | +## Examples |
| 133 | + |
| 134 | +### Check connectivity and wait until online |
| 135 | + |
| 136 | +```csharp |
| 137 | +using NuciWeb.HTTP; |
| 138 | + |
| 139 | +if (!NetworkUtils.HasInternetAccess()) |
| 140 | +{ |
| 141 | + NetworkUtils.WaitForInternetAccess(TimeSpan.FromSeconds(30)); |
| 142 | +} |
| 143 | +``` |
| 144 | + |
| 145 | +### Resolve hostnames for an IP |
| 146 | + |
| 147 | +```csharp |
| 148 | +using System.Net; |
| 149 | +using NuciWeb.HTTP; |
| 150 | + |
| 151 | +List<string> hostnames = NetworkUtils.GetHostnames(IPAddress.Parse("1.1.1.1")); |
| 152 | + |
| 153 | +if (hostnames.Count == 0) |
| 154 | +{ |
| 155 | + // No reverse DNS records were available |
| 156 | +} |
| 157 | +``` |
| 158 | + |
| 159 | +### Use a custom User-Agent fetcher |
| 160 | + |
| 161 | +```csharp |
| 162 | +using System.Threading.Tasks; |
| 163 | +using NuciWeb.HTTP; |
| 164 | + |
| 165 | +public sealed class StaticUaFetcher : IUserAgentFetcher |
| 166 | +{ |
| 167 | + public Task<string> GetUserAgent() |
| 168 | + => Task.FromResult("MyApp/1.0"); |
| 169 | +} |
| 170 | + |
| 171 | +HttpClient client = await HttpClientCreator.CreateAsync(new StaticUaFetcher()); |
| 172 | +``` |
| 173 | + |
| 174 | +## Development |
| 175 | + |
| 176 | +### Prerequisites |
| 177 | + |
| 178 | +- .NET SDK compatible with the target framework |
| 179 | + |
| 180 | +### Build |
| 181 | + |
| 182 | +```bash |
| 183 | +dotnet build NuciWeb.HTTP.csproj |
| 184 | +``` |
| 185 | + |
| 186 | +### Run |
| 187 | + |
| 188 | +```bash |
| 189 | +dotnet run --project NuciWeb.HTTP.csproj |
| 190 | +``` |
| 191 | + |
| 192 | +### Test |
| 193 | + |
| 194 | +```bash |
| 195 | +dotnet test |
| 196 | +``` |
| 197 | + |
| 198 | +## Contributing |
| 199 | + |
| 200 | +Contributions are welcome. |
22 | 201 |
|
23 | | -## Public IP address |
| 202 | +When contributing: |
24 | 203 |
|
25 | | -`NetworkUtils.GetPublicIpAddress()` uses multiple public IP providers. |
| 204 | +- keep the project cross-platform |
| 205 | +- preserve the existing public API unless a breaking change is intentional |
| 206 | +- keep the changes focused and consistent with the current coding style |
| 207 | +- update the documentation when behavior changes |
| 208 | +- include tests for any new behavior |
26 | 209 |
|
27 | | -On each call, it: |
28 | | -- Gets the full list of configured providers |
29 | | -- Randomizes the order |
30 | | -- Tries each provider one by one |
31 | | -- Returns the first successful non-empty response |
| 210 | +## License |
32 | 211 |
|
33 | | -If all providers fail, an `InvalidOperationException` is thrown. |
| 212 | +Licensed under the GNU General Public License v3.0 or later. |
| 213 | +See [LICENSE](./LICENSE) for details. |
0 commit comments