Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Made some changes to better abstract BufferTextWriter.

- Added BinaryTextWriter which is a buffer text writer that supports writing array segments.
- Updated tests.
- Added tests for forever frame encoding full messages.
  • Loading branch information...
commit bc9412bcab0f5ef097c7dc919e3ea1b37fc8718c 1 parent a02bb72
@davidfowl davidfowl authored
View
34 src/Microsoft.AspNet.SignalR.Core/Infrastructure/BinaryTextWriter.cs
@@ -0,0 +1,34 @@
+using System;
+using Microsoft.AspNet.SignalR.Hosting;
+
+namespace Microsoft.AspNet.SignalR.Infrastructure
+{
+ /// <summary>
+ /// A buffering text writer that supports writing binary directly as well
+ /// </summary>
+ internal unsafe class BinaryTextWriter : BufferTextWriter, IBinaryWriter
+ {
+ public BinaryTextWriter(IResponse response) :
+ base((data, state) => ((IResponse)state).Write(data), response, reuseBuffers: true, bufferSize: 128)
+ {
+
+ }
+
+ public BinaryTextWriter(IWebSocket socket) :
+ base((data, state) => ((IWebSocket)state).SendChunk(data), socket, reuseBuffers: false, bufferSize: 1024)
+ {
+
+ }
+
+
+ public BinaryTextWriter(Action<ArraySegment<byte>, object> write, object state, bool reuseBuffers, int bufferSize) :
+ base(write, state, reuseBuffers, bufferSize)
+ {
+ }
+
+ public void Write(ArraySegment<byte> data)
+ {
+ Writer.Write(data);
+ }
+ }
+}
View
13 src/Microsoft.AspNet.SignalR.Core/Infrastructure/BufferTextWriter.cs
@@ -13,7 +13,7 @@ namespace Microsoft.AspNet.SignalR.Infrastructure
/// we don't need to write to a long lived buffer. This saves massive amounts of memory
/// as the number of connections grows.
/// </summary>
- internal unsafe class BufferTextWriter : TextWriter, IBinaryWriter
+ internal abstract unsafe class BufferTextWriter : TextWriter
{
private readonly Encoding _encoding;
@@ -37,7 +37,7 @@ internal unsafe class BufferTextWriter : TextWriter, IBinaryWriter
}
[SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.IO.TextWriter.#ctor", Justification = "It won't be used")]
- public BufferTextWriter(Action<ArraySegment<byte>, object> write, object state, bool reuseBuffers, int bufferSize)
+ protected BufferTextWriter(Action<ArraySegment<byte>, object> write, object state, bool reuseBuffers, int bufferSize)
{
_write = write;
_writeState = state;
@@ -46,7 +46,7 @@ public BufferTextWriter(Action<ArraySegment<byte>, object> write, object state,
_bufferSize = bufferSize;
}
- private ChunkedWriter Writer
+ protected internal ChunkedWriter Writer
{
get
{
@@ -79,17 +79,12 @@ public override void Write(char value)
Writer.Write(value);
}
- public void Write(ArraySegment<byte> data)
- {
- Writer.Write(data);
- }
-
public override void Flush()
{
Writer.Flush();
}
- private class ChunkedWriter
+ internal class ChunkedWriter
{
private int _charPos;
private int _charLen;
View
2  src/Microsoft.AspNet.SignalR.Core/Infrastructure/Connection.cs
@@ -218,7 +218,7 @@ private ArraySegment<byte> SerializeMessageValue(object value)
{
using (var stream = new MemoryStream(128))
{
- var bufferWriter = new BufferTextWriter((buffer, state) =>
+ var bufferWriter = new BinaryTextWriter((buffer, state) =>
{
((MemoryStream)state).Write(buffer.Array, buffer.Offset, buffer.Count);
},
View
1  src/Microsoft.AspNet.SignalR.Core/Microsoft.AspNet.SignalR.Core.csproj
@@ -92,6 +92,7 @@
<Compile Include="Infrastructure\AckHandler.cs" />
<Compile Include="Configuration\DefaultConfigurationManager.cs" />
<Compile Include="Infrastructure\ArraySegmentTextReader.cs" />
+ <Compile Include="Infrastructure\BinaryTextWriter.cs" />
<Compile Include="Infrastructure\ConnectionManager.cs" />
<Compile Include="ConnectionMessage.cs" />
<Compile Include="Infrastructure\DataProtectionProviderProtectedData.cs" />
View
2  src/Microsoft.AspNet.SignalR.Core/Transports/PersistentResponse.cs
@@ -20,7 +20,7 @@ public sealed class PersistentResponse : IJsonWritable
private readonly Action<TextWriter> _writeCursor;
public PersistentResponse()
- : this(message => true, writer => { })
+ : this(message => false, writer => { })
{
}
View
2  src/Microsoft.AspNet.SignalR.Core/Transports/TransportDisconnectBase.cs
@@ -208,7 +208,7 @@ public Uri Url
protected virtual TextWriter CreateResponseWriter()
{
- return new BufferTextWriter(Context.Response);
+ return new BinaryTextWriter(Context.Response);
}
protected void IncrementErrors()
View
2  src/Microsoft.AspNet.SignalR.Core/Transports/WebSocketTransport.cs
@@ -99,7 +99,7 @@ public override Task ProcessRequest(ITransportConnection connection)
protected override TextWriter CreateResponseWriter()
{
- return new BufferTextWriter(_socket);
+ return new BinaryTextWriter(_socket);
}
public override Task Send(object value)
View
10 tests/Microsoft.AspNet.SignalR.Tests/BufferTextWriterFacts.cs
@@ -13,7 +13,7 @@ public class BufferTextWriterFacts
public void CanEncodingSurrogatePairsCorrectly()
{
var bytes = new List<byte>();
- var writer = new BufferTextWriter((buffer, state) =>
+ var writer = new BinaryTextWriter((buffer, state) =>
{
for (int i = buffer.Offset; i < buffer.Count; i++)
{
@@ -34,7 +34,7 @@ public void CanEncodingSurrogatePairsCorrectly()
public void WriteNewBufferIsUsedForWritingChunksIfReuseBuffersFalse()
{
var buffers = new List<ArraySegment<byte>>();
- var writer = new BufferTextWriter((buffer, state) =>
+ var writer = new BinaryTextWriter((buffer, state) =>
{
buffers.Add(buffer);
},
@@ -55,7 +55,7 @@ public void WriteNewBufferIsUsedForWritingChunksIfReuseBuffersFalse()
public void WriteSameBufferIsUsedForWritingChunksIfReuseBuffersTrue()
{
var buffers = new List<ArraySegment<byte>>();
- var writer = new BufferTextWriter((buffer, state) =>
+ var writer = new BinaryTextWriter((buffer, state) =>
{
buffers.Add(buffer);
},
@@ -79,7 +79,7 @@ public void WritesInChunks()
int size = 3000;
var buffers = new List<ArraySegment<byte>>();
- var writer = new BufferTextWriter((buffer, state) =>
+ var writer = new BinaryTextWriter((buffer, state) =>
{
buffers.Add(buffer);
},
@@ -121,7 +121,7 @@ private IEnumerable<int> GetChunks(int size, int bufferSize)
public void CanInterleaveStringsAndRawBinary()
{
var buffers = new List<ArraySegment<byte>>();
- var writer = new BufferTextWriter((buffer, state) =>
+ var writer = new BinaryTextWriter((buffer, state) =>
{
buffers.Add(buffer);
},
View
47 tests/Microsoft.AspNet.SignalR.Tests/Core/Transports/ForeverFrameTransportFacts.cs
@@ -1,9 +1,12 @@
using System;
+using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Hosting;
+using Microsoft.AspNet.SignalR.Messaging;
using Microsoft.AspNet.SignalR.Tests.Common.Infrastructure;
using Microsoft.AspNet.SignalR.Transports;
using Moq;
@@ -14,17 +17,31 @@ namespace Microsoft.AspNet.SignalR.Tests.Core
{
public class ForeverFrameTransportFacts
{
- [Fact]
- public void ForeverFrameTransportEscapesTags()
+ [Theory]
+ [InlineData("</sCRiPT>", "\\u003c/sCRiPT\\u003e")]
+ [InlineData("</SCRIPT dosomething='false'>", "\\u003c/SCRIPT dosomething='false'\\u003e")]
+ [InlineData("<p>ELLO</p>", "\\u003cp\\u003eELLO\\u003c/p\\u003e")]
+ public void ForeverFrameTransportEscapesTags(string data, string expected)
+ {
+ var request = new Mock<IRequest>();
+ var response = new CustomResponse();
+ var context = new HostContext(request.Object, response);
+ var fft = new ForeverFrameTransport(context, new DefaultDependencyResolver());
+
+ AssertEscaped(fft, response, data, expected);
+ }
+
+ [Theory]
+ [InlineData("<script type=\"\"></script>", "\\u003cscript type=\"\"\\u003e\\u003c/script\\u003e")]
+ [InlineData("<script type=''></script>", "\\u003cscript type=''\\u003e\\u003c/script\\u003e")]
+ public void ForeverFrameTransportEscapesTagsWithPersistentResponse(string data, string expected)
{
var request = new Mock<IRequest>();
var response = new CustomResponse();
var context = new HostContext(request.Object, response);
var fft = new ForeverFrameTransport(context, new DefaultDependencyResolver());
- AssertEscaped(fft, response, "</sCRiPT>", "\\u003c/sCRiPT\\u003e");
- AssertEscaped(fft, response, "</SCRIPT dosomething='false'>", "\\u003c/SCRIPT dosomething='false'\\u003e");
- AssertEscaped(fft, response, "<p>ELLO</p>", "\\u003cp\\u003eELLO\\u003c/p\\u003e");
+ AssertEscaped(fft, response, GetWrappedResponse(data), expected);
}
[Theory]
@@ -43,7 +60,7 @@ public void ForeverFrameTransportThrowsOnInvalidFrameId(string frameId)
var context = new HostContext(request.Object, response);
var connection = new Mock<ITransportConnection>();
var fft = new ForeverFrameTransport(context, new DefaultDependencyResolver());
-
+
Assert.Throws(typeof(InvalidOperationException), () => fft.InitializeResponse(connection.Object));
}
@@ -63,7 +80,7 @@ public void ForeverFrameTransportSetsCorrectContentType()
Assert.Equal("text/html; charset=UTF-8", response.ContentType);
}
- private static void AssertEscaped(ForeverFrameTransport fft, CustomResponse response, string input, string expectedOutput)
+ private static void AssertEscaped(ForeverFrameTransport fft, CustomResponse response, object input, string expectedOutput)
{
fft.Send(input).Wait();
@@ -74,6 +91,22 @@ private static void AssertEscaped(ForeverFrameTransport fft, CustomResponse resp
Assert.True(rawResponse.Contains(expectedOutput));
}
+ private static PersistentResponse GetWrappedResponse(string raw)
+ {
+ var data = Encoding.Default.GetBytes(raw);
+ var message = new Message("foo", "key", new ArraySegment<byte>(data));
+
+ var response = new PersistentResponse
+ {
+ Messages = new List<ArraySegment<Message>>
+ {
+ new ArraySegment<Message>(new Message[] { message })
+ }
+ };
+
+ return response;
+ }
+
private class CustomResponse : IResponse
{
private MemoryStream _stream;
Please sign in to comment.
Something went wrong with that request. Please try again.