diff --git a/websocket-sharp/Net/ChunkedInputStream.cs b/websocket-sharp/Net/ChunkedInputStream.cs index 1797dbc4..f2452401 100644 --- a/websocket-sharp/Net/ChunkedInputStream.cs +++ b/websocket-sharp/Net/ChunkedInputStream.cs @@ -1,204 +1,214 @@ -// -// ChunkedInputStream.cs -// Copied from System.Net.ChunkedInputStream.cs -// -// Authors: -// Gonzalo Paniagua Javier (gonzalo@novell.com) -// -// Copyright (c) 2005 Novell, Inc (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// +#region License +/* + * ChunkedInputStream.cs + * + * This code is derived from System.Net.ChunkedInputStream.cs of Mono + * (http://www.mono-project.com). + * + * The MIT License + * + * Copyright (c) 2005 Novell, Inc. (http://www.novell.com) + * Copyright (c) 2012-2014 sta.blockhead + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#endregion + +#region Authors +/* + * Authors: + * - Gonzalo Paniagua Javier + */ +#endregion using System; using System.IO; -using System.Runtime.InteropServices; -namespace WebSocketSharp.Net { +namespace WebSocketSharp.Net +{ + internal class ChunkedInputStream : RequestStream + { + #region Private Const Fields - class ChunkedInputStream : RequestStream { + private const int _bufferSize = 8192; - class ReadBufferState { + #endregion - public HttpStreamAsyncResult Ares; - public byte [] Buffer; - public int Count; - public int InitialCount; - public int Offset; + #region Private Fields - public ReadBufferState ( - byte [] buffer, int offset, int count, HttpStreamAsyncResult ares) - { - Buffer = buffer; - Offset = offset; - Count = count; - InitialCount = count; - Ares = ares; - } - } + private HttpListenerContext _context; + private ChunkStream _decoder; + private bool _disposed; + private bool _noMoreData; - #region Fields + #endregion - HttpListenerContext context; - ChunkStream decoder; - bool disposed; - bool no_more_data; + #region Public Constructors - #endregion + public ChunkedInputStream ( + HttpListenerContext context, Stream stream, byte [] buffer, int offset, int length) + : base (stream, buffer, offset, length) + { + _context = context; + _decoder = new ChunkStream ((WebHeaderCollection) context.Request.Headers); + } - #region Constructor + #endregion - public ChunkedInputStream ( - HttpListenerContext context, Stream stream, byte [] buffer, int offset, int length) - : base (stream, buffer, offset, length) - { - this.context = context; - WebHeaderCollection coll = (WebHeaderCollection) context.Request.Headers; - decoder = new ChunkStream (coll); - } + #region Public Properties - #endregion + public ChunkStream Decoder { + get { + return _decoder; + } - #region Property + set { + _decoder = value; + } + } - public ChunkStream Decoder { - get { return decoder; } - set { decoder = value; } - } + #endregion - #endregion + #region Private Methods - #region Private Method + private void onRead (IAsyncResult asyncResult) + { + var readState = (ReadBufferState) asyncResult.AsyncState; + var ares = readState.AsyncResult; + try { + var nread = base.EndRead (asyncResult); + _decoder.Write (ares.Buffer, ares.Offset, nread); + nread = _decoder.Read (readState.Buffer, readState.Offset, readState.Count); + readState.Offset += nread; + readState.Count -= nread; + if (readState.Count == 0 || !_decoder.WantMore || nread == 0) { + _noMoreData = !_decoder.WantMore && nread == 0; + ares.Count = readState.InitialCount - readState.Count; + ares.Complete (); - void OnRead (IAsyncResult base_ares) - { - var rb = (ReadBufferState) base_ares.AsyncState; - var ares = rb.Ares; - try { - int nread = base.EndRead (base_ares); - decoder.Write (ares.Buffer, ares.Offset, nread); - nread = decoder.Read (rb.Buffer, rb.Offset, rb.Count); - rb.Offset += nread; - rb.Count -= nread; - if (rb.Count == 0 || !decoder.WantMore || nread == 0) { - no_more_data = !decoder.WantMore && nread == 0; - ares.Count = rb.InitialCount - rb.Count; - ares.Complete (); - return; - } + return; + } - ares.Offset = 0; - ares.Count = Math.Min (8192, decoder.ChunkLeft + 6); - base.BeginRead (ares.Buffer, ares.Offset, ares.Count, OnRead, rb); - } catch (Exception e) { - context.Connection.SendError (e.Message, 400); - ares.Complete (e); - } - } + ares.Offset = 0; + ares.Count = Math.Min (_bufferSize, _decoder.ChunkLeft + 6); + base.BeginRead (ares.Buffer, ares.Offset, ares.Count, onRead, readState); + } + catch (Exception ex) { + _context.Connection.SendError (ex.Message, 400); + ares.Complete (ex); + } + } - #endregion + #endregion - #region Public Methods + #region Public Methods - public override IAsyncResult BeginRead ( - byte [] buffer, int offset, int count, AsyncCallback cback, object state) - { - if (disposed) - throw new ObjectDisposedException (GetType ().ToString ()); + public override IAsyncResult BeginRead ( + byte [] buffer, int offset, int count, AsyncCallback callback, object state) + { + if (_disposed) + throw new ObjectDisposedException (GetType ().ToString ()); - if (buffer == null) - throw new ArgumentNullException ("buffer"); + if (buffer == null) + throw new ArgumentNullException ("buffer"); - int len = buffer.Length; - if (offset < 0 || offset > len) - throw new ArgumentOutOfRangeException ("'offset' exceeds the size of buffer."); + var len = buffer.Length; + if (offset < 0 || offset > len) + throw new ArgumentOutOfRangeException ("'offset' exceeds the size of buffer."); - if (count < 0 || offset > len - count) - throw new ArgumentOutOfRangeException ("'offset' + 'count' exceeds the size of buffer."); + if (count < 0 || offset > len - count) + throw new ArgumentOutOfRangeException ("'offset' + 'count' exceeds the size of buffer."); - var ares = new HttpStreamAsyncResult (); - ares.Callback = cback; - ares.State = state; - if (no_more_data) { - ares.Complete (); - return ares; - } + var ares = new HttpStreamAsyncResult (); + ares.Callback = callback; + ares.State = state; + if (_noMoreData) { + ares.Complete (); + return ares; + } - int nread = decoder.Read (buffer, offset, count); - offset += nread; - count -= nread; - if (count == 0) { - // got all we wanted, no need to bother the decoder yet - ares.Count = nread; - ares.Complete (); - return ares; - } + var nread = _decoder.Read (buffer, offset, count); + offset += nread; + count -= nread; + if (count == 0) { + // Got all we wanted, no need to bother the decoder yet. + ares.Count = nread; + ares.Complete (); - if (!decoder.WantMore) { - no_more_data = nread == 0; - ares.Count = nread; - ares.Complete (); - return ares; - } + return ares; + } - ares.Buffer = new byte [8192]; - ares.Offset = 0; - ares.Count = 8192; - var rb = new ReadBufferState (buffer, offset, count, ares); - rb.InitialCount += nread; - base.BeginRead (ares.Buffer, ares.Offset, ares.Count, OnRead, rb); - return ares; - } + if (!_decoder.WantMore) { + _noMoreData = nread == 0; + ares.Count = nread; + ares.Complete (); - public override void Close () - { - if (!disposed) { - disposed = true; - base.Close (); - } - } + return ares; + } - public override int EndRead (IAsyncResult ares) - { - if (disposed) - throw new ObjectDisposedException (GetType ().ToString ()); + ares.Buffer = new byte [_bufferSize]; + ares.Offset = 0; + ares.Count = _bufferSize; - if (ares == null) - throw new ArgumentException ("Invalid IAsyncResult.", "ares"); + var readState = new ReadBufferState (buffer, offset, count, ares); + readState.InitialCount += nread; + base.BeginRead (ares.Buffer, ares.Offset, ares.Count, onRead, readState); - if (!ares.IsCompleted) - ares.AsyncWaitHandle.WaitOne (); + return ares; + } - var ares_ = ares as HttpStreamAsyncResult; - if (ares_.Error != null) - throw new HttpListenerException (400, "I/O operation aborted."); + public override void Close () + { + if (_disposed) + return; - return ares_.Count; - } + _disposed = true; + base.Close (); + } - public override int Read ([In,Out] byte [] buffer, int offset, int count) - { - var ares = BeginRead (buffer, offset, count, null, null); - return EndRead (ares); - } + public override int EndRead (IAsyncResult asyncResult) + { + if (_disposed) + throw new ObjectDisposedException (GetType ().ToString ()); - #endregion - } + if (asyncResult == null) + throw new ArgumentNullException ("asyncResult"); + + var ares = asyncResult as HttpStreamAsyncResult; + if (ares == null) + throw new ArgumentException ("Wrong IAsyncResult.", "asyncResult"); + + if (!ares.IsCompleted) + ares.AsyncWaitHandle.WaitOne (); + + if (ares.Error != null) + throw new HttpListenerException (400, "I/O operation aborted."); + + return ares.Count; + } + + public override int Read (byte [] buffer, int offset, int count) + { + var ares = BeginRead (buffer, offset, count, null, null); + return EndRead (ares); + } + + #endregion + } } diff --git a/websocket-sharp/Net/ReadBufferState.cs b/websocket-sharp/Net/ReadBufferState.cs new file mode 100644 index 00000000..0609c28c --- /dev/null +++ b/websocket-sharp/Net/ReadBufferState.cs @@ -0,0 +1,84 @@ +#region License +/* + * ReadBufferState.cs + * + * This code is derived from System.Net.ChunkedInputStream.cs of Mono + * (http://www.mono-project.com). + * + * The MIT License + * + * Copyright (c) 2005 Novell, Inc. (http://www.novell.com) + * Copyright (c) 2014 sta.blockhead + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#endregion + +#region Authors +/* + * Authors: + * - Gonzalo Paniagua Javier + */ +#endregion + +using System; + +namespace WebSocketSharp.Net +{ + internal class ReadBufferState + { + #region Public Constructors + + public ReadBufferState ( + byte [] buffer, int offset, int count, HttpStreamAsyncResult asyncResult) + { + Buffer = buffer; + Offset = offset; + Count = count; + InitialCount = count; + AsyncResult = asyncResult; + } + + #endregion + + #region Public Properties + + public HttpStreamAsyncResult AsyncResult { + get; set; + } + + public byte [] Buffer { + get; set; + } + + public int Count { + get; set; + } + + public int InitialCount { + get; set; + } + + public int Offset { + get; set; + } + + #endregion + } +} diff --git a/websocket-sharp/websocket-sharp.csproj b/websocket-sharp/websocket-sharp.csproj index 4819ec02..254816b1 100644 --- a/websocket-sharp/websocket-sharp.csproj +++ b/websocket-sharp/websocket-sharp.csproj @@ -131,6 +131,7 @@ +