mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-18 09:26:42 +08:00
212 lines
6.7 KiB
C#
212 lines
6.7 KiB
C#
//------------------------------------------------------------------------------
|
||
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||
// Github源代码仓库:https://github.com/RRQM
|
||
// API首页:https://touchsocket.net/
|
||
// 交流QQ群:234762506
|
||
// 感谢您的下载和使用
|
||
//------------------------------------------------------------------------------
|
||
|
||
using System.Runtime.CompilerServices;
|
||
|
||
namespace TouchSocket.Http;
|
||
|
||
static class TouchSocketHttpUtility
|
||
{
|
||
public const int MaxReadSize = 1024 * 1024;
|
||
|
||
public const byte COLON = (byte)':';
|
||
public const byte SPACE = (byte)' ';
|
||
public const byte TAB = (byte)'\t';
|
||
|
||
public static ReadOnlySpan<byte> CRLF => "\r\n"u8;
|
||
public static ReadOnlySpan<byte> CRLFCRLF => "\r\n\r\n"u8;
|
||
|
||
private static readonly byte[] s_http11Response = "HTTP/1.1 "u8.ToArray();
|
||
private static readonly byte[] s_http10Response = "HTTP/1.0 "u8.ToArray();
|
||
|
||
private static readonly string[] s_statusCodeCache = new string[600];
|
||
private static readonly byte[][] s_statusCodeBytesCache = new byte[600][];
|
||
|
||
static TouchSocketHttpUtility()
|
||
{
|
||
for (var i = 0; i < 600; i++)
|
||
{
|
||
s_statusCodeCache[i] = i.ToString();
|
||
s_statusCodeBytesCache[i] = Encoding.UTF8.GetBytes(s_statusCodeCache[i]);
|
||
}
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
internal static ReadOnlySpan<byte> GetStatusCodeBytes(int statusCode)
|
||
{
|
||
if (statusCode >= 0 && statusCode < 600)
|
||
{
|
||
return s_statusCodeBytesCache[statusCode];
|
||
}
|
||
return Encoding.UTF8.GetBytes(statusCode.ToString());
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
internal static ReadOnlySpan<byte> GetHttpVersionBytes(string version)
|
||
{
|
||
if (version == "1.1")
|
||
{
|
||
return s_http11Response.AsSpan(0, 8);
|
||
}
|
||
if (version == "1.0")
|
||
{
|
||
return s_http10Response.AsSpan(0, 8);
|
||
}
|
||
return default;
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public static void AppendAnd<TWriter>(ref TWriter writer) where TWriter : IBytesWriter
|
||
{
|
||
writer.Write("&"u8);
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public static void AppendColon<TWriter>(ref TWriter writer) where TWriter : IBytesWriter
|
||
{
|
||
writer.Write(":"u8);
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public static void AppendEqual<TWriter>(ref TWriter writer) where TWriter : IBytesWriter
|
||
{
|
||
writer.Write("="u8);
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public static void AppendHTTP<TWriter>(ref TWriter writer) where TWriter : IBytesWriter
|
||
{
|
||
writer.Write("HTTP"u8);
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public static void AppendQuestionMark<TWriter>(ref TWriter writer) where TWriter : IBytesWriter
|
||
{
|
||
writer.Write("?"u8);
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public static void AppendRn<TWriter>(ref TWriter writer) where TWriter : IBytesWriter
|
||
{
|
||
writer.Write(CRLF);
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public static void AppendSlash<TWriter>(ref TWriter writer) where TWriter : IBytesWriter
|
||
{
|
||
writer.Write("/"u8);
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public static void AppendSpace<TWriter>(ref TWriter writer) where TWriter : IBytesWriter
|
||
{
|
||
writer.Write(StringExtension.DefaultSpaceUtf8Span);
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public static void AppendUtf8String<TWriter>(ref TWriter writer, string value) where TWriter : IBytesWriter
|
||
{
|
||
WriterExtension.WriteNormalString(ref writer, value, Encoding.UTF8);
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public static void AppendHex<TWriter>(ref TWriter writer, int value) where TWriter : IBytesWriter
|
||
{
|
||
AppendUtf8String(ref writer, $"{value:X}");
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
internal static bool IsWhitespace(byte b) => b == SPACE || b == TAB;
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
internal static ReadOnlySpan<byte> TrimWhitespace(ReadOnlySpan<byte> span)
|
||
{
|
||
var start = 0;
|
||
var end = span.Length - 1;
|
||
|
||
while (start <= end && IsWhitespace(span[start]))
|
||
{
|
||
start++;
|
||
}
|
||
|
||
while (end >= start && IsWhitespace(span[end]))
|
||
{
|
||
end--;
|
||
}
|
||
return start > end ? [] : span[start..(end + 1)];
|
||
}
|
||
|
||
internal static string UnescapeDataString(ReadOnlySpan<byte> urlSpan)
|
||
{
|
||
#if NET9_0_OR_GREATER
|
||
Span<char> charBuffer = stackalloc char[urlSpan.Length];
|
||
var charCount = Encoding.UTF8.GetChars(urlSpan, charBuffer);
|
||
return Uri.UnescapeDataString(charBuffer.Slice(0, charCount));
|
||
#else
|
||
return Uri.UnescapeDataString(urlSpan.ToString(Encoding.UTF8));
|
||
#endif
|
||
}
|
||
|
||
internal static string UnescapeDataString(ReadOnlySpan<char> urlSpan)
|
||
{
|
||
#if NET9_0_OR_GREATER
|
||
return Uri.UnescapeDataString(urlSpan);
|
||
#else
|
||
return Uri.UnescapeDataString(urlSpan.ToString());
|
||
#endif
|
||
}
|
||
|
||
internal static int FindNextWhitespace(ReadOnlySpan<byte> span, int start)
|
||
{
|
||
for (var i = start; i < span.Length; i++)
|
||
{
|
||
if (TouchSocketHttpUtility.IsWhitespace(span[i]))
|
||
{
|
||
return i;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
internal static int SkipSpaces(ReadOnlySpan<byte> span, int start)
|
||
{
|
||
while (start < span.Length && TouchSocketHttpUtility.IsWhitespace(span[start]))
|
||
{
|
||
start++;
|
||
}
|
||
return start;
|
||
}
|
||
|
||
internal static void ProcessKeyValuePair(ReadOnlySpan<char> kvSpan, InternalHttpParams parameters)
|
||
{
|
||
var eqIndex = kvSpan.IndexOf('=');
|
||
ReadOnlySpan<char> keySpan, valueSpan;
|
||
|
||
if (eqIndex >= 0)
|
||
{
|
||
keySpan = kvSpan.Slice(0, eqIndex);
|
||
valueSpan = kvSpan.Slice(eqIndex + 1);
|
||
}
|
||
else
|
||
{
|
||
keySpan = kvSpan;
|
||
valueSpan = [];
|
||
}
|
||
|
||
if (!keySpan.IsEmpty)
|
||
{
|
||
var key = TouchSocketHttpUtility.UnescapeDataString(keySpan);
|
||
var value = TouchSocketHttpUtility.UnescapeDataString(valueSpan);
|
||
parameters.Add(key, value);
|
||
}
|
||
}
|
||
} |