From a55be214693c1ceaccd9e3c327f53b9a62a52297 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Tue, 1 Dec 2015 04:36:23 +0000 Subject: [PATCH 1/2] Empty buffer when null buffer --- .../Filter/StreamSocketOutput.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.AspNet.Server.Kestrel/Filter/StreamSocketOutput.cs b/src/Microsoft.AspNet.Server.Kestrel/Filter/StreamSocketOutput.cs index e990e34ee..d2c1deae3 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Filter/StreamSocketOutput.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Filter/StreamSocketOutput.cs @@ -12,6 +12,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Filter { public class StreamSocketOutput : ISocketOutput { + private static readonly byte[] _nullBuffer = new byte[0]; + private readonly Stream _outputStream; private readonly MemoryPool2 _memory; private MemoryPoolBlock2 _producingBlock; @@ -24,13 +26,13 @@ public StreamSocketOutput(Stream outputStream, MemoryPool2 memory) void ISocketOutput.Write(ArraySegment buffer, bool immediate) { - _outputStream.Write(buffer.Array, buffer.Offset, buffer.Count); + _outputStream.Write(buffer.Array ?? _nullBuffer, buffer.Offset, buffer.Count); } Task ISocketOutput.WriteAsync(ArraySegment buffer, bool immediate, CancellationToken cancellationToken) { // TODO: Use _outputStream.WriteAsync - _outputStream.Write(buffer.Array, buffer.Offset, buffer.Count); + _outputStream.Write(buffer.Array ?? _nullBuffer, buffer.Offset, buffer.Count); return TaskUtilities.CompletedTask; } From a85f37697c1b689fda9f4484b014338af18d9898 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Wed, 2 Dec 2015 21:01:08 +0000 Subject: [PATCH 2/2] Add SSL+Upgrade regression test --- .../StreamSocketOutputTests.cs | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 test/Microsoft.AspNet.Server.KestrelTests/StreamSocketOutputTests.cs diff --git a/test/Microsoft.AspNet.Server.KestrelTests/StreamSocketOutputTests.cs b/test/Microsoft.AspNet.Server.KestrelTests/StreamSocketOutputTests.cs new file mode 100644 index 000000000..7b19bf617 --- /dev/null +++ b/test/Microsoft.AspNet.Server.KestrelTests/StreamSocketOutputTests.cs @@ -0,0 +1,106 @@ +// 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.IO; +using Microsoft.AspNet.Server.Kestrel.Filter; +using Microsoft.AspNet.Server.Kestrel.Http; +using Xunit; + +namespace Microsoft.AspNet.Server.KestrelTests +{ + public class StreamSocketOutputTests + { + [Fact] + public void DoesNotThrowForNullBuffers() + { + // This test was added because SslStream throws if passed null buffers with (count == 0) + // Which happens if ProduceEnd is called in Frame without _responseStarted == true + // As it calls ProduceStart with write immediate == true + // This happens in WebSocket Upgrade over SSL + + ISocketOutput socketOutput = new StreamSocketOutput(new ThrowsOnNullWriteStream(), null); + + // Should not throw + socketOutput.Write(default(ArraySegment), true); + + Assert.True(true); + } + + private class ThrowsOnNullWriteStream : Stream + { + public override bool CanRead + { + get + { + throw new NotImplementedException(); + } + } + + public override bool CanSeek + { + get + { + throw new NotImplementedException(); + } + } + + public override bool CanWrite + { + get + { + throw new NotImplementedException(); + } + } + + public override long Length + { + get + { + throw new NotImplementedException(); + } + } + + public override long Position + { + get + { + throw new NotImplementedException(); + } + + set + { + throw new NotImplementedException(); + } + } + + public override void Flush() + { + throw new NotImplementedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + } + } + } +}