Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
WebGetter.cs
1using System;
2using System.Collections.Generic;
3using System.Net;
4using System.Net.Http;
5using System.Net.Http.Headers;
6using System.Net.Security;
7using System.Runtime.ExceptionServices;
8using System.Security.Authentication;
9using System.Security.Cryptography.X509Certificates;
10using System.Threading.Tasks;
13
15{
20 {
24 public WebGetter()
25 {
26 }
27
31 public string[] UriSchemes => new string[] { "http", "https" };
32
39 public bool CanGet(Uri Uri, out Grade Grade)
40 {
41 switch (Uri.Scheme.ToLower())
42 {
43 case "http":
44 case "https":
45 Grade = Grade.Ok;
46 return true;
47
48 default:
49 Grade = Grade.NotAtAll;
50 return false;
51 }
52 }
53
62 public Task<object> GetAsync(Uri Uri, X509Certificate Certificate,
63 RemoteCertificateEventHandler RemoteCertificateValidator,
64 params KeyValuePair<string, string>[] Headers)
65 {
66 return this.GetAsync(Uri, Certificate, RemoteCertificateValidator, 60000, Headers);
67 }
68
78 public async Task<object> GetAsync(Uri Uri, X509Certificate Certificate,
79 RemoteCertificateEventHandler RemoteCertificateValidator,
80 int TimeoutMs, params KeyValuePair<string, string>[] Headers)
81 {
82 HttpClientHandler Handler = GetClientHandler(Certificate, RemoteCertificateValidator);
83 using (HttpClient HttpClient = new HttpClient(Handler, true)
84 {
85 Timeout = TimeSpan.FromMilliseconds(TimeoutMs)
86 })
87 {
88 using (HttpRequestMessage Request = new HttpRequestMessage()
89 {
90 RequestUri = Uri,
91 Method = HttpMethod.Get
92 })
93 {
94 PrepareHeaders(Request, Headers, Handler);
95
96 HttpResponseMessage Response = await HttpClient.SendAsync(Request);
97
98 return await ProcessResponse(Response, Uri);
99 }
100 }
101 }
102
107 public static HttpClientHandler GetClientHandler()
108 {
109 return GetClientHandler(null, null);
110 }
111
118 public static HttpClientHandler GetClientHandler(X509Certificate Certificate,
119 RemoteCertificateEventHandler RemoteCertificateValidator)
120 {
121 RemoteCertificateValidator Validator = new RemoteCertificateValidator(RemoteCertificateValidator);
122
123 HttpClientHandler Handler = new HttpClientHandler()
124 {
125 AllowAutoRedirect = true,
126 CheckCertificateRevocationList = true,
127 ClientCertificateOptions = ClientCertificateOption.Automatic,
128 ServerCertificateCustomValidationCallback = Validator.RemoteCertificateValidationCallback,
129 AutomaticDecompression = (DecompressionMethods)(-1) // All
130 };
131
132 try
133 {
134 Handler.SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
135 }
136 catch (PlatformNotSupportedException)
137 {
138 // Ignore
139 }
140
141 if (!(Certificate is null))
142 {
143 Handler.ClientCertificateOptions = ClientCertificateOption.Manual;
144 Handler.ClientCertificates.Add(Certificate);
145 }
146
147 return Handler;
148 }
149
153 private class RemoteCertificateValidator
154 {
155 private readonly RemoteCertificateEventHandler callback;
156
161 public RemoteCertificateValidator(RemoteCertificateEventHandler Callback)
162 {
163 this.callback = Callback;
164 }
165
166 public bool RemoteCertificateValidationCallback(object Sender,
167 X509Certificate Certificate, X509Chain Chain, SslPolicyErrors SslPolicyErrors)
168 {
169 RemoteCertificateEventArgs e = new RemoteCertificateEventArgs(Certificate, Chain, SslPolicyErrors);
170
171 if (!(this.callback is null))
172 this.callback(Sender, e);
173
174 if (e.IsValid.HasValue)
175 return e.IsValid.Value;
176 else
177 return SslPolicyErrors == SslPolicyErrors.None;
178 }
179 }
180
189 public static async Task<object> ProcessResponse(HttpResponseMessage Response, Uri Uri)
190 {
191 byte[] Bin = await Response.Content.ReadAsByteArrayAsync();
192 string ContentType;
193 object Decoded;
194
195 if (Bin.Length == 0 || Response.Content.Headers.ContentType is null)
196 {
197 Decoded = Bin;
198 ContentType = string.Empty;
199 }
200 else
201 {
202 ContentType = Response.Content.Headers.ContentType.ToString();
203 Decoded = await InternetContent.DecodeAsync(ContentType, Bin, Uri);
204 }
205
206 if (Decoded is IWebServerMetaContent WebServerMetaContent)
207 await WebServerMetaContent.DecodeMetaInformation(Response);
208
209 if (!Response.IsSuccessStatusCode)
210 {
211 if (!(Decoded is string Message))
212 {
213 if (Decoded is null ||
214 (Decoded is byte[] Bin2 && Bin2.Length == 0) ||
215 Decoded is Dictionary<string, object>)
216 {
217 Message = Response.ReasonPhrase;
218 }
219 else
220 Message = Decoded.ToString();
221 }
222
223 throw new WebException(Message, Response.StatusCode, ContentType, Bin, Decoded, Response.Headers);
224 }
225
226 return Decoded;
227 }
228
229 internal static void PrepareHeaders(HttpRequestMessage Request, KeyValuePair<string, string>[] Headers, HttpClientHandler Handler)
230 {
231 if (!(Headers is null))
232 {
233 foreach (KeyValuePair<string, string> Header in Headers)
234 {
235 switch (Header.Key)
236 {
237 case "Accept":
238 if (!Request.Headers.Accept.TryParseAdd(Header.Value))
239 throw new InvalidOperationException("Invalid Accept header value: " + Header.Value);
240 break;
241
242 case "Authorization":
243 int i = Header.Value.IndexOf(' ');
244 if (i < 0)
245 Request.Headers.Authorization = new AuthenticationHeaderValue(Header.Value);
246 else
247 Request.Headers.Authorization = new AuthenticationHeaderValue(Header.Value.Substring(0, i), Header.Value.Substring(i + 1).TrimStart());
248 break;
249
250 case "Cookie":
251 foreach (KeyValuePair<string, string> P in CommonTypes.ParseFieldValues(Header.Value))
252 Handler.CookieContainer.Add(Request.RequestUri, new Cookie(P.Key, P.Value));
253 break;
254
255 default:
256 Request.Headers.Add(Header.Key, Header.Value);
257 break;
258 }
259 }
260 }
261 }
262
271 public Task<KeyValuePair<string, TemporaryStream>> GetTempStreamAsync(Uri Uri, X509Certificate Certificate,
272 RemoteCertificateEventHandler RemoteCertificateValidator, params KeyValuePair<string, string>[] Headers)
273 {
274 return this.GetTempStreamAsync(Uri, Certificate, RemoteCertificateValidator, 60000, Headers);
275 }
276
286 public async Task<KeyValuePair<string, TemporaryStream>> GetTempStreamAsync(Uri Uri, X509Certificate Certificate,
287 RemoteCertificateEventHandler RemoteCertificateValidator, int TimeoutMs, params KeyValuePair<string, string>[] Headers)
288 {
289 HttpClientHandler Handler = GetClientHandler(Certificate, RemoteCertificateValidator);
290 using (HttpClient HttpClient = new HttpClient(Handler, true)
291 {
292 Timeout = TimeSpan.FromMilliseconds(10000)
293 })
294 {
295 using (HttpRequestMessage Request = new HttpRequestMessage()
296 {
297 RequestUri = Uri,
298 Method = HttpMethod.Get
299 })
300 {
301 PrepareHeaders(Request, Headers, Handler);
302
303 HttpResponseMessage Response = await HttpClient.SendAsync(Request);
304
305 if (!Response.IsSuccessStatusCode)
306 await ProcessResponse(Response, Uri);
307
308 string ContentType = Response.Content.Headers.ContentType.ToString();
309 TemporaryStream File = new TemporaryStream();
310 try
311 {
312 await Response.Content.CopyToAsync(File);
313 }
314 catch (Exception ex)
315 {
316 File.Dispose();
317 File = null;
318
319 ExceptionDispatchInfo.Capture(ex).Throw();
320 }
321
322 return new KeyValuePair<string, TemporaryStream>(ContentType, File);
323 }
324 }
325 }
326
333 public bool CanHead(Uri Uri, out Grade Grade)
334 {
335 return this.CanGet(Uri, out Grade);
336 }
337
346 public Task<object> HeadAsync(Uri Uri, X509Certificate Certificate,
347 RemoteCertificateEventHandler RemoteCertificateValidator,
348 params KeyValuePair<string, string>[] Headers)
349 {
350 return this.HeadAsync(Uri, Certificate, RemoteCertificateValidator, 60000, Headers);
351 }
352
362 public async Task<object> HeadAsync(Uri Uri, X509Certificate Certificate,
363 RemoteCertificateEventHandler RemoteCertificateValidator,
364 int TimeoutMs, params KeyValuePair<string, string>[] Headers)
365 {
366 HttpClientHandler Handler = GetClientHandler(Certificate, RemoteCertificateValidator);
367 using (HttpClient HttpClient = new HttpClient(Handler, true)
368 {
369 Timeout = TimeSpan.FromMilliseconds(TimeoutMs)
370 })
371 {
372 using (HttpRequestMessage Request = new HttpRequestMessage()
373 {
374 RequestUri = Uri,
375 Method = HttpMethod.Head
376 })
377 {
378 PrepareHeaders(Request, Headers, Handler);
379
380 HttpResponseMessage Response = await HttpClient.SendAsync(Request);
381 Dictionary<string, object> Result = new Dictionary<string, object>()
382 {
383 { "Status", Response.StatusCode },
384 { "StatusCode", (int)Response.StatusCode },
385 { "Message", Response.ReasonPhrase },
386 { "IsSuccessStatusCode", Response.IsSuccessStatusCode },
387 { "Version", Response.Version.ToString() }
388 };
389
390 foreach (KeyValuePair<string, IEnumerable<string>> Header in Response.Headers)
391 {
392 string s = null;
393 List<string> List = null;
394
395 foreach (string Value in Header.Value)
396 {
397 if (s is null)
398 s = Value;
399 else
400 {
401 if (List is null)
402 List = new List<string>() { s };
403
404 List.Add(Value);
405 }
406 }
407
408 if (List is null)
409 Result[Header.Key] = s;
410 else
411 Result[Header.Key] = List.ToArray();
412 }
413
414 return Result;
415 }
416 }
417 }
418
419 }
420}
Helps with parsing of commong data types.
Definition: CommonTypes.cs:13
static KeyValuePair< string, string >[] ParseFieldValues(string Value)
Parses a set of comma or semicolon-separated field values, optionaly delimited by ' or " characters.
Definition: CommonTypes.cs:472
Exception class for web exceptions.
Definition: WebException.cs:11
Gets resources from the Web (i.e. using HTTP or HTTPS).
Definition: WebGetter.cs:20
bool CanGet(Uri Uri, out Grade Grade)
If the getter is able to get a resource, given its URI.
Definition: WebGetter.cs:39
WebGetter()
Gets resources from the Web (i.e. using HTTP or HTTPS).
Definition: WebGetter.cs:24
static HttpClientHandler GetClientHandler(X509Certificate Certificate, RemoteCertificateEventHandler RemoteCertificateValidator)
Gets a HTTP Client handler
Definition: WebGetter.cs:118
Task< object > HeadAsync(Uri Uri, X509Certificate Certificate, RemoteCertificateEventHandler RemoteCertificateValidator, params KeyValuePair< string, string >[] Headers)
Gets the headers of a resource, using a Uniform Resource Identifier (or Locator).
Definition: WebGetter.cs:346
Task< object > GetAsync(Uri Uri, X509Certificate Certificate, RemoteCertificateEventHandler RemoteCertificateValidator, params KeyValuePair< string, string >[] Headers)
Gets a resource, using a Uniform Resource Identifier (or Locator).
Definition: WebGetter.cs:62
async Task< object > GetAsync(Uri Uri, X509Certificate Certificate, RemoteCertificateEventHandler RemoteCertificateValidator, int TimeoutMs, params KeyValuePair< string, string >[] Headers)
Gets a resource, using a Uniform Resource Identifier (or Locator).
Definition: WebGetter.cs:78
static HttpClientHandler GetClientHandler()
Gets a HTTP Client handler
Definition: WebGetter.cs:107
static async Task< object > ProcessResponse(HttpResponseMessage Response, Uri Uri)
Decodes a response from the web. If the response is a success, the decoded response is returned....
Definition: WebGetter.cs:189
string[] UriSchemes
Supported URI schemes.
Definition: WebGetter.cs:31
Task< KeyValuePair< string, TemporaryStream > > GetTempStreamAsync(Uri Uri, X509Certificate Certificate, RemoteCertificateEventHandler RemoteCertificateValidator, params KeyValuePair< string, string >[] Headers)
Gets a (possibly big) resource, using a Uniform Resource Identifier (or Locator).
Definition: WebGetter.cs:271
async Task< KeyValuePair< string, TemporaryStream > > GetTempStreamAsync(Uri Uri, X509Certificate Certificate, RemoteCertificateEventHandler RemoteCertificateValidator, int TimeoutMs, params KeyValuePair< string, string >[] Headers)
Gets a (possibly big) resource, using a Uniform Resource Identifier (or Locator).
Definition: WebGetter.cs:286
bool CanHead(Uri Uri, out Grade Grade)
If the getter is able to get headers of a resource, given its URI.
Definition: WebGetter.cs:333
async Task< object > HeadAsync(Uri Uri, X509Certificate Certificate, RemoteCertificateEventHandler RemoteCertificateValidator, int TimeoutMs, params KeyValuePair< string, string >[] Headers)
Gets the headers of a resource, using a Uniform Resource Identifier (or Locator).
Definition: WebGetter.cs:362
Static class managing encoding and decoding of internet content.
static Task< object > DecodeAsync(string ContentType, byte[] Data, Encoding Encoding, KeyValuePair< string, string >[] Fields, Uri BaseUri)
Decodes an object.
Remove certificate validation event arguments.
bool? IsValid
If remote certificate is considered valid or not. null means default validation rules will be applied...
Manages a temporary stream. Contents is kept in-memory, if below a memory threshold,...
override void Dispose(bool disposing)
Releases the unmanaged resources used by the System.IO.Stream and optionally releases the managed res...
Interface for content classes, that process information available in HTTP headers in the response.
Basic interface for Internet Content getters. A class implementing this interface and having a defaul...
Basic interface for Internet Content headers. A class implementing this interface and having a defaul...
delegate void RemoteCertificateEventHandler(object Sender, RemoteCertificateEventArgs e)
Delegate for remote certificate event handlers.
Grade
Grade enumeration
Definition: Grade.cs:7