-
Notifications
You must be signed in to change notification settings - Fork 59
feat:支持解压Gzip Content-Encoding格式的数据包 #142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| using System.IO; | ||
| using System.IO.Compression; | ||
| using Net; | ||
| using AquaMai.Config.Attributes; | ||
| using HarmonyLib; | ||
|
|
||
| namespace AquaMai.Mods.GameSystem; | ||
|
|
||
| [ConfigSection( | ||
| name: "更多Content-Encoding格式", | ||
| en: """ | ||
| Enables support for decompressing data encoded with formats other than deflate, such as gzip. | ||
| Useful when the server uses CDNs such as Cloudflare that do not support deflate. | ||
| """, | ||
| zh: """ | ||
| 开启后游戏将支持解压非deflate格式的数据包,比如Gzip; | ||
| 用于服务器使用Cloudflare等不支持deflate格式的CDN; | ||
| """, | ||
| defaultOn: false)] | ||
|
|
||
| public class MoreContentEncoding | ||
| { | ||
| private const int BufferSize = 1024; | ||
|
|
||
| [HarmonyPrefix] | ||
| [HarmonyPatch(typeof(NetHttpClient), "Decompress")] | ||
| public static bool PreDecompress(NetHttpClient __instance) | ||
| { | ||
| var traverse = Traverse.Create(__instance); | ||
| var temporaryStream = traverse.Field<MemoryStream>("_temporaryStream").Value; | ||
| var memoryStream = traverse.Field<MemoryStream>("_memoryStream").Value; | ||
| var buffer = traverse.Field<byte[]>("_buffer").Value; | ||
|
Comment on lines
+23
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue (bug_risk): CopyTo 使用固定的 BufferSize 而不是实际的缓冲区长度,如果底层缓冲区大小发生变化,就可能产生不匹配。
Original comment in Englishissue (bug_risk): CopyTo uses a fixed BufferSize instead of the actual buffer length, which can cause mismatches if the underlying buffer size changes.
|
||
|
|
||
| memoryStream.SetLength(0L); | ||
| if (temporaryStream.Length == 0L) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| var raw = temporaryStream.ToArray(); | ||
|
|
||
| // - 0x1F 0x8B -> gzip | ||
| // - 0x78 ?? + valid zlib -> zlib (the stock format: zlib header + raw deflate + adler32) | ||
| // - otherwise -> treat as plaintext | ||
| if (raw.Length >= 2 && raw[0] == 0x1F && raw[1] == 0x8B) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: gzip 解压分支没有 try/catch,而 zlib 分支有。由于该 prefix 完全替换了 Prompt for AI agents |
||
| { | ||
| using var gz = new GZipStream(new MemoryStream(raw, writable: false), CompressionMode.Decompress); | ||
| CopyTo(gz, memoryStream, buffer); | ||
| } | ||
| else if (raw.Length >= 6 && raw[0] == 0x78 && TryInflateZlib(raw, memoryStream, buffer)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: 使用非默认窗口大小的合法 zlib 响应不会被解压。不要只匹配 Prompt for AI agents |
||
| { | ||
| // zlib 成功解压( | ||
| } | ||
| else | ||
| { | ||
| memoryStream.Write(raw, 0, raw.Length); | ||
| } | ||
|
|
||
| memoryStream.Seek(0L, SeekOrigin.Begin); | ||
| temporaryStream.Seek(0L, SeekOrigin.Begin); | ||
| temporaryStream.SetLength(0L); | ||
| return false; | ||
| } | ||
|
|
||
| private static bool TryInflateZlib(byte[] raw, MemoryStream output, byte[] buffer) | ||
| { | ||
| var startLength = output.Length; | ||
| try | ||
| { | ||
| // 跳过 2 字节的 zlib 头部,忽略末尾的 4 字节 Adler32 校验和。 | ||
| using var input = new MemoryStream(raw, 2, raw.Length - 6, writable: false); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: 该分支会接受 Prompt for AI agents |
||
| using var deflate = new DeflateStream(input, CompressionMode.Decompress); | ||
| CopyTo(deflate, output, buffer); | ||
| return true; | ||
| } | ||
| catch | ||
| { | ||
| output.SetLength(startLength); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| private static void CopyTo(Stream from, Stream to, byte[] buffer) | ||
| { | ||
| while (true) | ||
| { | ||
| var count = from.Read(buffer, 0, BufferSize); | ||
| if (count <= 0) break; | ||
| to.Write(buffer, 0, count); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2:
BufferSize固定为 1024,但读取目标_buffer是游戏内部字段,其长度未知。若_buffer.Length < 1024,CopyTo中的Read(buffer, 0, 1024)会抛ArgumentOutOfRangeException。建议按_buffer.Length读取(如Math.Min(BufferSize, buffer.Length)),或直接使用Math.Min保证不超过缓冲区长度。Prompt for AI agents