lampac-talks f843f04fd4 chore: initial commit 154.3
Signed-off-by: lampac-talks <lampac-talks@users.noreply.github.com>
2026-01-30 16:23:09 +03:00

1214 lines
54 KiB
C#

using Newtonsoft.Json;
using Shared.Engine.Pools;
using Shared.Engine.Utilities;
using Shared.Models;
using Shared.Models.Events;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
namespace Shared.Engine
{
public static class Http
{
static readonly ThreadLocal<JsonSerializer> _serializerDefault = new ThreadLocal<JsonSerializer>(JsonSerializer.CreateDefault);
static readonly ThreadLocal<JsonSerializer> _serializerIgnoreDeserialize = new ThreadLocal<JsonSerializer>(() => JsonSerializer.Create(new JsonSerializerSettings { Error = (se, ev) => { ev.ErrorContext.Handled = true; } }));
public static IHttpClientFactory httpClientFactory;
#region defaultHeaders / UserAgent
public static readonly Dictionary<string, string> defaultUaHeaders = new Dictionary<string, string>()
{
["sec-ch-ua-mobile"] = "?0",
["sec-ch-ua-platform"] = "\"Windows\"",
["sec-ch-ua"] = "\"Chromium\";v=\"142\", \"Google Chrome\";v=\"142\", \"Not_A Brand\";v=\"99\"",
["user-agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36"
};
public static readonly Dictionary<string, string> defaultCommonHeaders = new Dictionary<string, string>()
{
["cache-control"] = "no-cache",
["dnt"] = "1",
["pragma"] = "no-cache",
["priority"] = "u=0, i"
};
public static readonly Dictionary<string, string> defaultFullHeaders = defaultUaHeaders.Concat(defaultCommonHeaders).ToDictionary(
kv => kv.Key,
kv => kv.Value
);
public static string UserAgent => defaultUaHeaders["user-agent"];
#endregion
#region Handler
public static HttpClientHandler Handler(string url, WebProxy proxy, CookieContainer cookieContainer = null)
{
return Handler(url, proxy, null, cookieContainer);
}
static HttpClientHandler Handler(string url, WebProxy proxy, StringBuilder loglines, CookieContainer cookieContainer = null)
{
var handler = new HttpClientHandler()
{
AllowAutoRedirect = true,
AutomaticDecompression = DecompressionMethods.Brotli | DecompressionMethods.GZip | DecompressionMethods.Deflate
};
handler.ServerCertificateCustomValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
if (proxy != null)
{
handler.UseProxy = true;
handler.Proxy = proxy;
if (loglines != null && IsLogged)
loglines.Append($"proxy: {proxy.Address.ToString()}\n");
}
else
{
handler.UseProxy = false;
}
if (cookieContainer != null)
{
handler.CookieContainer = cookieContainer;
handler.UseCookies = true; //<-- Enable the use of cookies.
}
if (AppInit.conf.globalproxy != null && AppInit.conf.globalproxy.Length > 0)
{
foreach (var p in AppInit.conf.globalproxy)
{
if (p.list == null || p.list.Length == 0 || p.pattern == null)
continue;
if (Regex.IsMatch(url, p.pattern, RegexOptions.IgnoreCase))
{
string proxyip = p.list.OrderBy(a => Guid.NewGuid()).First();
NetworkCredential credentials = null;
if (proxyip.Contains("@"))
{
var g = Regex.Match(proxyip, p.pattern_auth).Groups;
proxyip = g["sheme"].Value + g["host"].Value;
credentials = new NetworkCredential(g["username"].Value, g["password"].Value);
}
else if (p.useAuth)
credentials = new NetworkCredential(p.username, p.password);
handler.UseProxy = true;
handler.Proxy = new WebProxy(proxyip, p.BypassOnLocal, null, credentials);
if (loglines != null && IsLogged)
loglines.Append($"globalproxy: {proxyip} {(p.useAuth ? $" - {p.username}:{p.password}" : "")}\n");
break;
}
}
}
if (InvkEvent.IsHttpClientHandler())
InvkEvent.HttpClientHandler(new EventHttpHandler(url, handler, proxy, cookieContainer, Startup.memoryCache));
return handler;
}
#endregion
#region DefaultRequestHeaders
public static void DefaultRequestHeaders(string url, HttpRequestMessage client, string cookie, string referer, List<HeadersModel> headers, bool useDefaultHeaders = true)
{
DefaultRequestHeaders(url, client, cookie, referer, headers, null, useDefaultHeaders);
}
public static void DefaultRequestHeaders(string url, HttpRequestMessage client, string cookie, string referer, List<HeadersModel> headers, StringBuilder loglines, bool useDefaultHeaders = true)
{
var addHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (useDefaultHeaders)
{
addHeaders.TryAdd("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
addHeaders.TryAdd("accept-language", "ru-RU,ru;q=0.9,uk-UA;q=0.8,uk;q=0.7,en-US;q=0.6,en;q=0.5");
}
if (cookie != null)
addHeaders.TryAdd("cookie", cookie);
if (referer != null)
addHeaders.TryAdd("referer", referer);
if (useDefaultHeaders)
{
if (headers != null && headers.FirstOrDefault(i => i.name.Equals("user-agent", StringComparison.OrdinalIgnoreCase)) != null)
{
foreach (var h in defaultCommonHeaders)
addHeaders.TryAdd(h.Key, h.Value);
}
else
{
foreach (var h in defaultFullHeaders)
addHeaders.TryAdd(h.Key, h.Value);
}
}
if (headers != null)
{
foreach (var h in headers)
addHeaders[h.name] = h.val;
}
if (NormalizeHeaders(addHeaders) is var normalizeHeaders && normalizeHeaders != null)
{
foreach (var h in normalizeHeaders)
{
if (client.Headers.TryAddWithoutValidation(h.Key, h.Value))
{
if (IsLogged && loglines != null)
loglines.Append($"{h.Key}: {h.Value}\n");
}
else if (client.Content?.Headers != null)
{
if (client.Content.Headers.TryAddWithoutValidation(h.Key, h.Value))
{
if (IsLogged && loglines != null)
loglines.Append($"{h.Key}: {h.Value}\n");
}
}
}
}
if (InvkEvent.IsHttpClientHeaders())
InvkEvent.HttpClientHeaders(new EventHttpHeaders(url, client, cookie, referer, headers, useDefaultHeaders, Startup.memoryCache));
}
#endregion
#region NormalizeHeaders
public static Dictionary<string, T> NormalizeHeaders<T>(Dictionary<string, T> raw)
{
if (raw == null || raw.Count == 0)
return null;
var result = new Dictionary<string, T>(raw.Count, StringComparer.Ordinal);
foreach (var kv in raw)
result[NormalizeHeaderName(kv.Key)] = kv.Value;
return result;
}
public static Dictionary<string, string> NormalizeHeaders(List<HeadersModel> raw)
{
if (raw == null || raw.Count == 0)
return null;
var result = new Dictionary<string, string>(raw.Count, StringComparer.Ordinal);
foreach (var kv in raw)
result[NormalizeHeaderName(kv.name)] = kv.val;
return result;
}
private static string NormalizeHeaderName(string key)
{
return string.Create(key.Length, key, static (span, src) =>
{
bool upper = true;
for (int i = 0; i < src.Length; i++)
{
char c = src[i];
if (c == '-')
{
span[i] = '-';
upper = true;
continue;
}
if (upper)
{
// Для заголовков обычно корректнее invariant
span[i] = char.ToUpperInvariant(c);
upper = false;
}
else
{
span[i] = c;
}
}
});
}
#endregion
#region GetLocation
async public static Task<string> GetLocation(string url, string referer = null, int timeoutSeconds = 8, List<HeadersModel> headers = null, int httpversion = 1, bool allowAutoRedirect = false, WebProxy proxy = null)
{
try
{
var handler = Handler(url, proxy);
handler.AllowAutoRedirect = allowAutoRedirect;
var client = FrendlyHttp.MessageClient(httpversion == 2 ? "http2" : "base", handler);
var req = new HttpRequestMessage(HttpMethod.Get, url)
{
Version = httpversion == 1 ? HttpVersion.Version11 : new Version(httpversion, 0)
};
DefaultRequestHeaders(url, req, null, referer, headers);
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(Math.Max(5, timeoutSeconds))))
{
using (HttpResponseMessage response = await client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, cts.Token).ConfigureAwait(false))
{
string location = (int)response.StatusCode == 301 || (int)response.StatusCode == 302 || (int)response.StatusCode == 307 ? response.Headers.Location?.ToString() : response.RequestMessage.RequestUri?.ToString();
location = Uri.EscapeUriString(System.Web.HttpUtility.UrlDecode(location ?? ""));
return string.IsNullOrWhiteSpace(location) ? null : location;
}
}
}
catch
{
return null;
}
}
#endregion
#region ResponseHeaders
async public static Task<HttpResponseMessage> ResponseHeaders(string url, int timeoutSeconds = 8, List<HeadersModel> headers = null, int httpversion = 1, bool allowAutoRedirect = false, WebProxy proxy = null)
{
try
{
var handler = Handler(url, proxy);
handler.AllowAutoRedirect = allowAutoRedirect;
var client = FrendlyHttp.MessageClient(httpversion == 2 ? "http2" : "base", handler);
var req = new HttpRequestMessage(HttpMethod.Get, url)
{
Version = httpversion == 1 ? HttpVersion.Version11 : new Version(httpversion, 0)
};
DefaultRequestHeaders(url, req, null, null, headers);
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(Math.Max(5, timeoutSeconds))))
using (HttpResponseMessage response = await client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, cts.Token).ConfigureAwait(false))
return response;
}
catch
{
return null;
}
}
#endregion
#region Get<T>
async public static Task<T> Get<T>(string url, string cookie = null, string referer = null, long MaxResponseContentBufferSize = 0, int timeoutSeconds = 15, List<HeadersModel> headers = null, bool IgnoreDeserializeObject = false, WebProxy proxy = null, bool statusCodeOK = true, int httpversion = 1, CookieContainer cookieContainer = null, bool useDefaultHeaders = true, bool weblog = true, HttpContent body = null)
{
return (await BaseGetAsync<T>(
url, cookie, referer, MaxResponseContentBufferSize, timeoutSeconds, headers, IgnoreDeserializeObject, proxy,statusCodeOK, httpversion, cookieContainer, useDefaultHeaders, body, weblog
).ConfigureAwait(false)).content;
}
#endregion
#region BaseGetAsync<T>
async public static Task<(T content, HttpResponseMessage response)> BaseGetAsync<T>(string url, string cookie = null, string referer = null, long MaxResponseContentBufferSize = 0, int timeoutSeconds = 15, List<HeadersModel> headers = null, bool IgnoreDeserializeObject = false, WebProxy proxy = null, bool statusCodeOK = true, int httpversion = 1, CookieContainer cookieContainer = null, bool useDefaultHeaders = true, HttpContent body = null, bool weblog = true)
{
var ms = PoolInvk.msm.GetStream();
try
{
T result = default;
var req = await BaseGetReaderAsync(async e =>
{
try
{
await e.stream.CopyToAsync(ms, PoolInvk.bufferSize, e.ct);
ms.Position = 0;
using (var streamReader = new StreamReader(ms, Encoding.UTF8, detectEncodingFromByteOrderMarks: false, bufferSize: PoolInvk.bufferSize, leaveOpen: true))
{
using (var jsonReader = new JsonTextReader(streamReader)
{
ArrayPool = NewtonsoftPool.Array
})
{
var serializer = IgnoreDeserializeObject
? _serializerIgnoreDeserialize.Value
: _serializerDefault.Value;
result = serializer.Deserialize<T>(jsonReader);
if (e.loglines != null)
e.loglines.Append($"\n{JsonConvert.SerializeObject(result, Formatting.Indented)}");
}
}
}
catch (Exception ex)
{
if (e.loglines != null)
e.loglines.Append($"\n{ex.Message}");
}
},
url, cookie, referer, MaxResponseContentBufferSize, timeoutSeconds, headers, IgnoreDeserializeObject, proxy, statusCodeOK, httpversion, cookieContainer, useDefaultHeaders, body, weblog
).ConfigureAwait(false);
return (result, req.response);
}
finally
{
ms.Dispose();
}
}
#endregion
#region BaseGetReaderAsync
async public static Task<(bool success, HttpResponseMessage response)> BaseGetReaderAsync(Action<(Stream stream, CancellationToken ct, StringBuilder loglines)> action, string url, string cookie = null, string referer = null, long MaxResponseContentBufferSize = 0, int timeoutSeconds = 15, List<HeadersModel> headers = null, bool IgnoreDeserializeObject = false, WebProxy proxy = null, bool statusCodeOK = true, int httpversion = 1, CookieContainer cookieContainer = null, bool useDefaultHeaders = true, HttpContent body = null, bool weblog = true)
{
try
{
var loglines = IsLogged && weblog
? StringBuilderPool.Rent()
: null;
try
{
var handler = Handler(url, proxy, loglines, cookieContainer);
var client = FrendlyHttp.MessageClient(httpversion == 1 ? "base" : $"http{httpversion}", handler, MaxResponseContentBufferSize);
if (cookieContainer != null && loglines != null)
{
var cookiesString = new StringBuilder(200);
foreach (Cookie c in cookieContainer.GetCookies(new Uri(url)))
cookiesString.Append($"{c.Name}={c.Value}; ");
if (cookiesString.Length > 0)
loglines.Append($"Cookie: {cookiesString.ToString().TrimEnd(' ', ';')}\n");
}
var req = new HttpRequestMessage(HttpMethod.Get, url)
{
Version = httpversion == 1 ? HttpVersion.Version11 : new Version(httpversion, 0),
Content = body
};
DefaultRequestHeaders(url, req, cookie, referer, headers, loglines, useDefaultHeaders);
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(Math.Max(5, timeoutSeconds))))
{
using (HttpResponseMessage response = await client.SendAsync(req, cts.Token).ConfigureAwait(false))
{
if (loglines != null)
{
loglines.Append($"\n\nStatusCode: {(int)response.StatusCode}\n");
foreach (var h in response.Headers)
{
if (h.Key == "Set-Cookie")
{
foreach (string v in h.Value)
loglines.Append($"{h.Key}: {v}\n");
}
else
loglines.Append($"{h.Key}: {string.Join("", h.Value)}\n");
}
}
using (HttpContent content = response.Content)
{
if (InvkEvent.IsHttpAsync())
await InvkEvent.HttpAsync(new EventHttpResponse(url, null, client, "ReadAsStream", response, Startup.memoryCache));
if (statusCodeOK && response.StatusCode != HttpStatusCode.OK)
return (false, response);
using (var stream = await content.ReadAsStreamAsync(cts.Token).ConfigureAwait(false))
{
action.Invoke((stream, cts.Token, loglines));
return (true, response);
}
}
}
}
}
catch (Exception ex)
{
if (loglines != null)
loglines.Append(ex.ToString());
if (InvkEvent.IsHttpAsync())
{
await InvkEvent.HttpAsync(new EventHttpResponse(url, null, null, ex.ToString(), new HttpResponseMessage()
{
StatusCode = HttpStatusCode.InternalServerError,
RequestMessage = new HttpRequestMessage()
}, Startup.memoryCache));
}
return (false, new HttpResponseMessage()
{
StatusCode = HttpStatusCode.InternalServerError,
RequestMessage = new HttpRequestMessage()
});
}
finally
{
if (!url.Contains("127.0.0.1") && loglines != null)
WriteLog(url, "GET", body == null ? null : body.ReadAsStringAsync().Result, loglines);
StringBuilderPool.Return(loglines);
}
}
catch
{
return default;
}
}
#endregion
#region GetSpan
async public static Task<bool> GetSpan(Action<ReadOnlySpan<char>> spanAction, string url, Encoding encoding = default, string cookie = null, string referer = null, long MaxResponseContentBufferSize = 0, int timeoutSeconds = 15, List<HeadersModel> headers = null, bool IgnoreDeserializeObject = false, WebProxy proxy = null, bool statusCodeOK = true, int httpversion = 1, CookieContainer cookieContainer = null, bool useDefaultHeaders = true, HttpContent body = null, bool weblog = true)
{
var ms = PoolInvk.msm.GetStream();
try
{
var req = await BaseGetReaderAsync(async e =>
{
try
{
await e.stream.CopyToAsync(ms, PoolInvk.bufferSize, e.ct);
ms.Position = 0;
OwnerTo.Span(ms, encoding != default ? encoding : Encoding.UTF8, span =>
{
if (span.IsEmpty)
return;
spanAction.Invoke(span);
if (e.loglines != null)
e.loglines.Append($"\n{span.ToString()}");
});
}
catch (Exception ex)
{
if (e.loglines != null)
e.loglines.Append($"\n{ex.Message}");
}
},
url, cookie, referer, MaxResponseContentBufferSize, timeoutSeconds, headers, IgnoreDeserializeObject, proxy, statusCodeOK, httpversion, cookieContainer, useDefaultHeaders, body, weblog
).ConfigureAwait(false);
return req.success;
}
finally
{
ms.Dispose();
}
}
#endregion
#region PostSpan
async public static Task<bool> PostSpan(Action<ReadOnlySpan<char>> spanAction, string url, string data, string cookie = null, int timeoutSeconds = 15, List<HeadersModel> headers = null, Encoding encoding = default, WebProxy proxy = null, bool IgnoreDeserializeObject = false, CookieContainer cookieContainer = null, bool useDefaultHeaders = true, int httpversion = 1, int MaxResponseContentBufferSize = 0, bool statusCodeOK = true)
{
var ms = PoolInvk.msm.GetStream();
try
{
var req = await BasePostReaderAsync(async e =>
{
try
{
await e.stream.CopyToAsync(ms, PoolInvk.bufferSize, e.ct);
ms.Position = 0;
OwnerTo.Span(ms, encoding != default ? encoding : Encoding.UTF8, span =>
{
if (span.IsEmpty)
return;
spanAction.Invoke(span);
if (e.loglines != null)
e.loglines.Append($"\n{span.ToString()}");
});
}
catch (Exception ex)
{
if (e.loglines != null)
e.loglines.Append($"\n{ex.Message}");
}
},
url, new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded"),
cookie, MaxResponseContentBufferSize, timeoutSeconds, headers, proxy, httpversion, cookieContainer, useDefaultHeaders, IgnoreDeserializeObject, statusCodeOK
).ConfigureAwait(false);
return req.success;
}
finally
{
ms.Dispose();
}
}
#endregion
#region Get
async public static Task<string> Get(string url, Encoding encoding = default, string cookie = null, string referer = null, int timeoutSeconds = 15, List<HeadersModel> headers = null, long MaxResponseContentBufferSize = 0, WebProxy proxy = null, int httpversion = 1, bool statusCodeOK = true, bool weblog = true, CookieContainer cookieContainer = null, bool useDefaultHeaders = true, HttpContent body = null)
{
return (await BaseGet(url, encoding, cookie: cookie, referer: referer, timeoutSeconds: timeoutSeconds, headers: headers, MaxResponseContentBufferSize: MaxResponseContentBufferSize, proxy: proxy, httpversion: httpversion, statusCodeOK: statusCodeOK, weblog: weblog, cookieContainer: cookieContainer, useDefaultHeaders: useDefaultHeaders, body: body).ConfigureAwait(false)).content;
}
#endregion
#region BaseGet
async public static Task<(string content, HttpResponseMessage response)> BaseGet(string url, Encoding encoding = default, string cookie = null, string referer = null, int timeoutSeconds = 15, long MaxResponseContentBufferSize = 0, List<HeadersModel> headers = null, WebProxy proxy = null, int httpversion = 1, bool statusCodeOK = true, bool weblog = true, CookieContainer cookieContainer = null, bool useDefaultHeaders = true, HttpContent body = null)
{
var loglines = IsLogged && weblog
? StringBuilderPool.Rent()
: null;
try
{
var handler = Handler(url, proxy, loglines, cookieContainer);
var client = FrendlyHttp.MessageClient(httpversion == 1 ? "base" : $"http{httpversion}", handler, MaxResponseContentBufferSize);
if (cookieContainer != null && loglines != null)
{
var cookiesString = new StringBuilder(200);
foreach (Cookie c in cookieContainer.GetCookies(new Uri(url)))
cookiesString.Append($"{c.Name}={c.Value}; ");
if (cookiesString.Length > 0)
loglines.Append($"Cookie: {cookiesString.ToString().TrimEnd(' ', ';')}\n");
}
var req = new HttpRequestMessage(HttpMethod.Get, url)
{
Version = httpversion == 1 ? HttpVersion.Version11 : new Version(httpversion, 0),
Content = body
};
DefaultRequestHeaders(url, req, cookie, referer, headers, loglines, useDefaultHeaders);
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(Math.Max(5, timeoutSeconds))))
{
using (HttpResponseMessage response = await client.SendAsync(req, cts.Token).ConfigureAwait(false))
{
if (loglines != null)
{
loglines.Append($"\n\nStatusCode: {(int)response.StatusCode}\n");
foreach (var h in response.Headers)
{
if (h.Key == "Set-Cookie")
{
foreach (string v in h.Value)
loglines.Append($"{h.Key}: {v}\n");
}
else
loglines.Append($"{h.Key}: {string.Join("", h.Value)}\n");
}
}
using (HttpContent content = response.Content)
{
if (encoding != default)
{
string res = encoding.GetString(await content.ReadAsByteArrayAsync(cts.Token).ConfigureAwait(false));
if (InvkEvent.IsHttpAsync())
await InvkEvent.HttpAsync(new EventHttpResponse(url, null, client, res, response, Startup.memoryCache));
if (string.IsNullOrWhiteSpace(res))
return (null, response);
if (loglines != null)
loglines.Append($"\n{res}");
if (statusCodeOK && response.StatusCode != HttpStatusCode.OK)
return (null, response);
return (res, response);
}
else
{
string res = await content.ReadAsStringAsync(cts.Token).ConfigureAwait(false);
if (InvkEvent.IsHttpAsync())
await InvkEvent.HttpAsync(new EventHttpResponse(url, null, client, res, response, Startup.memoryCache));
if (string.IsNullOrWhiteSpace(res))
return (null, response);
if (loglines != null)
loglines.Append($"\n{res}");
if (statusCodeOK && response.StatusCode != HttpStatusCode.OK)
return (null, response);
return (res, response);
}
}
}
}
}
catch (Exception ex)
{
if (loglines != null)
loglines.Append(ex.ToString());
if (InvkEvent.IsHttpAsync())
{
await InvkEvent.HttpAsync(new EventHttpResponse(url, null, null, ex.ToString(), new HttpResponseMessage()
{
StatusCode = HttpStatusCode.InternalServerError,
RequestMessage = new HttpRequestMessage()
}, Startup.memoryCache));
}
return (null, new HttpResponseMessage()
{
StatusCode = HttpStatusCode.InternalServerError,
RequestMessage = new HttpRequestMessage()
});
}
finally
{
if (!url.Contains("127.0.0.1") && loglines != null)
WriteLog(url, "GET", body == null ? null : body.ReadAsStringAsync().Result, loglines);
StringBuilderPool.Return(loglines);
}
}
#endregion
#region Post
public static Task<string> Post(string url, string data, string cookie = null, int MaxResponseContentBufferSize = 0, int timeoutSeconds = 15, List<HeadersModel> headers = null, WebProxy proxy = null, int httpversion = 1, CookieContainer cookieContainer = null, bool useDefaultHeaders = true, bool removeContentType = false, Encoding encoding = default, bool statusCodeOK = true)
{
return Post(url, new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded"),
encoding, cookie, MaxResponseContentBufferSize, timeoutSeconds, headers, proxy, httpversion, cookieContainer, useDefaultHeaders, removeContentType, statusCodeOK
);
}
async public static Task<string> Post(string url, HttpContent data, Encoding encoding = default, string cookie = null, int MaxResponseContentBufferSize = 0, int timeoutSeconds = 15, List<HeadersModel> headers = null, WebProxy proxy = null, int httpversion = 1, CookieContainer cookieContainer = null, bool useDefaultHeaders = true, bool removeContentType = false, bool statusCodeOK = true)
{
return (await BasePost(
url, data, encoding, cookie, MaxResponseContentBufferSize, timeoutSeconds, headers, proxy, httpversion, cookieContainer, useDefaultHeaders, removeContentType, statusCodeOK
).ConfigureAwait(false)).content;
}
#endregion
#region BasePost
async public static Task<(string content, HttpResponseMessage response)> BasePost(string url, HttpContent data, Encoding encoding = default, string cookie = null, int MaxResponseContentBufferSize = 0, int timeoutSeconds = 15, List<HeadersModel> headers = null, WebProxy proxy = null, int httpversion = 1, CookieContainer cookieContainer = null, bool useDefaultHeaders = true, bool removeContentType = false, bool statusCodeOK = true)
{
var loglines = IsLogged
? StringBuilderPool.Rent()
: null;
try
{
var handler = Handler(url, proxy, loglines, cookieContainer);
var client = FrendlyHttp.MessageClient(httpversion == 1 ? "base" : $"http{httpversion}", handler, MaxResponseContentBufferSize);
if (cookieContainer != null && loglines != null)
{
var cookiesString = new StringBuilder(200);
foreach (Cookie c in cookieContainer.GetCookies(new Uri(url)))
cookiesString.Append($"{c.Name}={c.Value}; ");
if (cookiesString.Length > 0)
loglines.Append($"Cookie: {cookiesString.ToString().TrimEnd(' ', ';')}\n");
}
var req = new HttpRequestMessage(HttpMethod.Post, url)
{
Version = httpversion == 1 ? HttpVersion.Version11 : new Version(httpversion, 0),
Content = data
};
DefaultRequestHeaders(url, req, cookie, null, headers, loglines, useDefaultHeaders);
if (removeContentType)
req.Content.Headers.Remove("Content-Type");
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(Math.Max(5, timeoutSeconds))))
{
using (HttpResponseMessage response = await client.SendAsync(req, cts.Token).ConfigureAwait(false))
{
if (loglines != null)
{
loglines.Append($"\n\nStatusCode: {(int)response.StatusCode}\n");
foreach (var h in response.Headers)
{
if (h.Key == "Set-Cookie")
{
foreach (string v in h.Value)
loglines.Append($"{h.Key}: {v}\n");
}
else
loglines.Append($"{h.Key}: {string.Join("", h.Value)}\n");
}
}
using (HttpContent content = response.Content)
{
if (encoding != default)
{
string res = encoding.GetString(await content.ReadAsByteArrayAsync(cts.Token).ConfigureAwait(false));
if (InvkEvent.IsHttpAsync())
await InvkEvent.HttpAsync(new EventHttpResponse(url, data, client, res, response, Startup.memoryCache));
if (string.IsNullOrWhiteSpace(res))
return (null, response);
if (loglines != null)
loglines.Append($"\n{res}");
if (statusCodeOK && response.StatusCode != HttpStatusCode.OK)
return (null, response);
return (res, response);
}
else
{
string res = await content.ReadAsStringAsync(cts.Token).ConfigureAwait(false);
if (InvkEvent.IsHttpAsync())
await InvkEvent.HttpAsync(new EventHttpResponse(url, data, client, res, response, Startup.memoryCache));
if (string.IsNullOrWhiteSpace(res))
return (null, response);
if (loglines != null)
loglines.Append($"\n{res}");
if (statusCodeOK && response.StatusCode != HttpStatusCode.OK)
return (null, response);
return (res, response);
}
}
}
}
}
catch (Exception ex)
{
if (loglines != null)
loglines.Append(ex.ToString());
if (InvkEvent.IsHttpAsync())
{
await InvkEvent.HttpAsync(new EventHttpResponse(url, data, null, ex.ToString(), new HttpResponseMessage()
{
StatusCode = HttpStatusCode.InternalServerError,
RequestMessage = new HttpRequestMessage()
}, Startup.memoryCache));
}
return (null, new HttpResponseMessage()
{
StatusCode = HttpStatusCode.InternalServerError,
RequestMessage = new HttpRequestMessage()
});
}
finally
{
if (!url.Contains("127.0.0.1") && loglines != null)
WriteLog(url, "POST", data.ReadAsStringAsync().Result, loglines);
StringBuilderPool.Return(loglines);
}
}
#endregion
#region Post<T>
public static Task<T> Post<T>(string url, string data, string cookie = null, int timeoutSeconds = 15, List<HeadersModel> headers = null, Encoding encoding = default, WebProxy proxy = null, bool IgnoreDeserializeObject = false, CookieContainer cookieContainer = null, bool useDefaultHeaders = true, int httpversion = 1, int MaxResponseContentBufferSize = 0, bool statusCodeOK = true)
{
return Post<T>(url, new StringContent(data, Encoding.UTF8, "application/x-www-form-urlencoded"),
cookie, timeoutSeconds, headers, encoding, proxy, IgnoreDeserializeObject, cookieContainer, useDefaultHeaders, httpversion, MaxResponseContentBufferSize, statusCodeOK
);
}
async public static Task<T> Post<T>(string url, HttpContent data, string cookie = null, int timeoutSeconds = 15, List<HeadersModel> headers = null, Encoding encoding = default, WebProxy proxy = null, bool IgnoreDeserializeObject = false, CookieContainer cookieContainer = null, bool useDefaultHeaders = true, int httpversion = 1, int MaxResponseContentBufferSize = 0, bool statusCodeOK = true)
{
var ms = PoolInvk.msm.GetStream();
try
{
T result = default;
var req = await BasePostReaderAsync(async e =>
{
try
{
await e.stream.CopyToAsync(ms, PoolInvk.bufferSize, e.ct);
ms.Position = 0;
var encdg = encoding != default ? encoding : Encoding.UTF8;
using (var streamReader = new StreamReader(ms, encdg, detectEncodingFromByteOrderMarks: false, bufferSize: PoolInvk.bufferSize, leaveOpen: true))
{
using (var jsonReader = new JsonTextReader(streamReader)
{
ArrayPool = NewtonsoftPool.Array
})
{
var serializer = IgnoreDeserializeObject
? _serializerIgnoreDeserialize.Value
: _serializerDefault.Value;
result = serializer.Deserialize<T>(jsonReader);
if (e.loglines != null)
e.loglines.Append($"\n{JsonConvert.SerializeObject(result, Formatting.Indented)}");
}
}
}
catch (Exception ex)
{
if (e.loglines != null)
e.loglines.Append($"\n{ex.Message}");
}
},
url, data, cookie, MaxResponseContentBufferSize, timeoutSeconds, headers, proxy, httpversion, cookieContainer, useDefaultHeaders, IgnoreDeserializeObject, statusCodeOK
).ConfigureAwait(false);
return result;
}
finally
{
ms.Dispose();
}
}
#endregion
#region BasePostReaderAsync
async public static Task<(bool success, HttpResponseMessage response)> BasePostReaderAsync(Action<(Stream stream, CancellationToken ct, StringBuilder loglines)> action, string url, HttpContent data, string cookie = null, int MaxResponseContentBufferSize = 0, int timeoutSeconds = 15, List<HeadersModel> headers = null, WebProxy proxy = null, int httpversion = 1, CookieContainer cookieContainer = null, bool useDefaultHeaders = true, bool IgnoreDeserializeObject = false, bool statusCodeOK = true)
{
var loglines = IsLogged
? StringBuilderPool.Rent()
: null;
try
{
var handler = Handler(url, proxy, loglines, cookieContainer);
var client = FrendlyHttp.MessageClient(httpversion == 1 ? "base" : $"http{httpversion}", handler, MaxResponseContentBufferSize);
if (cookieContainer != null && loglines != null)
{
var cookiesString = new StringBuilder(200);
foreach (Cookie c in cookieContainer.GetCookies(new Uri(url)))
cookiesString.Append($"{c.Name}={c.Value}; ");
if (cookiesString.Length > 0)
loglines.Append($"Cookie: {cookiesString.ToString().TrimEnd(' ', ';')}\n");
}
var req = new HttpRequestMessage(HttpMethod.Post, url)
{
Version = httpversion == 1 ? HttpVersion.Version11 : new Version(httpversion, 0),
Content = data
};
DefaultRequestHeaders(url, req, cookie, null, headers, loglines, useDefaultHeaders);
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(Math.Max(5, timeoutSeconds))))
{
using (HttpResponseMessage response = await client.SendAsync(req, cts.Token).ConfigureAwait(false))
{
if (loglines != null)
{
loglines.Append($"\n\nStatusCode: {(int)response.StatusCode}\n");
foreach (var h in response.Headers)
{
if (h.Key == "Set-Cookie")
{
foreach (string v in h.Value)
loglines.Append($"{h.Key}: {v}\n");
}
else
loglines.Append($"{h.Key}: {string.Join("", h.Value)}\n");
}
}
using (HttpContent content = response.Content)
{
if (InvkEvent.IsHttpAsync())
await InvkEvent.HttpAsync(new EventHttpResponse(url, data, client, "ReadAsStream", response, Startup.memoryCache));
if (statusCodeOK && response.StatusCode != HttpStatusCode.OK)
return (false, response);
using (var stream = await content.ReadAsStreamAsync(cts.Token).ConfigureAwait(false))
{
action.Invoke((stream, cts.Token, loglines));
return (true, response);
}
}
}
}
}
catch (Exception ex)
{
if (loglines != null)
loglines.Append(ex.ToString());
if (InvkEvent.IsHttpAsync())
{
await InvkEvent.HttpAsync(new EventHttpResponse(url, data, null, ex.ToString(), new HttpResponseMessage()
{
StatusCode = HttpStatusCode.InternalServerError,
RequestMessage = new HttpRequestMessage()
}, Startup.memoryCache));
}
return (false, new HttpResponseMessage()
{
StatusCode = HttpStatusCode.InternalServerError,
RequestMessage = new HttpRequestMessage()
});
}
finally
{
if (!url.Contains("127.0.0.1") && loglines != null)
WriteLog(url, "POST", data.ReadAsStringAsync().Result, loglines);
StringBuilderPool.Return(loglines);
}
}
#endregion
#region Download
async public static Task<byte[]> Download(string url, string cookie = null, string referer = null, int timeoutSeconds = 60, long MaxResponseContentBufferSize = 50_000_000, List<HeadersModel> headers = null, WebProxy proxy = null, bool statusCodeOK = true, bool useDefaultHeaders = true)
{
return (await BaseDownload(url, cookie, referer, timeoutSeconds, MaxResponseContentBufferSize, headers, proxy, statusCodeOK, useDefaultHeaders).ConfigureAwait(false)).array;
}
#endregion
#region BaseDownload
async public static Task<(byte[] array, HttpResponseMessage response)> BaseDownload(string url, string cookie = null, string referer = null, int timeoutSeconds = 60, long MaxResponseContentBufferSize = 50_000_000, List<HeadersModel> headers = null, WebProxy proxy = null, bool statusCodeOK = true, bool useDefaultHeaders = true)
{
try
{
var handler = Handler(url, proxy);
var client = FrendlyHttp.MessageClient("base", handler, MaxResponseContentBufferSize);
var req = new HttpRequestMessage(HttpMethod.Get, url)
{
Version = HttpVersion.Version11
};
DefaultRequestHeaders(url, req, cookie, referer, headers, useDefaultHeaders);
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(Math.Max(20, timeoutSeconds))))
{
using (HttpResponseMessage response = await client.SendAsync(req, cts.Token).ConfigureAwait(false))
{
if (statusCodeOK && response.StatusCode != HttpStatusCode.OK)
return (null, response);
using (HttpContent content = response.Content)
{
byte[] res = await content.ReadAsByteArrayAsync(cts.Token).ConfigureAwait(false);
if (res == null || res.Length == 0)
return (null, response);
return (res, response);
}
}
}
}
catch
{
return (null, new HttpResponseMessage()
{
StatusCode = HttpStatusCode.InternalServerError,
RequestMessage = new HttpRequestMessage()
});
}
}
#endregion
#region DownloadFile
async public static Task<bool> DownloadFile(string url, string path, int timeoutSeconds = 20, List<HeadersModel> headers = null, WebProxy proxy = null)
{
try
{
using (var handler = Handler(url, proxy))
{
using (var client = new HttpClient(handler))
{
client.Timeout = TimeSpan.FromSeconds(timeoutSeconds);
bool setDefaultUseragent = true;
if (headers != null)
{
foreach (var item in headers)
{
if (item.name.Equals("user-agent", StringComparison.OrdinalIgnoreCase))
setDefaultUseragent = false;
if (!client.DefaultRequestHeaders.Contains(item.name))
client.DefaultRequestHeaders.Add(item.name, item.val);
}
}
if (setDefaultUseragent)
client.DefaultRequestHeaders.Add("User-Agent", UserAgent);
using (var stream = await client.GetStreamAsync(url))
{
using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, PoolInvk.bufferSize))
{
await stream.CopyToAsync(fileStream, PoolInvk.bufferSize);
return true;
}
}
}
}
}
catch
{
return false;
}
}
#endregion
#region DownloadToStream
async public static Task<bool> DownloadToStream(Stream ms, string url, int timeoutSeconds = 20, List<HeadersModel> headers = null, WebProxy proxy = null)
{
try
{
using (var handler = Handler(url, proxy))
{
using (var client = new HttpClient(handler))
{
client.Timeout = TimeSpan.FromSeconds(timeoutSeconds);
bool setDefaultUseragent = true;
if (headers != null)
{
foreach (var item in headers)
{
if (item.name.Equals("user-agent", StringComparison.OrdinalIgnoreCase))
setDefaultUseragent = false;
if (!client.DefaultRequestHeaders.Contains(item.name))
client.DefaultRequestHeaders.Add(item.name, item.val);
}
}
if (setDefaultUseragent)
client.DefaultRequestHeaders.Add("User-Agent", UserAgent);
using (HttpResponseMessage response = await client.GetAsync(url).ConfigureAwait(false))
{
if (response.StatusCode != HttpStatusCode.OK)
return false;
using (HttpContent content = response.Content)
{
await content.CopyToAsync(ms);
ms.Position = 0;
return true;
}
}
}
}
}
catch
{
return false;
}
}
#endregion
#region IsLogSend
public static INws nws;
public static ISoks ws;
public static bool IsLogged
{
get
{
if (AppInit.conf.filelog)
return true;
if (!AppInit.conf.weblog.enable || onlog == null)
return false;
if (nws == null && ws == null)
return false;
if (nws?.CountWeblogClients > 0 || ws?.CountWeblogClients > 0)
return true;
return false;
}
}
#endregion
#region WriteLog
static FileStream logFileStream = null;
public static EventHandler<string> onlog = null;
static void WriteLog(string url, string method, in string postdata, StringBuilder result)
{
if (!IsLogged || result == null)
return;
var log = new StringBuilder((result.Length + (postdata?.Length ?? 0)) *2);
log.Append($"{DateTime.Now}\n{method}: {url}\n");
if (!string.IsNullOrEmpty(postdata))
log.Append($"{postdata}\n\n");
log.Append(result);
onlog?.Invoke(null, log.ToString());
if (!AppInit.conf.filelog)
return;
string dateLog = DateTime.Today.ToString("dd.MM.yy");
string patchlog = $"cache/logs/HttpClient_{dateLog}.log";
if (logFileStream == null || !File.Exists(patchlog))
logFileStream = new FileStream(patchlog, FileMode.Append, FileAccess.Write, FileShare.Read, PoolInvk.bufferSize);
var buffer = Encoding.UTF8.GetBytes($"\n\n\n################################################################\n\n{log.ToString()}");
logFileStream.Write(buffer, 0, buffer.Length);
logFileStream.Flush();
}
#endregion
}
}