Pre-encode known Json values in SignalR (#9999)
This commit is contained in:
parent
1b47f44876
commit
f30e738848
|
|
@ -13,22 +13,22 @@ namespace Microsoft.AspNetCore.Http.Connections
|
|||
{
|
||||
public static class NegotiateProtocol
|
||||
{
|
||||
// Use C#7.3's ReadOnlySpan<byte> optimization for static data https://vcsjones.com/2019/02/01/csharp-readonly-span-bytes-static/
|
||||
private const string ConnectionIdPropertyName = "connectionId";
|
||||
private static ReadOnlySpan<byte> ConnectionIdPropertyNameBytes => new byte[] { (byte)'c', (byte)'o', (byte)'n', (byte)'n', (byte)'e', (byte)'c', (byte)'t', (byte)'i', (byte)'o', (byte)'n', (byte)'I', (byte)'d' };
|
||||
private static JsonEncodedText ConnectionIdPropertyNameBytes = JsonEncodedText.Encode(ConnectionIdPropertyName);
|
||||
private const string UrlPropertyName = "url";
|
||||
private static ReadOnlySpan<byte> UrlPropertyNameBytes => new byte[] { (byte)'u', (byte)'r', (byte)'l' };
|
||||
private static JsonEncodedText UrlPropertyNameBytes = JsonEncodedText.Encode(UrlPropertyName);
|
||||
private const string AccessTokenPropertyName = "accessToken";
|
||||
private static ReadOnlySpan<byte> AccessTokenPropertyNameBytes => new byte[] { (byte)'a', (byte)'c', (byte)'c', (byte)'e', (byte)'s', (byte)'s', (byte)'T', (byte)'o', (byte)'k', (byte)'e', (byte)'n' };
|
||||
private static JsonEncodedText AccessTokenPropertyNameBytes = JsonEncodedText.Encode(AccessTokenPropertyName);
|
||||
private const string AvailableTransportsPropertyName = "availableTransports";
|
||||
private static ReadOnlySpan<byte> AvailableTransportsPropertyNameBytes => new byte[] { (byte)'a', (byte)'v', (byte)'a', (byte)'i', (byte)'l', (byte)'a', (byte)'b', (byte)'l', (byte)'e', (byte)'T', (byte)'r', (byte)'a', (byte)'n', (byte)'s', (byte)'p', (byte)'o', (byte)'r', (byte)'t', (byte)'s' };
|
||||
private static JsonEncodedText AvailableTransportsPropertyNameBytes = JsonEncodedText.Encode(AvailableTransportsPropertyName);
|
||||
private const string TransportPropertyName = "transport";
|
||||
private static ReadOnlySpan<byte> TransportPropertyNameBytes => new byte[] { (byte)'t', (byte)'r', (byte)'a', (byte)'n', (byte)'s', (byte)'p', (byte)'o', (byte)'r', (byte)'t' };
|
||||
private static JsonEncodedText TransportPropertyNameBytes = JsonEncodedText.Encode(TransportPropertyName);
|
||||
private const string TransferFormatsPropertyName = "transferFormats";
|
||||
private static ReadOnlySpan<byte> TransferFormatsPropertyNameBytes => new byte[] { (byte)'t', (byte)'r', (byte)'a', (byte)'n', (byte)'s', (byte)'f', (byte)'e', (byte)'r', (byte)'F', (byte)'o', (byte)'r', (byte)'m', (byte)'a', (byte)'t', (byte)'s' };
|
||||
private static JsonEncodedText TransferFormatsPropertyNameBytes = JsonEncodedText.Encode(TransferFormatsPropertyName);
|
||||
private const string ErrorPropertyName = "error";
|
||||
private static ReadOnlySpan<byte> ErrorPropertyNameBytes => new byte[] { (byte)'e', (byte)'r', (byte)'r', (byte)'o', (byte)'r' };
|
||||
private static JsonEncodedText ErrorPropertyNameBytes = JsonEncodedText.Encode(ErrorPropertyName);
|
||||
|
||||
// Use C#7.3's ReadOnlySpan<byte> optimization for static data https://vcsjones.com/2019/02/01/csharp-readonly-span-bytes-static/
|
||||
// Used to detect ASP.NET SignalR Server connection attempt
|
||||
private static ReadOnlySpan<byte> ProtocolVersionPropertyNameBytes => new byte[] { (byte)'P', (byte)'r', (byte)'o', (byte)'t', (byte)'o', (byte)'c', (byte)'o', (byte)'l', (byte)'V', (byte)'e', (byte)'r', (byte)'s', (byte)'i', (byte)'o', (byte)'n' };
|
||||
|
||||
|
|
@ -120,19 +120,19 @@ namespace Microsoft.AspNetCore.Http.Connections
|
|||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonTokenType.PropertyName:
|
||||
if (reader.TextEquals(UrlPropertyNameBytes))
|
||||
if (reader.TextEquals(UrlPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
url = reader.ReadAsString(UrlPropertyName);
|
||||
}
|
||||
else if (reader.TextEquals(AccessTokenPropertyNameBytes))
|
||||
else if (reader.TextEquals(AccessTokenPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
accessToken = reader.ReadAsString(AccessTokenPropertyName);
|
||||
}
|
||||
else if (reader.TextEquals(ConnectionIdPropertyNameBytes))
|
||||
else if (reader.TextEquals(ConnectionIdPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
connectionId = reader.ReadAsString(ConnectionIdPropertyName);
|
||||
}
|
||||
else if (reader.TextEquals(AvailableTransportsPropertyNameBytes))
|
||||
else if (reader.TextEquals(AvailableTransportsPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
reader.CheckRead();
|
||||
reader.EnsureArrayStart();
|
||||
|
|
@ -150,7 +150,7 @@ namespace Microsoft.AspNetCore.Http.Connections
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (reader.TextEquals(ErrorPropertyNameBytes))
|
||||
else if (reader.TextEquals(ErrorPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
error = reader.ReadAsString(ErrorPropertyName);
|
||||
}
|
||||
|
|
@ -221,11 +221,11 @@ namespace Microsoft.AspNetCore.Http.Connections
|
|||
case JsonTokenType.PropertyName:
|
||||
var memberName = reader.ValueSpan;
|
||||
|
||||
if (memberName.SequenceEqual(TransportPropertyNameBytes))
|
||||
if (memberName.SequenceEqual(TransportPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
availableTransport.Transport = reader.ReadAsString(TransportPropertyName);
|
||||
}
|
||||
else if (memberName.SequenceEqual(TransferFormatsPropertyNameBytes))
|
||||
else if (memberName.SequenceEqual(TransferFormatsPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
reader.CheckRead();
|
||||
reader.EnsureArrayStart();
|
||||
|
|
|
|||
|
|
@ -20,25 +20,24 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
/// </summary>
|
||||
public sealed class JsonHubProtocol : IHubProtocol
|
||||
{
|
||||
// Use C#7.3's ReadOnlySpan<byte> optimization for static data https://vcsjones.com/2019/02/01/csharp-readonly-span-bytes-static/
|
||||
private const string ResultPropertyName = "result";
|
||||
private static ReadOnlySpan<byte> ResultPropertyNameBytes => new byte[] { (byte)'r', (byte)'e', (byte)'s', (byte)'u', (byte)'l', (byte)'t' };
|
||||
private static JsonEncodedText ResultPropertyNameBytes = JsonEncodedText.Encode(ResultPropertyName);
|
||||
private const string ItemPropertyName = "item";
|
||||
private static ReadOnlySpan<byte> ItemPropertyNameBytes => new byte[] { (byte)'i', (byte)'t', (byte)'e', (byte)'m' };
|
||||
private static JsonEncodedText ItemPropertyNameBytes = JsonEncodedText.Encode(ItemPropertyName);
|
||||
private const string InvocationIdPropertyName = "invocationId";
|
||||
private static ReadOnlySpan<byte> InvocationIdPropertyNameBytes => new byte[] { (byte)'i', (byte)'n', (byte)'v', (byte)'o', (byte)'c', (byte)'a', (byte)'t', (byte)'i', (byte)'o', (byte)'n', (byte)'I', (byte)'d' };
|
||||
private static JsonEncodedText InvocationIdPropertyNameBytes = JsonEncodedText.Encode(InvocationIdPropertyName);
|
||||
private const string StreamIdsPropertyName = "streamIds";
|
||||
private static ReadOnlySpan<byte> StreamIdsPropertyNameBytes => new byte[] { (byte)'s', (byte)'t', (byte)'r', (byte)'e', (byte)'a', (byte)'m', (byte)'I', (byte)'d', (byte)'s' };
|
||||
private static JsonEncodedText StreamIdsPropertyNameBytes = JsonEncodedText.Encode(StreamIdsPropertyName);
|
||||
private const string TypePropertyName = "type";
|
||||
private static ReadOnlySpan<byte> TypePropertyNameBytes => new byte[] { (byte)'t', (byte)'y', (byte)'p', (byte)'e' };
|
||||
private static JsonEncodedText TypePropertyNameBytes = JsonEncodedText.Encode(TypePropertyName);
|
||||
private const string ErrorPropertyName = "error";
|
||||
private static ReadOnlySpan<byte> ErrorPropertyNameBytes => new byte[] { (byte)'e', (byte)'r', (byte)'r', (byte)'o', (byte)'r' };
|
||||
private static JsonEncodedText ErrorPropertyNameBytes = JsonEncodedText.Encode(ErrorPropertyName);
|
||||
private const string TargetPropertyName = "target";
|
||||
private static ReadOnlySpan<byte> TargetPropertyNameBytes => new byte[] { (byte)'t', (byte)'a', (byte)'r', (byte)'g', (byte)'e', (byte)'t' };
|
||||
private static JsonEncodedText TargetPropertyNameBytes = JsonEncodedText.Encode(TargetPropertyName);
|
||||
private const string ArgumentsPropertyName = "arguments";
|
||||
private static ReadOnlySpan<byte> ArgumentsPropertyNameBytes => new byte[] { (byte)'a', (byte)'r', (byte)'g', (byte)'u', (byte)'m', (byte)'e', (byte)'n', (byte)'t', (byte)'s' };
|
||||
private static JsonEncodedText ArgumentsPropertyNameBytes = JsonEncodedText.Encode(ArgumentsPropertyName);
|
||||
private const string HeadersPropertyName = "headers";
|
||||
private static ReadOnlySpan<byte> HeadersPropertyNameBytes => new byte[] { (byte)'h', (byte)'e', (byte)'a', (byte)'d', (byte)'e', (byte)'r', (byte)'s' };
|
||||
private static JsonEncodedText HeadersPropertyNameBytes = JsonEncodedText.Encode(HeadersPropertyName);
|
||||
|
||||
private static readonly string ProtocolName = "json";
|
||||
private static readonly int ProtocolVersion = 1;
|
||||
|
|
@ -144,7 +143,7 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonTokenType.PropertyName:
|
||||
if (reader.TextEquals(TypePropertyNameBytes))
|
||||
if (reader.TextEquals(TypePropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
type = reader.ReadAsInt32(TypePropertyName);
|
||||
|
||||
|
|
@ -153,11 +152,11 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
throw new InvalidDataException($"Expected '{TypePropertyName}' to be of type {JsonTokenType.Number}.");
|
||||
}
|
||||
}
|
||||
else if (reader.TextEquals(InvocationIdPropertyNameBytes))
|
||||
else if (reader.TextEquals(InvocationIdPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
invocationId = reader.ReadAsString(InvocationIdPropertyName);
|
||||
}
|
||||
else if (reader.TextEquals(StreamIdsPropertyNameBytes))
|
||||
else if (reader.TextEquals(StreamIdsPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
reader.CheckRead();
|
||||
|
||||
|
|
@ -177,15 +176,15 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
|
||||
streamIds = newStreamIds.ToArray();
|
||||
}
|
||||
else if (reader.TextEquals(TargetPropertyNameBytes))
|
||||
else if (reader.TextEquals(TargetPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
target = reader.ReadAsString(TargetPropertyName);
|
||||
}
|
||||
else if (reader.TextEquals(ErrorPropertyNameBytes))
|
||||
else if (reader.TextEquals(ErrorPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
error = reader.ReadAsString(ErrorPropertyName);
|
||||
}
|
||||
else if (reader.TextEquals(ResultPropertyNameBytes))
|
||||
else if (reader.TextEquals(ResultPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
hasResult = true;
|
||||
|
||||
|
|
@ -204,7 +203,7 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
result = BindType(token.RootElement, returnType);
|
||||
}
|
||||
}
|
||||
else if (reader.TextEquals(ItemPropertyNameBytes))
|
||||
else if (reader.TextEquals(ItemPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
reader.CheckRead();
|
||||
|
||||
|
|
@ -233,7 +232,7 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
return new StreamBindingFailureMessage(id, ExceptionDispatchInfo.Capture(ex));
|
||||
}
|
||||
}
|
||||
else if (reader.TextEquals(ArgumentsPropertyNameBytes))
|
||||
else if (reader.TextEquals(ArgumentsPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
reader.CheckRead();
|
||||
|
||||
|
|
@ -272,7 +271,7 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (reader.TextEquals(HeadersPropertyNameBytes))
|
||||
else if (reader.TextEquals(HeadersPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
reader.CheckRead();
|
||||
headers = ReadHeaders(ref reader);
|
||||
|
|
@ -516,7 +515,7 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
else if (message.HasResult)
|
||||
{
|
||||
using var token = GetParsedObject(message.Result, message.Result?.GetType());
|
||||
token.RootElement.WriteAsProperty(ResultPropertyNameBytes, writer);
|
||||
token.RootElement.WriteAsProperty(ResultPropertyNameBytes.EncodedUtf8Bytes, writer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -530,7 +529,7 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
WriteInvocationId(message, writer);
|
||||
|
||||
using var token = GetParsedObject(message.Item, message.Item?.GetType());
|
||||
token.RootElement.WriteAsProperty(ItemPropertyNameBytes, writer);
|
||||
token.RootElement.WriteAsProperty(ItemPropertyNameBytes.EncodedUtf8Bytes, writer);
|
||||
}
|
||||
|
||||
private void WriteInvocationMessage(InvocationMessage message, Utf8JsonWriter writer)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ using System.IO;
|
|||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Internal;
|
||||
using Microsoft.AspNetCore.SignalR.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Protocol
|
||||
{
|
||||
|
|
@ -18,15 +17,14 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
/// </summary>
|
||||
public static class HandshakeProtocol
|
||||
{
|
||||
// Use C#7.3's ReadOnlySpan<byte> optimization for static data https://vcsjones.com/2019/02/01/csharp-readonly-span-bytes-static/
|
||||
private const string ProtocolPropertyName = "protocol";
|
||||
private static ReadOnlySpan<byte> ProtocolPropertyNameBytes => new byte[] { (byte)'p', (byte)'r', (byte)'o', (byte)'t', (byte)'o', (byte)'c', (byte)'o', (byte)'l' };
|
||||
private static JsonEncodedText ProtocolPropertyNameBytes = JsonEncodedText.Encode(ProtocolPropertyName);
|
||||
private const string ProtocolVersionPropertyName = "version";
|
||||
private static ReadOnlySpan<byte> ProtocolVersionPropertyNameBytes => new byte[] { (byte)'v', (byte)'e', (byte)'r', (byte)'s', (byte)'i', (byte)'o', (byte)'n' };
|
||||
private static JsonEncodedText ProtocolVersionPropertyNameBytes = JsonEncodedText.Encode(ProtocolVersionPropertyName);
|
||||
private const string ErrorPropertyName = "error";
|
||||
private static ReadOnlySpan<byte> ErrorPropertyNameBytes => new byte[] { (byte)'e', (byte)'r', (byte)'r', (byte)'o', (byte)'r' };
|
||||
private static JsonEncodedText ErrorPropertyNameBytes = JsonEncodedText.Encode(ErrorPropertyName);
|
||||
private const string TypePropertyName = "type";
|
||||
private static ReadOnlySpan<byte> TypePropertyNameBytes => new byte[] { (byte)'t', (byte)'y', (byte)'p', (byte)'e' };
|
||||
private static JsonEncodedText TypePropertyNameBytes = JsonEncodedText.Encode(TypePropertyName);
|
||||
|
||||
private static ConcurrentDictionary<IHubProtocol, ReadOnlyMemory<byte>> _messageCache = new ConcurrentDictionary<IHubProtocol, ReadOnlyMemory<byte>>();
|
||||
|
||||
|
|
@ -135,13 +133,13 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
{
|
||||
if (reader.TokenType == JsonTokenType.PropertyName)
|
||||
{
|
||||
if (reader.TextEquals(TypePropertyNameBytes))
|
||||
if (reader.TextEquals(TypePropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
// a handshake response does not have a type
|
||||
// check the incoming message was not any other type of message
|
||||
throw new InvalidDataException("Expected a handshake response from the server.");
|
||||
}
|
||||
else if (reader.TextEquals(ErrorPropertyNameBytes))
|
||||
else if (reader.TextEquals(ErrorPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
error = reader.ReadAsString(ErrorPropertyName);
|
||||
}
|
||||
|
|
@ -190,11 +188,11 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
|
|||
{
|
||||
if (reader.TokenType == JsonTokenType.PropertyName)
|
||||
{
|
||||
if (reader.TextEquals(ProtocolPropertyNameBytes))
|
||||
if (reader.TextEquals(ProtocolPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
protocol = reader.ReadAsString(ProtocolPropertyName);
|
||||
}
|
||||
else if (reader.TextEquals(ProtocolVersionPropertyNameBytes))
|
||||
else if (reader.TextEquals(ProtocolVersionPropertyNameBytes.EncodedUtf8Bytes))
|
||||
{
|
||||
protocolVersion = reader.ReadAsInt32(ProtocolVersionPropertyName);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue