Skip to content

Commit

Permalink
Some HTTP utils
Browse files Browse the repository at this point in the history
  • Loading branch information
TheArcaneBrony committed Jul 29, 2024
1 parent f09a666 commit 26b02bc
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 1 deletion.
105 changes: 104 additions & 1 deletion ArcaneLibs/Extensions/HttpExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,114 @@
using System.Reflection;
using System.Text;

namespace ArcaneLibs.Extensions;

public static class HttpExtensions {
private static readonly string[] SensitiveHttpHeaders = [
"Authorization"
];

public static void ResetSendStatus(this HttpRequestMessage request) {
typeof(HttpRequestMessage).GetField("_sendStatus", BindingFlags.NonPublic | BindingFlags.Instance)
?.SetValue(request, 0);
}


public static long GetContentLength(this HttpRequestMessage request) {
if (request.Content == null) return 0;
if (request.Content.Headers.ContentLength.HasValue) return request.Content.Headers.ContentLength.Value;
return request.Content.ReadAsStream().Length;
// return -1;
}

public static long GetContentLength(this HttpResponseMessage response) {
if (response.Content == null) return 0;
if (response.Content.Headers.ContentLength.HasValue) return response.Content.Headers.ContentLength.Value;
if (response.Content is StreamContent streamContent) return streamContent.ReadAsStream().Length;
return -1;
}

public static string Summarise(this HttpRequestMessage request, bool includeQuery = true, bool includeHeaders = false, bool includeSensitiveHeaders = false,
bool includeContentIfText = false) {
if(request.RequestUri == null) throw new NullReferenceException("RequestUri is null");
var uri = request.RequestUri;

var sb = new StringBuilder();

// "HttpRequest<StreamContent>(123456): "
sb.Append("HttpRequest");
if (request.Content is not null) sb.Append($"<{request.Content.GetType()}>");
sb.Append($"({request.GetHashCode()})");
sb.Append(": ");

// "GET https://example.com", includeQuery? ++ "?query=string"
sb.Append($"{request.Method} {uri.FormatParts(includeQuery: includeQuery)}");

// "(123 B)"
if (request.Content != null) {
var contentLength = request.GetContentLength();
if (contentLength > 0) sb.Append($"({contentLength}");
}

// "Accept: text/html, text/plain"
// "Content-Type: application/json"
if (includeHeaders) {
foreach (var header in request.Headers) {
if (!includeSensitiveHeaders && SensitiveHttpHeaders.Contains(header.Key)) continue;
sb.Append($"\n{header.Key}: {string.Join(", ", header.Value)}");
}
}

// "<data>"
if (includeContentIfText && request.Content != null) {
var content = request.Content.ReadAsStringAsync().Result;
if (!string.IsNullOrEmpty(content)) sb.Append($"\n{content}");
}

return sb.ToString();
}

public static string Summarise(this HttpResponseMessage response, bool includeHeaders = false, bool includeSensitiveHeaders = false, bool includeContentIfText = false, string[]? hideHeaders = null) {
if(response.RequestMessage == null) throw new NullReferenceException("RequestMessage is null");
var request = response.RequestMessage;
var uri = request.RequestUri;

var sb = new StringBuilder();

// "HttpResponse<StreamContent>(123456): "
sb.Append("HttpResponse");
if (response.Content is not null) sb.Append($"<{response.Content.GetType()}>");
sb.Append($"({response.GetHashCode()})");
sb.Append(": ");

// "GET https://example.com", includeQuery? ++ "?query=string"
sb.Append($"{request.Method} {uri.Scheme}://{uri.Host}{uri.AbsolutePath}");

Check warning on line 84 in ArcaneLibs/Extensions/HttpExtensions.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check warning on line 84 in ArcaneLibs/Extensions/HttpExtensions.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check warning on line 84 in ArcaneLibs/Extensions/HttpExtensions.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.
if (!string.IsNullOrEmpty(request.RequestUri.Query)) sb.Append(request.RequestUri.Query);

Check warning on line 85 in ArcaneLibs/Extensions/HttpExtensions.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check warning on line 85 in ArcaneLibs/Extensions/HttpExtensions.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check warning on line 85 in ArcaneLibs/Extensions/HttpExtensions.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

// "(123 B)"
if (response.Content != null) {
var contentLength = response.GetContentLength();
if (contentLength > 0) sb.Append($" ({Util.BytesToString(contentLength)})");
else sb.Append(" (stream)");
}

// "200 OK"
sb.Append($" {(int) response.StatusCode} {response.ReasonPhrase}");

// "Content-Type: application/json"
if (includeHeaders) {
foreach (var header in response.Headers) {
if (!includeSensitiveHeaders && SensitiveHttpHeaders.Contains(header.Key)) continue;
if (hideHeaders != null && hideHeaders.Contains(header.Key)) continue;
sb.Append($"\n{header.Key}: {string.Join(", ", header.Value)}");
}
}

// "<data>"
if (includeContentIfText && response.Content != null) {
var content = response.Content.ReadAsStringAsync().Result;
if (!string.IsNullOrEmpty(content)) sb.Append($"\n{content}");
}

return sb.ToString();
}
}
19 changes: 19 additions & 0 deletions ArcaneLibs/Extensions/UriExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Text;
using System.Web;

namespace ArcaneLibs.Extensions;
Expand All @@ -11,4 +12,22 @@ public static Uri AddQuery(this Uri uri, string name, string value) {
// Console.WriteLine("OriginalString: " + uri.OriginalString);
return new Uri(location + "?" + newQuery, uri.IsAbsoluteUri ? UriKind.Absolute : UriKind.Relative);
}

public static Uri EnsureAbsolute(this Uri uri, Uri baseUri) {
if (uri.IsAbsoluteUri) {
if(baseUri is not null && !uri.OriginalString.StartsWith(baseUri.OriginalString)) {
throw new ArgumentException("Uri is not a child of the baseUri");
}
return uri;
}
return new Uri(baseUri, uri);
}

public static string FormatParts(this Uri uri, bool includeQuery = true, bool includeFragment = true) {
var sb = new StringBuilder();
sb.Append(uri.Scheme).Append("://").Append(uri.Host).Append(uri.AbsolutePath);
if (includeQuery && !string.IsNullOrEmpty(uri.Query)) sb.Append(uri.Query);
if (includeFragment && !string.IsNullOrEmpty(uri.Fragment)) sb.Append(uri.Fragment);
return sb.ToString();
}
}
29 changes: 29 additions & 0 deletions ArcaneLibs/Util.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Collections;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using ArcaneLibs.Extensions;

namespace ArcaneLibs;

Expand Down Expand Up @@ -176,4 +178,31 @@ public static string SI_BytesToString(long byteCount, int maxnums = 2) {
var num = Math.Round(bytes / Math.Pow(1000, place), maxnums);
return (Math.Sign(byteCount) * num) + " " + suf[place];
}

public static string ExpandPath(string? path, bool retry = true)
{
if (path is null) throw new ArgumentNullException(nameof(path));
// _logger.LogInformation("Expanding path `{}`", path);
Console.WriteLine("Expanding path '{0}'", path);

if (path.StartsWith('~'))
{
path = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), path[1..]);
}

Environment.GetEnvironmentVariables().Cast<DictionaryEntry>().OrderByDescending(x => x.Key.ToString()!.Length).ToList()
.ForEach(x => { path = path.Replace($"${x.Key}", x.Value.ToString()); });

Check warning on line 194 in ArcaneLibs/Util.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check warning on line 194 in ArcaneLibs/Util.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check warning on line 194 in ArcaneLibs/Util.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

// _logger.LogInformation("Expanded path to `{}`", path);
Console.WriteLine("Expanded path to '{0}'", path);
var tries = 0;
while (retry && path.ContainsAnyOf("~$".Split()))
{
if (tries++ > 100)
throw new Exception($"Path `{path}` contains unrecognised environment variables");
path = ExpandPath(path, false);
}

return path;
}
}

0 comments on commit 26b02bc

Please sign in to comment.