mirror of
https://github.com/BeyondDimension/SteamTools.git
synced 2026-10-17 05:30:48 +08:00
Merge branch 'develop' of https://github.com/BeyondDimension/SteamTools into develop
This commit is contained in:
+118
@@ -90,4 +90,122 @@ partial class HttpReverseProxyMiddleware
|
||||
notfound: insertPosition = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool FindScriptInjectInsertPositionForGithub(byte[] buffer_, Encoding encoding, out ReadOnlyMemory<byte> buffer, out int insertPosition)
|
||||
{
|
||||
buffer = buffer_.AsMemory();
|
||||
|
||||
ReadOnlySpan<byte> mark = "<script"u8;
|
||||
var lastScriptWithSrcStart = -1;
|
||||
var span = buffer_.AsSpan();
|
||||
|
||||
if (span.Length >= mark.Length)
|
||||
{
|
||||
for (var i = 0; i <= span.Length - mark.Length; i++)
|
||||
{
|
||||
if (!EqualsAsciiIgnoreCase(span.Slice(i, mark.Length), mark))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var afterMarkIndex = i + mark.Length;
|
||||
if (afterMarkIndex < span.Length && IsHtmlAttributeNameChar(span[afterMarkIndex]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var tagEndOffset = span.Slice(afterMarkIndex).IndexOf((byte)'>');
|
||||
if (tagEndOffset < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var tagEndIndex = afterMarkIndex + tagEndOffset;
|
||||
var scriptTag = span.Slice(i, tagEndIndex - i + 1);
|
||||
if (ScriptTagHasSrcAttribute(scriptTag))
|
||||
{
|
||||
lastScriptWithSrcStart = i;
|
||||
}
|
||||
|
||||
i = tagEndIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastScriptWithSrcStart >= 0)
|
||||
{
|
||||
insertPosition = lastScriptWithSrcStart;
|
||||
return true;
|
||||
}
|
||||
|
||||
return FindScriptInjectInsertPosition(buffer_, encoding, out buffer, out insertPosition);
|
||||
}
|
||||
|
||||
static bool ScriptTagHasSrcAttribute(ReadOnlySpan<byte> scriptTag)
|
||||
{
|
||||
ReadOnlySpan<byte> src = "src"u8;
|
||||
|
||||
if (scriptTag.Length < src.Length)
|
||||
return false;
|
||||
|
||||
for (var i = 0; i <= scriptTag.Length - src.Length; i++)
|
||||
{
|
||||
if (!EqualsAsciiIgnoreCase(scriptTag.Slice(i, src.Length), src))
|
||||
continue;
|
||||
|
||||
if (i > 0 && IsHtmlAttributeNameChar(scriptTag[i - 1]))
|
||||
continue;
|
||||
|
||||
var j = i + src.Length;
|
||||
while (j < scriptTag.Length && IsAsciiWhitespace(scriptTag[j]))
|
||||
{
|
||||
j++;
|
||||
}
|
||||
|
||||
if (j < scriptTag.Length && scriptTag[j] == (byte)'=')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool EqualsAsciiIgnoreCase(ReadOnlySpan<byte> left, ReadOnlySpan<byte> right)
|
||||
{
|
||||
if (left.Length != right.Length)
|
||||
return false;
|
||||
|
||||
for (var i = 0; i < left.Length; i++)
|
||||
{
|
||||
var l = ToUpperAscii(left[i]);
|
||||
var r = ToUpperAscii(right[i]);
|
||||
if (l != r)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static byte ToUpperAscii(byte value)
|
||||
{
|
||||
if (value is >= (byte)'a' and <= (byte)'z')
|
||||
return (byte)(value - 32);
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool IsAsciiWhitespace(byte value) =>
|
||||
value == (byte)' ' ||
|
||||
value == (byte)'\t' ||
|
||||
value == (byte)'\r' ||
|
||||
value == (byte)'\n' ||
|
||||
value == (byte)'\f';
|
||||
|
||||
static bool IsHtmlAttributeNameChar(byte value) =>
|
||||
(value is >= (byte)'a' and <= (byte)'z') ||
|
||||
(value is >= (byte)'A' and <= (byte)'Z') ||
|
||||
(value is >= (byte)'0' and <= (byte)'9') ||
|
||||
value == (byte)'-' ||
|
||||
value == (byte)'_' ||
|
||||
value == (byte)':' ||
|
||||
value == (byte)'.';
|
||||
}
|
||||
+15
-1
@@ -327,7 +327,12 @@ Actual value was {actualValue}.
|
||||
}
|
||||
}
|
||||
|
||||
if (FindScriptInjectInsertPosition(buffer_, encoding, out var buffer, out var position))
|
||||
var isGithubHost = IsGithubHost(context.Request.Host.Host);
|
||||
var isFindPosition = isGithubHost
|
||||
? FindScriptInjectInsertPositionForGithub(buffer_, encoding, out var buffer, out var position)
|
||||
: FindScriptInjectInsertPosition(buffer_, encoding, out buffer, out position);
|
||||
|
||||
if (isFindPosition)
|
||||
{
|
||||
using var bodyWriter = new MemoryStream();
|
||||
using Stream? bodyCompress = GetStreamByContentCompression(bodyWriter, contentCompression, CompressionMode.Compress, true);
|
||||
@@ -398,6 +403,15 @@ Actual value was {actualValue}.
|
||||
context.Response.Body = originalBody;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsGithubHost(string? host)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(host))
|
||||
return false;
|
||||
|
||||
return host.Equals("github.com", StringComparison.OrdinalIgnoreCase) ||
|
||||
host.EndsWith(".github.com", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
static Stream? GetStreamByContentCompression(Stream stream, string contentCompression, CompressionMode mode, bool leaveOpen) => contentCompression switch
|
||||
|
||||
@@ -46,4 +46,55 @@ public sealed class HttpReverseProxyMiddlewareUnitTest
|
||||
var new_html = encoding.GetString(s.ToArray());
|
||||
TestContext.WriteLine(new_html);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFindScriptInjectInsertPositionForGithub_BeforeLastScript()
|
||||
{
|
||||
var html = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="/first.js"></script>
|
||||
<script src="/runtime.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
|
||||
var buffer = Encoding.UTF8.GetBytes(html);
|
||||
var ok = HttpReverseProxyMiddleware.FindScriptInjectInsertPositionForGithub(buffer, Encoding.UTF8, out _, out var position);
|
||||
|
||||
Assert.That(ok, Is.True);
|
||||
var expected = html.LastIndexOf("<script src=\"/runtime.js\">", StringComparison.OrdinalIgnoreCase);
|
||||
Assert.That(position, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFindScriptInjectInsertPositionForGithub_BeforeLastScriptWithSrc()
|
||||
{
|
||||
var html = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<script src="/first.js"></script>
|
||||
<script>window.__INLINE__ = true;</script>
|
||||
<script src="/runtime.js" data-rspack="@github-ui/github-ui:runtime"></script>
|
||||
<script>window.__AFTER_RUNTIME__ = true;</script>
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
|
||||
var buffer = Encoding.UTF8.GetBytes(html);
|
||||
var ok = HttpReverseProxyMiddleware.FindScriptInjectInsertPositionForGithub(buffer, Encoding.UTF8, out _, out var position);
|
||||
|
||||
Assert.That(ok, Is.True);
|
||||
var expected = html.LastIndexOf("<script src=\"/runtime.js\"", StringComparison.OrdinalIgnoreCase);
|
||||
Assert.That(position, Is.EqualTo(expected));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user