diff --git a/SignalR.sln b/SignalR.sln
index 0a0d5e979a..9436f9d8a2 100644
--- a/SignalR.sln
+++ b/SignalR.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.26510.0
+VisualStudioVersion = 15.0.26606.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DA69F624-5398-4884-87E4-B816698CDE65}"
EndProject
@@ -52,8 +52,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Signal
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{6CEC3DC2-5B01-45A8-8F0D-8531315DA90B}"
ProjectSection(SolutionItems) = preProject
- test\Common\ArrayOutput.cs = test\Common\ArrayOutput.cs
- test\Common\ByteArrayExtensions.cs = test\Common\ByteArrayExtensions.cs
test\Common\ChannelExtensions.cs = test\Common\ChannelExtensions.cs
test\Common\TaskExtensions.cs = test\Common\TaskExtensions.cs
EndProjectSection
diff --git a/build/dependencies.props b/build/dependencies.props
index a2f64ad9f2..7cf7a55447 100644
--- a/build/dependencies.props
+++ b/build/dependencies.props
@@ -3,6 +3,7 @@
0.4.0-*
2.0.0-*
0.1.0-*
+ 4.4.0-*
3.1.0
2.1.0-*
10.0.1
diff --git a/client-ts/Microsoft.AspNetCore.SignalR.Test.Server/EchoEndPoint.cs b/client-ts/Microsoft.AspNetCore.SignalR.Test.Server/EchoEndPoint.cs
index 2852c885ae..835bbbd2f0 100644
--- a/client-ts/Microsoft.AspNetCore.SignalR.Test.Server/EchoEndPoint.cs
+++ b/client-ts/Microsoft.AspNetCore.SignalR.Test.Server/EchoEndPoint.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.IO.Pipelines;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Sockets;
diff --git a/samples/SocialWeather/SocialWeatherEndPoint.cs b/samples/SocialWeather/SocialWeatherEndPoint.cs
index 685787d559..2e8e4fa7da 100644
--- a/samples/SocialWeather/SocialWeatherEndPoint.cs
+++ b/samples/SocialWeather/SocialWeatherEndPoint.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
-using System.IO.Pipelines;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Sockets;
using Microsoft.Extensions.Logging;
diff --git a/samples/SocketsSample/EndPoints/MessagesEndPoint.cs b/samples/SocketsSample/EndPoints/MessagesEndPoint.cs
index 4d910b1f66..eee54395e2 100644
--- a/samples/SocketsSample/EndPoints/MessagesEndPoint.cs
+++ b/samples/SocketsSample/EndPoints/MessagesEndPoint.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
-using System.IO.Pipelines;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Sockets;
diff --git a/src/Common/IOutputExtensions.cs b/src/Common/IOutputExtensions.cs
deleted file mode 100644
index 19b5d3b1e4..0000000000
--- a/src/Common/IOutputExtensions.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Binary;
-using System.Runtime;
-using System.Runtime.CompilerServices;
-
-namespace System.Buffers
-{
- internal static class IOutputExtensions
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteBigEndian<[Primitive] T>(this IOutput self, T value) where T : struct
- {
- var size = Unsafe.SizeOf();
- if (self.Buffer.Length < size)
- {
- self.Enlarge(size);
- if (self.Buffer.Length < size)
- {
- return false;
- }
- }
-
- self.Buffer.WriteBigEndian(value);
- self.Advance(size);
- return true;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWrite(this IOutput self, ReadOnlySpan data)
- {
- while (data.Length > 0)
- {
- if (self.Buffer.Length == 0)
- {
- self.Enlarge(data.Length);
- if (self.Buffer.Length == 0)
- {
- // Failed to enlarge
- return false;
- }
- }
-
- var toWrite = Math.Min(self.Buffer.Length, data.Length);
-
- // Slice based on what we can fit
- var chunk = data.Slice(0, toWrite);
- data = data.Slice(toWrite);
-
- // Copy the chunk
- chunk.CopyTo(self.Buffer);
- self.Advance(chunk.Length);
- }
-
- return true;
- }
- }
-}
diff --git a/src/Microsoft.AspNetCore.SignalR.Client/HubConnection.cs b/src/Microsoft.AspNetCore.SignalR.Client/HubConnection.cs
index fb6678d1b8..afbc2ad32a 100644
--- a/src/Microsoft.AspNetCore.SignalR.Client/HubConnection.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Client/HubConnection.cs
@@ -133,7 +133,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
{
try
{
- var payload = await _protocol.WriteToArrayAsync(invocationMessage);
+ var payload = _protocol.WriteToArray(invocationMessage);
_logger.LogInformation("Sending Invocation '{invocationId}'", invocationMessage.InvocationId);
diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageFormatter.cs b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageFormatter.cs
index 3d8df0ca8c..4a9b3ecab8 100644
--- a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageFormatter.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageFormatter.cs
@@ -2,24 +2,26 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Binary;
using System.Buffers;
+using System.IO;
namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
{
public static class BinaryMessageFormatter
{
- public static bool TryWriteMessage(ReadOnlySpan payload, IOutput output)
+ public static bool TryWriteMessage(ReadOnlySpan payload, MemoryStream output)
{
- // Try to write the data
- if (!output.TryWriteBigEndian((long)payload.Length))
- {
- return false;
- }
+ var length = sizeof(long);
+ var buffer = ArrayPool.Shared.Rent(length);
+ BufferWriter.WriteBigEndian(buffer, payload.Length);
+ output.Write(buffer, 0, length);
+ ArrayPool.Shared.Return(buffer);
- if (!output.TryWrite(payload))
- {
- return false;
- }
+ buffer = ArrayPool.Shared.Rent(payload.Length);
+ payload.CopyTo(buffer);
+ output.Write(buffer, 0, payload.Length);
+ ArrayPool.Shared.Return(buffer);
return true;
}
diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageParser.cs b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageParser.cs
index 8cc02cfa3e..56c1c52793 100644
--- a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageParser.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BinaryMessageParser.cs
@@ -3,7 +3,6 @@
using System;
using System.Binary;
-using System.Buffers;
namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
{
@@ -16,33 +15,27 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
_state = default(ParserState);
}
- public bool TryParseMessage(ref BytesReader buffer, out ReadOnlyBuffer payload)
+ public bool TryParseMessage(ref ReadOnlySpan buffer, out ReadOnlyBuffer payload)
{
if (_state.Length == null)
{
- var lengthBuffer = buffer.TryReadBytes(sizeof(long));
+ long length = 0;
- if (lengthBuffer == null)
+ if (buffer.Length < sizeof(long))
{
payload = default(ReadOnlyBuffer);
return false;
}
- var length = lengthBuffer.Value.ToSingleSpan();
+ length = buffer.Slice(0, sizeof(long)).ReadBigEndian();
- if (length.Length < sizeof(long))
- {
- payload = default(ReadOnlyBuffer);
- return false;
- }
-
- var longLength = length.ReadBigEndian();
- if (longLength > Int32.MaxValue)
+ if (length > Int32.MaxValue)
{
throw new FormatException("Messages over 2GB in size are not supported");
}
- buffer.Advance(length.Length);
- _state.Length = (int)longLength;
+
+ buffer = buffer.Slice(sizeof(long));
+ _state.Length = (int)length;
}
if (_state.Payload == null)
@@ -50,13 +43,13 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
_state.Payload = new byte[_state.Length.Value];
}
- while (_state.Read < _state.Payload.Length && buffer.Unread.Length > 0)
+ while (_state.Read < _state.Payload.Length && buffer.Length > 0)
{
// Copy what we can from the current unread segment
- var toCopy = Math.Min(_state.Payload.Length - _state.Read, buffer.Unread.Length);
- buffer.Unread.Slice(0, toCopy).CopyTo(_state.Payload.Slice(_state.Read));
+ var toCopy = Math.Min(_state.Payload.Length - _state.Read, buffer.Length);
+ buffer.Slice(0, toCopy).CopyTo(new Span(_state.Payload, _state.Read));
_state.Read += toCopy;
- buffer.Advance(toCopy);
+ buffer = buffer.Slice(toCopy);
}
if (_state.Read == _state.Payload.Length)
diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BufferExtensions.cs b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BufferExtensions.cs
deleted file mode 100644
index c9c1f257dd..0000000000
--- a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/BufferExtensions.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-namespace System.Buffers
-{
- internal static class BufferExtensions
- {
- public static ReadOnlySpan ToSingleSpan(this ReadOnlyBytes self)
- {
- if (self.Rest == null)
- {
- return self.First.Span;
- }
- else
- {
- return self.ToSpan();
- }
- }
-
- public static ReadOnlyBytes? TryReadBytes(this BytesReader self, int count)
- {
- try
- {
- return self.ReadBytes(count);
- }
- catch (ArgumentOutOfRangeException)
- {
- return null;
- }
- }
- }
-}
diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageFormatter.cs b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageFormatter.cs
index ed4a67580a..f66c4880d2 100644
--- a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageFormatter.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageFormatter.cs
@@ -2,37 +2,44 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.Binary;
using System.Buffers;
+using System.Globalization;
+using System.IO;
using System.Text;
-using System.Text.Formatting;
namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
{
public static class TextMessageFormatter
{
+ private const int Int32OverflowLength = 10;
+
internal const char FieldDelimiter = ':';
internal const char MessageDelimiter = ';';
-
- public static bool TryWriteMessage(ReadOnlySpan payload, IOutput output)
+
+ public static bool TryWriteMessage(ReadOnlySpan payload, Stream output)
{
// Calculate the length, it's the number of characters for text messages, but number of base64 characters for binary
- var length = payload.Length;
// Write the length as a string
- output.Append(length, TextEncoder.Utf8);
+
+ // Super inefficient...
+ var lengthString = payload.Length.ToString(CultureInfo.InvariantCulture);
+ var buffer = ArrayPool.Shared.Rent(Int32OverflowLength);
+ var encodedLength = Encoding.UTF8.GetBytes(lengthString, 0, lengthString.Length, buffer, 0);
+ output.Write(buffer, 0, encodedLength);
+ ArrayPool.Shared.Return(buffer);
// Write the field delimiter ':'
- output.Append(FieldDelimiter, TextEncoder.Utf8);
+ output.WriteByte((byte)FieldDelimiter);
- // Write the payload
- if (!output.TryWrite(payload))
- {
- return false;
- }
+ buffer = ArrayPool.Shared.Rent(payload.Length);
+ payload.CopyTo(buffer);
+ output.Write(buffer, 0, payload.Length);
+ ArrayPool.Shared.Return(buffer);
// Terminator
- output.Append(MessageDelimiter, TextEncoder.Utf8);
+ output.WriteByte((byte)MessageDelimiter);
+
return true;
}
}
diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageParser.cs b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageParser.cs
index 6e7357dce2..9793dcf793 100644
--- a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageParser.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Formatters/TextMessageParser.cs
@@ -2,13 +2,14 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.Buffers;
using System.Text;
namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
{
public class TextMessageParser
{
+ private const int Int32OverflowLength = 10;
+
private ParserState _state;
public void Reset()
@@ -20,9 +21,9 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
/// Attempts to parse a message from the buffer. Returns 'false' if there is not enough data to complete a message. Throws an
/// exception if there is a format error in the provided data.
///
- public bool TryParseMessage(ref BytesReader buffer, out ReadOnlyBuffer payload)
+ public bool TryParseMessage(ref ReadOnlySpan buffer, out ReadOnlyBuffer payload)
{
- while (buffer.Unread.Length > 0)
+ while (buffer.Length > 0)
{
switch (_state.Phase)
{
@@ -65,53 +66,50 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
return false;
}
- private bool TryReadLength(ref BytesReader buffer)
+ private bool TryReadLength(ref ReadOnlySpan buffer)
{
// Read until the first ':' to find the length
- var lengthBuffer = buffer.ReadBytesUntil((byte)TextMessageFormatter.FieldDelimiter);
+ var found = buffer.IndexOf((byte)TextMessageFormatter.FieldDelimiter);
- if (lengthBuffer == null)
+ if (found == -1)
{
// Insufficient data
return false;
}
- var lengthSpan = lengthBuffer.Value.ToSingleSpan();
+ var lengthSpan = buffer.Slice(0, found);
- // Parse the length
- if (!PrimitiveParser.TryParseInt32(lengthSpan, out var length, out var consumedByLength, encoder: TextEncoder.Utf8) || consumedByLength < lengthSpan.Length)
+ if (!TryParseInt32(lengthSpan, out var length, out var bytesConsumed) || bytesConsumed < lengthSpan.Length)
{
- if (TextEncoder.Utf8.TryDecode(lengthSpan, out var lengthString, out _))
- {
- throw new FormatException($"Invalid length: '{lengthString}'");
- }
-
- throw new FormatException("Invalid length");
+ throw new FormatException($"Invalid length: '{Encoding.UTF8.GetString(lengthSpan.ToArray())}'");
}
+ buffer = buffer.Slice(found);
+
_state.Length = length;
_state.Phase = ParsePhase.LengthComplete;
return true;
}
- private bool TryReadDelimiter(ref BytesReader buffer, char delimiter, ParsePhase nextPhase, string field)
+ private bool TryReadDelimiter(ref ReadOnlySpan buffer, char delimiter, ParsePhase nextPhase, string field)
{
- if (buffer.Unread.Length == 0)
+ if (buffer.Length == 0)
{
return false;
}
- if (buffer.Unread[0] != delimiter)
+ if (buffer[0] != delimiter)
{
throw new FormatException($"Missing delimiter '{delimiter}' after {field}");
}
- buffer.Advance(1);
+
+ buffer = buffer.Slice(1);
_state.Phase = nextPhase;
return true;
}
- private void ReadPayload(ref BytesReader buffer)
+ private void ReadPayload(ref ReadOnlySpan buffer)
{
if (_state.Payload == null)
{
@@ -125,13 +123,105 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
else
{
// Copy as much as possible from the Unread buffer
- var toCopy = Math.Min(_state.Length - _state.Read, buffer.Unread.Length);
- buffer.Unread.Slice(0, toCopy).CopyTo(_state.Payload.Slice(_state.Read));
+ var toCopy = Math.Min(_state.Length - _state.Read, buffer.Length);
+
+ buffer.Slice(0, toCopy).CopyTo(new Span(_state.Payload, _state.Read));
_state.Read += toCopy;
- buffer.Advance(toCopy);
+ buffer = buffer.Slice(toCopy);
}
}
+ public static bool TryParseInt32(ReadOnlySpan text, out int value, out int bytesConsumed)
+ {
+ if (text.Length < 1)
+ {
+ bytesConsumed = 0;
+ value = default(int);
+ return false;
+ }
+
+ int indexOfFirstDigit = 0;
+ int sign = 1;
+ if (text[0] == '-')
+ {
+ indexOfFirstDigit = 1;
+ sign = -1;
+ }
+ else if (text[0] == '+')
+ {
+ indexOfFirstDigit = 1;
+ }
+
+ int overflowLength = Int32OverflowLength + indexOfFirstDigit;
+
+ // Parse the first digit separately. If invalid here, we need to return false.
+ int firstDigit = text[indexOfFirstDigit] - 48; // '0'
+ if (firstDigit < 0 || firstDigit > 9)
+ {
+ bytesConsumed = 0;
+ value = default(int);
+ return false;
+ }
+ int parsedValue = firstDigit;
+
+ if (text.Length < overflowLength)
+ {
+ // Length is less than Int32OverflowLength; overflow is not possible
+ for (int index = indexOfFirstDigit + 1; index < text.Length; index++)
+ {
+ int nextDigit = text[index] - 48; // '0'
+ if (nextDigit < 0 || nextDigit > 9)
+ {
+ bytesConsumed = index;
+ value = parsedValue * sign;
+ return true;
+ }
+ parsedValue = parsedValue * 10 + nextDigit;
+ }
+ }
+ else
+ {
+ // Length is greater than Int32OverflowLength; overflow is only possible after Int32OverflowLength
+ // digits. There may be no overflow after Int32OverflowLength if there are leading zeroes.
+ for (int index = indexOfFirstDigit + 1; index < overflowLength - 1; index++)
+ {
+ int nextDigit = text[index] - 48; // '0'
+ if (nextDigit < 0 || nextDigit > 9)
+ {
+ bytesConsumed = index;
+ value = parsedValue * sign;
+ return true;
+ }
+ parsedValue = parsedValue * 10 + nextDigit;
+ }
+ for (int index = overflowLength - 1; index < text.Length; index++)
+ {
+ int nextDigit = text[index] - 48; // '0'
+ if (nextDigit < 0 || nextDigit > 9)
+ {
+ bytesConsumed = index;
+ value = parsedValue * sign;
+ return true;
+ }
+ // If parsedValue > (int.MaxValue / 10), any more appended digits will cause overflow.
+ // if parsedValue == (int.MaxValue / 10), any nextDigit greater than 7 or 8 (depending on sign) implies overflow.
+ bool positive = sign > 0;
+ bool nextDigitTooLarge = nextDigit > 8 || (positive && nextDigit > 7);
+ if (parsedValue > int.MaxValue / 10 || parsedValue == int.MaxValue / 10 && nextDigitTooLarge)
+ {
+ bytesConsumed = 0;
+ value = default(int);
+ return false;
+ }
+ parsedValue = parsedValue * 10 + nextDigit;
+ }
+ }
+
+ bytesConsumed = text.Length;
+ value = parsedValue * sign;
+ return true;
+ }
+
private struct ParserState
{
public ParsePhase Phase;
diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/HubProtocolWriteMessageExtensions.cs b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/HubProtocolWriteMessageExtensions.cs
index b53f2909ee..6f499e6cd6 100644
--- a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/HubProtocolWriteMessageExtensions.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/HubProtocolWriteMessageExtensions.cs
@@ -3,34 +3,22 @@
using System;
using System.IO;
-using System.IO.Pipelines;
-using System.IO.Pipelines.Text.Primitives;
-using System.Text;
-using System.Threading.Tasks;
namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
{
public static class HubProtocolWriteMessageExtensions
{
- public static async ValueTask WriteToArrayAsync(this IHubProtocol protocol, HubMessage message)
+ public static byte[] WriteToArray(this IHubProtocol protocol, HubMessage message)
{
- using (var memoryStream = new MemoryStream())
+ using (var output = new MemoryStream())
{
- var pipe = memoryStream.AsPipelineWriter();
-
- // See https://github.com/dotnet/corefxlab/issues/1460, the TextEncoder is unimportant but required.
- var output = new PipelineTextOutput(pipe, TextEncoder.Utf8);
-
// Encode the message
if (!protocol.TryWriteMessage(message, output))
{
throw new InvalidOperationException("Failed to write message to the output stream");
}
-
- await output.FlushAsync();
-
- // Create a message
- return memoryStream.ToArray();
+
+ return output.ToArray();
}
}
}
diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/IHubProtocol.cs b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/IHubProtocol.cs
index a8bae3cc05..4ba7423321 100644
--- a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/IHubProtocol.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/IHubProtocol.cs
@@ -4,6 +4,7 @@
using System;
using System.Buffers;
using System.Collections.Generic;
+using System.IO;
namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
{
@@ -11,6 +12,6 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
{
bool TryParseMessages(ReadOnlySpan input, IInvocationBinder binder, out IList messages);
- bool TryWriteMessage(HubMessage message, IOutput output);
+ bool TryWriteMessage(HubMessage message, Stream output);
}
}
diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/JsonHubProtocol.cs b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/JsonHubProtocol.cs
index 370f219010..82ed1fffeb 100644
--- a/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/JsonHubProtocol.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Common/Internal/Protocol/JsonHubProtocol.cs
@@ -47,11 +47,10 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
public bool TryParseMessages(ReadOnlySpan input, IInvocationBinder binder, out IList messages)
{
- var reader = new BytesReader(input.ToArray());
messages = new List();
var parser = new TextMessageParser();
- while (parser.TryParseMessage(ref reader, out var payload))
+ while (parser.TryParseMessage(ref input, out var payload))
{
// TODO: Need a span-native JSON parser!
using (var memoryStream = new MemoryStream(payload.ToArray()))
@@ -63,9 +62,8 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Protocol
return messages.Count > 0;
}
- public bool TryWriteMessage(HubMessage message, IOutput output)
+ public bool TryWriteMessage(HubMessage message, Stream output)
{
- // TODO: Need IOutput-compatible JSON serializer!
using (var memoryStream = new MemoryStream())
{
WriteMessage(message, memoryStream);
diff --git a/src/Microsoft.AspNetCore.SignalR.Common/Microsoft.AspNetCore.SignalR.Common.csproj b/src/Microsoft.AspNetCore.SignalR.Common/Microsoft.AspNetCore.SignalR.Common.csproj
index e783c7c491..2c479940fe 100644
--- a/src/Microsoft.AspNetCore.SignalR.Common/Microsoft.AspNetCore.SignalR.Common.csproj
+++ b/src/Microsoft.AspNetCore.SignalR.Common/Microsoft.AspNetCore.SignalR.Common.csproj
@@ -12,13 +12,10 @@
Microsoft.AspNetCore.SignalR
-
-
-
-
-
+
+
diff --git a/src/Microsoft.AspNetCore.SignalR.Redis/RedisHubLifetimeManager.cs b/src/Microsoft.AspNetCore.SignalR.Redis/RedisHubLifetimeManager.cs
index dd80dc5afc..13308c2224 100644
--- a/src/Microsoft.AspNetCore.SignalR.Redis/RedisHubLifetimeManager.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Redis/RedisHubLifetimeManager.cs
@@ -5,15 +5,12 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
-using System.IO.Pipelines;
-using System.IO.Pipelines.Text.Primitives;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.AspNetCore.Sockets;
-using Microsoft.AspNetCore.Sockets.Internal.Formatters;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
@@ -313,7 +310,7 @@ namespace Microsoft.AspNetCore.SignalR.Redis
private async Task WriteAsync(ConnectionContext connection, HubMessage hubMessage)
{
var protocol = connection.Metadata.Get(HubConnectionMetadataNames.HubProtocol);
- var data = await protocol.WriteToArrayAsync(hubMessage);
+ var data = protocol.WriteToArray(hubMessage);
while (await connection.Transport.Output.WaitToWriteAsync())
{
diff --git a/src/Microsoft.AspNetCore.SignalR/DefaultHubLifetimeManager.cs b/src/Microsoft.AspNetCore.SignalR/DefaultHubLifetimeManager.cs
index 15218eb4d6..4d1ee56803 100644
--- a/src/Microsoft.AspNetCore.SignalR/DefaultHubLifetimeManager.cs
+++ b/src/Microsoft.AspNetCore.SignalR/DefaultHubLifetimeManager.cs
@@ -4,14 +4,11 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.IO.Pipelines;
-using System.IO.Pipelines.Text.Primitives;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.AspNetCore.Sockets;
-using Microsoft.AspNetCore.Sockets.Internal.Formatters;
namespace Microsoft.AspNetCore.SignalR
{
@@ -125,7 +122,7 @@ namespace Microsoft.AspNetCore.SignalR
private async Task WriteAsync(ConnectionContext connection, HubMessage hubMessage)
{
var protocol = connection.Metadata.Get(HubConnectionMetadataNames.HubProtocol);
- var payload = await protocol.WriteToArrayAsync(hubMessage);
+ var payload = protocol.WriteToArray(hubMessage);
while (await connection.Transport.Output.WaitToWriteAsync())
{
diff --git a/src/Microsoft.AspNetCore.SignalR/HubEndPoint.cs b/src/Microsoft.AspNetCore.SignalR/HubEndPoint.cs
index 139920dd05..cd04d3acd7 100644
--- a/src/Microsoft.AspNetCore.SignalR/HubEndPoint.cs
+++ b/src/Microsoft.AspNetCore.SignalR/HubEndPoint.cs
@@ -230,7 +230,7 @@ namespace Microsoft.AspNetCore.SignalR
private async Task SendMessageAsync(ConnectionContext connection, IHubProtocol protocol, HubMessage hubMessage)
{
- var payload = await protocol.WriteToArrayAsync(hubMessage);
+ var payload = protocol.WriteToArray(hubMessage);
while (await connection.Transport.Output.WaitToWriteAsync())
{
diff --git a/src/Microsoft.AspNetCore.Sockets.Http/HttpConnectionDispatcher.cs b/src/Microsoft.AspNetCore.Sockets.Http/HttpConnectionDispatcher.cs
index 5a7ed4af4e..e5a5b70d17 100644
--- a/src/Microsoft.AspNetCore.Sockets.Http/HttpConnectionDispatcher.cs
+++ b/src/Microsoft.AspNetCore.Sockets.Http/HttpConnectionDispatcher.cs
@@ -3,7 +3,6 @@
using System;
using System.IO;
-using System.IO.Pipelines;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
diff --git a/src/Microsoft.AspNetCore.Sockets.Http/Internal/Transports/ServerSentEventsMessageFormatter.cs b/src/Microsoft.AspNetCore.Sockets.Http/Internal/Transports/ServerSentEventsMessageFormatter.cs
index 896134e1a5..54b6a6ca87 100644
--- a/src/Microsoft.AspNetCore.Sockets.Http/Internal/Transports/ServerSentEventsMessageFormatter.cs
+++ b/src/Microsoft.AspNetCore.Sockets.Http/Internal/Transports/ServerSentEventsMessageFormatter.cs
@@ -2,8 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.Binary;
using System.Buffers;
+using System.IO;
namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
{
@@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
private const byte LineFeed = (byte)'\n';
- public static bool TryWriteMessage(ReadOnlySpan payload, IOutput output)
+ public static bool TryWriteMessage(ReadOnlySpan payload, MemoryStream output)
{
// Write the payload
if (!TryWritePayload(payload, output))
@@ -22,15 +22,12 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
return false;
}
- if (!output.TryWrite(Newline))
- {
- return false;
- }
+ output.Write(Newline, 0, Newline.Length);
return true;
}
- private static bool TryWritePayload(ReadOnlySpan payload, IOutput output)
+ private static bool TryWritePayload(ReadOnlySpan payload, Stream output)
{
// Short-cut for empty payload
if (payload.Length == 0)
@@ -88,22 +85,16 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
return true;
}
- private static bool TryWriteLine(ReadOnlySpan line, IOutput output)
+ private static bool TryWriteLine(ReadOnlySpan payload, Stream output)
{
- if (!output.TryWrite(DataPrefix))
- {
- return false;
- }
+ output.Write(DataPrefix, 0, DataPrefix.Length);
- if (!output.TryWrite(line))
- {
- return false;
- }
+ var buffer = ArrayPool.Shared.Rent(payload.Length);
+ payload.CopyTo(buffer);
+ output.Write(buffer, 0, payload.Length);
+ ArrayPool.Shared.Return(buffer);
- if (!output.TryWrite(Newline))
- {
- return false;
- }
+ output.Write(Newline, 0, Newline.Length);
return true;
}
diff --git a/src/Microsoft.AspNetCore.Sockets.Http/Internal/Transports/ServerSentEventsTransport.cs b/src/Microsoft.AspNetCore.Sockets.Http/Internal/Transports/ServerSentEventsTransport.cs
index a0d9b8fc99..a2007c6dfc 100644
--- a/src/Microsoft.AspNetCore.Sockets.Http/Internal/Transports/ServerSentEventsTransport.cs
+++ b/src/Microsoft.AspNetCore.Sockets.Http/Internal/Transports/ServerSentEventsTransport.cs
@@ -2,9 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.IO.Pipelines;
-using System.IO.Pipelines.Text.Primitives;
-using System.Text;
+using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Channels;
@@ -44,17 +42,15 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Transports
await context.Response.WriteAsync(":\r\n");
await context.Response.Body.FlushAsync();
- var pipe = context.Response.Body.AsPipelineWriter();
- var output = new PipelineTextOutput(pipe, TextEncoder.Utf8); // We don't need the Encoder, but it's harmless to set.
-
try
{
+ var ms = new MemoryStream();
while (await _application.WaitToReadAsync(token))
{
while (_application.TryRead(out var buffer))
{
_logger.SSEWritingMessage(_connectionId, buffer.Length);
- if (!ServerSentEventsMessageFormatter.TryWriteMessage(buffer, output))
+ if (!ServerSentEventsMessageFormatter.TryWriteMessage(buffer, ms))
{
// We ran out of space to write, even after trying to enlarge.
// This should only happen in a significant lack-of-memory scenario.
@@ -64,11 +60,12 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Transports
// Throwing InvalidOperationException here, but it's not quite an invalid operation...
throw new InvalidOperationException("Ran out of space to format messages!");
}
-
- await output.FlushAsync();
}
}
+ ms.Seek(0, SeekOrigin.Begin);
+ await ms.CopyToAsync(context.Response.Body);
+
await _application.Completion;
}
catch (OperationCanceledException)
diff --git a/src/Microsoft.AspNetCore.Sockets.Http/Microsoft.AspNetCore.Sockets.Http.csproj b/src/Microsoft.AspNetCore.Sockets.Http/Microsoft.AspNetCore.Sockets.Http.csproj
index 971786f6ca..93e9f92f60 100644
--- a/src/Microsoft.AspNetCore.Sockets.Http/Microsoft.AspNetCore.Sockets.Http.csproj
+++ b/src/Microsoft.AspNetCore.Sockets.Http/Microsoft.AspNetCore.Sockets.Http.csproj
@@ -11,10 +11,6 @@
false
-
-
-
-
@@ -24,7 +20,8 @@
-
+
+
diff --git a/test/Common/ArrayOutput.cs b/test/Common/ArrayOutput.cs
deleted file mode 100644
index 463bf20580..0000000000
--- a/test/Common/ArrayOutput.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Buffers;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-
-namespace Microsoft.AspNetCore.Sockets.Tests.Internal
-{
- internal class ArrayOutput : IOutput
- {
- private IList> _buffers = new List>();
-
- private int _chunkSize;
- private byte[] _activeBuffer;
- private int _offset;
-
- public Span Buffer => _activeBuffer.Slice(_offset);
-
- public ArrayOutput(int chunkSize)
- {
- _chunkSize = chunkSize;
- AdvanceChunk();
- }
-
- public void Advance(int bytes)
- {
- // Determine the new location
- _offset += bytes;
- Debug.Assert(_offset <= _activeBuffer.Length, "How did we write more data than we had space?");
- }
-
- public void Enlarge(int desiredBufferLength = 0)
- {
- if (desiredBufferLength == 0 || _activeBuffer.Length - _offset < desiredBufferLength)
- {
- AdvanceChunk();
- }
- }
-
- public byte[] ToArray()
- {
- var totalLength = _buffers.Sum(b => b.Count) + _offset;
-
- var arr = new byte[totalLength];
-
- int offset = 0;
- foreach (var buffer in _buffers)
- {
- System.Buffer.BlockCopy(buffer.Array, 0, arr, offset, buffer.Count);
- offset += buffer.Count;
- }
-
- if (_offset > 0)
- {
- System.Buffer.BlockCopy(_activeBuffer, 0, arr, offset, _offset);
- }
-
- return arr;
- }
-
- private void AdvanceChunk()
- {
- if (_activeBuffer != null)
- {
- _buffers.Add(new ArraySegment(_activeBuffer, 0, _offset));
- }
-
- _activeBuffer = new byte[_chunkSize];
- _offset = 0;
- }
- }
-}
diff --git a/test/Common/ByteArrayExtensions.cs b/test/Common/ByteArrayExtensions.cs
deleted file mode 100644
index 9b02403b27..0000000000
--- a/test/Common/ByteArrayExtensions.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Buffers;
-using System.Collections.Generic;
-
-namespace System
-{
- internal static class ByteArrayExtensions
- {
- public static ReadOnlyBytes ToChunkedReadOnlyBytes(this byte[] data, int chunkSize)
- {
- if (chunkSize == 0)
- {
- return new ReadOnlyBytes(data);
- }
-
- var chunks = new List();
- for (var i = 0; i < data.Length; i += chunkSize)
- {
- var thisChunkSize = Math.Min(chunkSize, data.Length - i);
- var chunk = new byte[thisChunkSize];
- for (var j = 0; j < thisChunkSize; j++)
- {
- chunk[j] = data[i + j];
- }
- chunks.Add(chunk);
- }
-
- chunks.Reverse();
-
- ReadOnlyBytes? bytes = null;
- foreach (var chunk in chunks)
- {
- if (bytes == null)
- {
- bytes = new ReadOnlyBytes(chunk);
- }
- else
- {
- bytes = new ReadOnlyBytes(chunk, bytes);
- }
- }
- return bytes.Value;
- }
- }
-}
diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionTests.cs b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionTests.cs
index 7b97e55a18..cf15f6688c 100644
--- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionTests.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionTests.cs
@@ -4,6 +4,7 @@
using System;
using System.Buffers;
using System.Collections.Generic;
+using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
@@ -191,7 +192,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
throw new InvalidOperationException("No Parsed Message provided");
}
- public bool TryWriteMessage(HubMessage message, IOutput output)
+ public bool TryWriteMessage(HubMessage message, Stream output)
{
WriteCalls += 1;
diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/Microsoft.AspNetCore.SignalR.Client.Tests.csproj b/test/Microsoft.AspNetCore.SignalR.Client.Tests/Microsoft.AspNetCore.SignalR.Client.Tests.csproj
index c564fcbb8a..71be053e5d 100644
--- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/Microsoft.AspNetCore.SignalR.Client.Tests.csproj
+++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/Microsoft.AspNetCore.SignalR.Client.Tests.csproj
@@ -9,7 +9,6 @@
-
diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/TestConnection.cs b/test/Microsoft.AspNetCore.SignalR.Client.Tests/TestConnection.cs
index 5e5104ced9..a2ab964f01 100644
--- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/TestConnection.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/TestConnection.cs
@@ -2,15 +2,14 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Channels;
-using Microsoft.AspNetCore.Sockets;
using Microsoft.AspNetCore.Sockets.Client;
using Microsoft.AspNetCore.Sockets.Internal.Formatters;
-using Microsoft.AspNetCore.Sockets.Tests.Internal;
using Newtonsoft.Json;
using Xunit;
@@ -88,7 +87,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
private byte[] FormatMessageToArray(byte[] message)
{
- var output = new ArrayOutput(1024);
+ var output = new MemoryStream();
Assert.True(TextMessageFormatter.TryWriteMessage(message, output));
return output.ToArray();
}
diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/JsonHubProtocolTests.cs b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/JsonHubProtocolTests.cs
index e26aad5d85..d36d1b16d6 100644
--- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/JsonHubProtocolTests.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/JsonHubProtocolTests.cs
@@ -1,12 +1,12 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
using Microsoft.AspNetCore.Sockets.Internal.Formatters;
-using Microsoft.AspNetCore.Sockets.Tests.Internal;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Xunit;
@@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
[Theory]
[MemberData(nameof(ProtocolTestData))]
- public async Task WriteMessage(HubMessage message, bool camelCase, NullValueHandling nullValueHandling, string expectedOutput)
+ public void WriteMessage(HubMessage message, bool camelCase, NullValueHandling nullValueHandling, string expectedOutput)
{
expectedOutput = Frame(expectedOutput);
@@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
};
var protocol = new JsonHubProtocol(jsonSerializer);
- var encoded = await protocol.WriteToArrayAsync(message);
+ var encoded = protocol.WriteToArray(message);
var json = Encoding.UTF8.GetString(encoded);
Assert.Equal(expectedOutput, json);
@@ -142,7 +142,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
private static byte[] FormatMessageToArray(byte[] message)
{
- var output = new ArrayOutput(1024);
+ var output = new MemoryStream();
Assert.True(TextMessageFormatter.TryWriteMessage(message, output));
return output.ToArray();
}
diff --git a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Microsoft.AspNetCore.SignalR.Common.Tests.csproj b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Microsoft.AspNetCore.SignalR.Common.Tests.csproj
index c9fe4062b9..7518cdb42c 100644
--- a/test/Microsoft.AspNetCore.SignalR.Common.Tests/Microsoft.AspNetCore.SignalR.Common.Tests.csproj
+++ b/test/Microsoft.AspNetCore.SignalR.Common.Tests/Microsoft.AspNetCore.SignalR.Common.Tests.csproj
@@ -7,10 +7,6 @@
netcoreapp2.0
-
-
-
-
diff --git a/test/Microsoft.AspNetCore.SignalR.Microbenchmarks/MessageParserBenchmark.cs b/test/Microsoft.AspNetCore.SignalR.Microbenchmarks/MessageParserBenchmark.cs
index 40443b692a..20331dea06 100644
--- a/test/Microsoft.AspNetCore.SignalR.Microbenchmarks/MessageParserBenchmark.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Microbenchmarks/MessageParserBenchmark.cs
@@ -1,8 +1,8 @@
using System;
using System.Buffers;
+using System.IO;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Sockets.Internal.Formatters;
-using Microsoft.AspNetCore.Sockets.Tests.Internal;
namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
{
@@ -12,8 +12,8 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
private static readonly Random Random = new Random();
private readonly TextMessageParser _textMessageParser = new TextMessageParser();
private readonly BinaryMessageParser _binaryMessageParser = new BinaryMessageParser();
- private ReadOnlyBytes _binaryInput;
- private ReadOnlyBytes _textInput;
+ private ReadOnlyBuffer _binaryInput;
+ private ReadOnlyBuffer _textInput;
[Params(32, 64)]
public int ChunkSize { get; set; }
@@ -26,30 +26,30 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
{
var buffer = new byte[MessageLength];
Random.NextBytes(buffer);
- var output = new ArrayOutput(MessageLength + 32);
+ var output = new MemoryStream();
if (!BinaryMessageFormatter.TryWriteMessage(buffer, output))
{
throw new InvalidOperationException("Failed to format message");
}
- _binaryInput = output.ToArray().ToChunkedReadOnlyBytes(ChunkSize);
+ _binaryInput = output.ToArray();
buffer = new byte[MessageLength];
Random.NextBytes(buffer);
- output = new ArrayOutput(MessageLength + 32);
+ output = new MemoryStream();
if (!TextMessageFormatter.TryWriteMessage(buffer, output))
{
throw new InvalidOperationException("Failed to format message");
}
- _textInput = output.ToArray().ToChunkedReadOnlyBytes(ChunkSize);
+ _textInput = output.ToArray();
}
[Benchmark]
public void SingleBinaryMessage()
{
- var reader = new BytesReader(_binaryInput);
- if (!_binaryMessageParser.TryParseMessage(ref reader, out _))
+ var buffer = _binaryInput.Span;
+ if (!_binaryMessageParser.TryParseMessage(ref buffer, out _))
{
throw new InvalidOperationException("Failed to parse");
}
@@ -58,8 +58,8 @@ namespace Microsoft.AspNetCore.SignalR.Microbenchmarks
[Benchmark]
public void SingleTextMessage()
{
- var reader = new BytesReader(_textInput);
- if (!_textMessageParser.TryParseMessage(ref reader, out _))
+ var buffer = _textInput.Span;
+ if (!_textMessageParser.TryParseMessage(ref buffer, out _))
{
throw new InvalidOperationException("Failed to parse");
}
diff --git a/test/Microsoft.AspNetCore.SignalR.Microbenchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks.csproj b/test/Microsoft.AspNetCore.SignalR.Microbenchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks.csproj
index af3aa9a7b2..f838587df2 100644
--- a/test/Microsoft.AspNetCore.SignalR.Microbenchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks.csproj
+++ b/test/Microsoft.AspNetCore.SignalR.Microbenchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks.csproj
@@ -7,11 +7,6 @@
netcoreapp2.0;net461
-
-
-
-
-
diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/BinaryMessageFormatterTests.cs b/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/BinaryMessageFormatterTests.cs
index 595cc5641f..ef47d6e9bf 100644
--- a/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/BinaryMessageFormatterTests.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/BinaryMessageFormatterTests.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.IO;
using System.Text;
using Microsoft.AspNetCore.Sockets.Internal.Formatters;
using Xunit;
@@ -28,7 +29,7 @@ namespace Microsoft.AspNetCore.Sockets.Tests.Internal.Formatters
Encoding.UTF8.GetBytes("Hello,\r\nWorld!")
};
- var output = new ArrayOutput(chunkSize: 8); // Use small chunks to test Advance/Enlarge and partial payload writing
+ var output = new MemoryStream(); // Use small chunks to test Advance/Enlarge and partial payload writing
foreach (var message in messages)
{
Assert.True(BinaryMessageFormatter.TryWriteMessage(message, output));
@@ -46,11 +47,11 @@ namespace Microsoft.AspNetCore.Sockets.Tests.Internal.Formatters
[InlineData(0, 256, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xAB, 0xCD, 0xEF, 0x12 }, new byte[] { 0xAB, 0xCD, 0xEF, 0x12 })]
public void WriteBinaryMessage(int offset, int chunkSize, byte[] encoded, byte[] payload)
{
- var output = new ArrayOutput(chunkSize);
+ var output = new MemoryStream();
if (offset > 0)
{
- output.Advance(offset);
+ output.Seek(offset, SeekOrigin.Begin);
}
Assert.True(BinaryMessageFormatter.TryWriteMessage(payload, output));
@@ -66,11 +67,11 @@ namespace Microsoft.AspNetCore.Sockets.Tests.Internal.Formatters
public void WriteTextMessage(int offset, int chunkSize, byte[] encoded, string payload)
{
var message = Encoding.UTF8.GetBytes(payload);
- var output = new ArrayOutput(chunkSize);
+ var output = new MemoryStream();
if (offset > 0)
{
- output.Advance(offset);
+ output.Seek(offset, SeekOrigin.Begin);
}
Assert.True(BinaryMessageFormatter.TryWriteMessage(message, output));
diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/BinaryMessageParserTests.cs b/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/BinaryMessageParserTests.cs
index 9ae8d374bd..d1ba3651ad 100644
--- a/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/BinaryMessageParserTests.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/BinaryMessageParserTests.cs
@@ -19,9 +19,9 @@ namespace Microsoft.AspNetCore.Sockets.Common.Tests.Internal.Formatters
public void ReadMessage(byte[] encoded, string payload)
{
var parser = new BinaryMessageParser();
- var reader = new BytesReader(encoded);
- Assert.True(parser.TryParseMessage(ref reader, out var message));
- Assert.Equal(reader.Index, encoded.Length);
+ ReadOnlySpan span = encoded.AsSpan();
+ Assert.True(parser.TryParseMessage(ref span, out var message));
+ Assert.Equal(0, span.Length);
Assert.Equal(Encoding.UTF8.GetBytes(payload), message.ToArray());
}
@@ -32,18 +32,14 @@ namespace Microsoft.AspNetCore.Sockets.Common.Tests.Internal.Formatters
public void ReadBinaryMessage(byte[] encoded, byte[] payload)
{
var parser = new BinaryMessageParser();
- var reader = new BytesReader(encoded);
- Assert.True(parser.TryParseMessage(ref reader, out var message));
- Assert.Equal(reader.Index, encoded.Length);
+ ReadOnlySpan span = encoded.AsSpan();
+ Assert.True(parser.TryParseMessage(ref span, out var message));
+ Assert.Equal(0, span.Length);
Assert.Equal(payload, message.ToArray());
}
- [Theory]
- [InlineData(0)] // No chunking
- [InlineData(4)]
- [InlineData(8)]
- [InlineData(256)]
- public void ReadMultipleMessages(int chunkSize)
+ [Fact]
+ public void ReadMultipleMessages()
{
var encoded = new byte[]
{
@@ -53,16 +49,15 @@ namespace Microsoft.AspNetCore.Sockets.Common.Tests.Internal.Formatters
/* body: */ 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x0D, 0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21,
};
var parser = new BinaryMessageParser();
- var buffer = encoded.ToChunkedReadOnlyBytes(chunkSize);
- var reader = new BytesReader(buffer);
+ ReadOnlySpan span = encoded.AsSpan();
var messages = new List();
- while (parser.TryParseMessage(ref reader, out var message))
+ while (parser.TryParseMessage(ref span, out var message))
{
messages.Add(message.ToArray());
}
- Assert.Equal(encoded.Length, reader.Index);
+ Assert.Equal(0, span.Length);
Assert.Equal(2, messages.Count);
Assert.Equal(new byte[0], messages[0]);
@@ -75,9 +70,9 @@ namespace Microsoft.AspNetCore.Sockets.Common.Tests.Internal.Formatters
public void ReadIncompleteMessages(byte[] encoded)
{
var parser = new BinaryMessageParser();
- var reader = new BytesReader(new ReadOnlyBytes(encoded));
- Assert.False(parser.TryParseMessage(ref reader, out var message));
- Assert.Equal(encoded.Length, reader.Index);
+ ReadOnlySpan span = encoded.AsSpan();
+ Assert.False(parser.TryParseMessage(ref span, out var message));
+ Assert.Equal(0, span.Length);
}
}
}
diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/TextMessageFormatterTests.cs b/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/TextMessageFormatterTests.cs
index 10677c2407..e3c78c8940 100644
--- a/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/TextMessageFormatterTests.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/TextMessageFormatterTests.cs
@@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using System.Collections.Generic;
+using System.IO;
using System.Text;
using Microsoft.AspNetCore.Sockets.Internal.Formatters;
using Xunit;
@@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Sockets.Tests.Internal.Formatters
Encoding.UTF8.GetBytes("Hello,\r\nWorld!")
};
- var output = new ArrayOutput(chunkSize: 8); // Use small chunks to test Advance/Enlarge and partial payload writing
+ var output = new MemoryStream();
foreach (var message in messages)
{
Assert.True(TextMessageFormatter.TryWriteMessage(message, output));
@@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Sockets.Tests.Internal.Formatters
public void WriteMessage(int chunkSize, string encoded, string payload)
{
var message = Encoding.UTF8.GetBytes(payload);
- var output = new ArrayOutput(chunkSize); // Use small chunks to test Advance/Enlarge and partial payload writing
+ var output = new MemoryStream();
Assert.True(TextMessageFormatter.TryWriteMessage(message, output));
diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/TextMessageParserTests.cs b/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/TextMessageParserTests.cs
index 6397a7ee17..ef2caaa829 100644
--- a/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/TextMessageParserTests.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Tests/Formatters/TextMessageParserTests.cs
@@ -21,35 +21,28 @@ namespace Microsoft.AspNetCore.Sockets.Common.Tests.Internal.Formatters
{
var parser = new TextMessageParser();
var buffer = Encoding.UTF8.GetBytes(encoded);
- var reader = new BytesReader(buffer.ToChunkedReadOnlyBytes(chunkSize));
+ ReadOnlySpan span = buffer.AsSpan();
- Assert.True(parser.TryParseMessage(ref reader, out var message));
- Assert.Equal(reader.Index, buffer.Length);
+ Assert.True(parser.TryParseMessage(ref span, out var message));
+ Assert.Equal(0, span.Length);
Assert.Equal(Encoding.UTF8.GetBytes(payload), message.ToArray());
}
- [Theory]
- [InlineData(0)] // Not chunked
- [InlineData(4)]
- [InlineData(8)]
- public void ReadMultipleMessages(int chunkSize)
+ [Fact]
+ public void ReadMultipleMessages()
{
const string encoded = "0:;14:Hello,\r\nWorld!;";
var parser = new TextMessageParser();
var data = Encoding.UTF8.GetBytes(encoded);
- var buffer = chunkSize > 0 ?
- data.ToChunkedReadOnlyBytes(chunkSize) :
- new ReadOnlyBytes(data);
-
- var reader = new BytesReader(buffer);
+ ReadOnlySpan span = data.AsSpan();
var messages = new List();
- while (parser.TryParseMessage(ref reader, out var message))
+ while (parser.TryParseMessage(ref span, out var message))
{
messages.Add(message.ToArray());
}
- Assert.Equal(reader.Index, Encoding.UTF8.GetByteCount(encoded));
+ Assert.Equal(0, span.Length);
Assert.Equal(2, messages.Count);
Assert.Equal(new byte[0], messages[0]);
@@ -68,8 +61,8 @@ namespace Microsoft.AspNetCore.Sockets.Common.Tests.Internal.Formatters
{
var parser = new TextMessageParser();
var buffer = Encoding.UTF8.GetBytes(encoded);
- var reader = new BytesReader(buffer);
- Assert.False(parser.TryParseMessage(ref reader, out _));
+ ReadOnlySpan span = buffer.AsSpan();
+ Assert.False(parser.TryParseMessage(ref span, out _));
}
[Theory]
@@ -82,8 +75,11 @@ namespace Microsoft.AspNetCore.Sockets.Common.Tests.Internal.Formatters
{
var parser = new TextMessageParser();
var buffer = Encoding.UTF8.GetBytes(encoded);
- var reader = new BytesReader(buffer);
- var ex = Assert.Throws(() => parser.TryParseMessage(ref reader, out _));
+ var ex = Assert.Throws(() =>
+ {
+ ReadOnlySpan span = buffer.AsSpan();
+ parser.TryParseMessage(ref span, out _);
+ });
Assert.Equal(expectedMessage, ex.Message);
}
@@ -96,8 +92,12 @@ namespace Microsoft.AspNetCore.Sockets.Common.Tests.Internal.Formatters
// We need to include the ':' so that
var buffer = new byte[] { 0x48, 0x65, 0x80, 0x6C, 0x6F, (byte)':' };
var reader = new BytesReader(buffer);
- var ex = Assert.Throws(() => parser.TryParseMessage(ref reader, out _));
- Assert.Equal("Invalid length", ex.Message);
+ var ex = Assert.Throws(() =>
+ {
+ ReadOnlySpan span = buffer.AsSpan();
+ parser.TryParseMessage(ref span, out _);
+ });
+ Assert.Equal("Invalid length: 'He�lo'", ex.Message);
}
}
}
diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/Microsoft.AspNetCore.SignalR.Tests.csproj b/test/Microsoft.AspNetCore.SignalR.Tests/Microsoft.AspNetCore.SignalR.Tests.csproj
index 25d5d021c4..852e041f78 100644
--- a/test/Microsoft.AspNetCore.SignalR.Tests/Microsoft.AspNetCore.SignalR.Tests.csproj
+++ b/test/Microsoft.AspNetCore.SignalR.Tests/Microsoft.AspNetCore.SignalR.Tests.csproj
@@ -16,8 +16,6 @@
-
-
diff --git a/test/Microsoft.AspNetCore.SignalR.Tests/TestClient.cs b/test/Microsoft.AspNetCore.SignalR.Tests/TestClient.cs
index 7e10ba2398..c21c90cdb2 100644
--- a/test/Microsoft.AspNetCore.SignalR.Tests/TestClient.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Tests/TestClient.cs
@@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
public async Task SendInvocationAsync(string methodName, params object[] args)
{
var invocationId = GetInvocationId();
- var payload = await _protocol.WriteToArrayAsync(new InvocationMessage(invocationId, nonBlocking: false, target: methodName, arguments: args));
+ var payload = _protocol.WriteToArray(new InvocationMessage(invocationId, nonBlocking: false, target: methodName, arguments: args));
await Application.Output.WriteAsync(payload);
diff --git a/test/Microsoft.AspNetCore.Sockets.Tests/Microsoft.AspNetCore.Sockets.Tests.csproj b/test/Microsoft.AspNetCore.Sockets.Tests/Microsoft.AspNetCore.Sockets.Tests.csproj
index e17e197247..4e0dcb7d96 100644
--- a/test/Microsoft.AspNetCore.Sockets.Tests/Microsoft.AspNetCore.Sockets.Tests.csproj
+++ b/test/Microsoft.AspNetCore.Sockets.Tests/Microsoft.AspNetCore.Sockets.Tests.csproj
@@ -8,7 +8,6 @@
-
diff --git a/test/Microsoft.AspNetCore.Sockets.Tests/ServerSentEventsMessageFormatterTests.cs b/test/Microsoft.AspNetCore.Sockets.Tests/ServerSentEventsMessageFormatterTests.cs
index d5c7d739cc..44c7939720 100644
--- a/test/Microsoft.AspNetCore.Sockets.Tests/ServerSentEventsMessageFormatterTests.cs
+++ b/test/Microsoft.AspNetCore.Sockets.Tests/ServerSentEventsMessageFormatterTests.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.IO;
using System.Text;
using Microsoft.AspNetCore.Sockets.Internal.Formatters;
using Xunit;
@@ -19,7 +20,7 @@ namespace Microsoft.AspNetCore.Sockets.Tests.Internal.Formatters
[InlineData("data: Hello\r\ndata: \r\n\r\n", "Hello\r\n")]
public void WriteTextMessage(string encoded, string payload)
{
- var output = new ArrayOutput(chunkSize: 8); // Use small chunks to test Advance/Enlarge and partial payload writing
+ var output = new MemoryStream();
Assert.True(ServerSentEventsMessageFormatter.TryWriteMessage(Encoding.UTF8.GetBytes(payload), output));
Assert.Equal(encoded, Encoding.UTF8.GetString(output.ToArray()));