Refactored ChunkedInputStream.cs
This commit is contained in:
		| @@ -1,115 +1,117 @@ | ||||
| // | ||||
| // 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 <gonzalo@novell.com> | ||||
|  */ | ||||
| #endregion | ||||
|  | ||||
| using System; | ||||
| using System.IO; | ||||
| using System.Runtime.InteropServices; | ||||
|  | ||||
| namespace WebSocketSharp.Net { | ||||
|  | ||||
| 	class ChunkedInputStream : RequestStream { | ||||
|  | ||||
| 		class ReadBufferState { | ||||
|  | ||||
| 			public HttpStreamAsyncResult Ares; | ||||
| 			public byte []               Buffer; | ||||
| 			public int                   Count; | ||||
| 			public int                   InitialCount; | ||||
| 			public int                   Offset; | ||||
|  | ||||
| 			public ReadBufferState ( | ||||
| 				byte [] buffer, int offset, int count, HttpStreamAsyncResult ares) | ||||
| namespace WebSocketSharp.Net | ||||
| { | ||||
| 				Buffer = buffer; | ||||
| 				Offset = offset; | ||||
| 				Count = count; | ||||
| 				InitialCount = count; | ||||
| 				Ares = ares; | ||||
| 			} | ||||
| 		} | ||||
|   internal class ChunkedInputStream : RequestStream | ||||
|   { | ||||
|     #region Private Const Fields | ||||
|  | ||||
| 		#region Fields | ||||
|  | ||||
| 		HttpListenerContext context; | ||||
| 		ChunkStream         decoder; | ||||
| 		bool                disposed; | ||||
| 		bool                no_more_data; | ||||
|     private const int _bufferSize = 8192; | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
| 		#region Constructor | ||||
|     #region Private Fields | ||||
|  | ||||
|     private HttpListenerContext _context; | ||||
|     private ChunkStream         _decoder; | ||||
|     private bool                _disposed; | ||||
|     private bool                _noMoreData; | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
|     #region Public Constructors | ||||
|  | ||||
|     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); | ||||
|       _context = context; | ||||
|       _decoder = new ChunkStream ((WebHeaderCollection) context.Request.Headers); | ||||
|     } | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
| 		#region Property | ||||
|     #region Public Properties | ||||
|  | ||||
|     public ChunkStream Decoder { | ||||
| 			get { return decoder; } | ||||
| 			set { decoder = value; } | ||||
|       get { | ||||
|         return _decoder; | ||||
|       } | ||||
|  | ||||
|       set { | ||||
|         _decoder = value; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
| 		#region Private Method | ||||
|     #region Private Methods | ||||
|  | ||||
| 		void OnRead (IAsyncResult base_ares) | ||||
|     private void onRead (IAsyncResult asyncResult) | ||||
|     { | ||||
| 			var rb = (ReadBufferState) base_ares.AsyncState; | ||||
| 			var ares = rb.Ares; | ||||
|       var readState = (ReadBufferState) asyncResult.AsyncState; | ||||
|       var ares = readState.AsyncResult; | ||||
|       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; | ||||
|         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 (); | ||||
|  | ||||
|           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.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); | ||||
|       } | ||||
|     } | ||||
|  | ||||
| @@ -118,15 +120,15 @@ namespace WebSocketSharp.Net { | ||||
|     #region Public Methods | ||||
|  | ||||
|     public override IAsyncResult BeginRead ( | ||||
| 			byte [] buffer, int offset, int count, AsyncCallback cback, object state) | ||||
|       byte [] buffer, int offset, int count, AsyncCallback callback, object state) | ||||
|     { | ||||
| 			if (disposed) | ||||
|       if (_disposed) | ||||
|         throw new ObjectDisposedException (GetType ().ToString ()); | ||||
|  | ||||
|       if (buffer == null) | ||||
|         throw new ArgumentNullException ("buffer"); | ||||
|  | ||||
| 			int len = buffer.Length; | ||||
|       var len = buffer.Length; | ||||
|       if (offset < 0 || offset > len) | ||||
|         throw new ArgumentOutOfRangeException ("'offset' exceeds the size of buffer."); | ||||
|  | ||||
| @@ -134,66 +136,74 @@ namespace WebSocketSharp.Net { | ||||
|         throw new ArgumentOutOfRangeException ("'offset' + 'count' exceeds the size of buffer."); | ||||
|  | ||||
|       var ares = new HttpStreamAsyncResult (); | ||||
| 			ares.Callback = cback; | ||||
|       ares.Callback = callback; | ||||
|       ares.State = state; | ||||
| 			if (no_more_data) { | ||||
|       if (_noMoreData) { | ||||
|         ares.Complete (); | ||||
|         return ares; | ||||
|       } | ||||
|  | ||||
| 			int nread = decoder.Read (buffer, offset, count); | ||||
|       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 | ||||
|         // Got all we wanted, no need to bother the decoder yet. | ||||
|         ares.Count = nread; | ||||
|         ares.Complete (); | ||||
|  | ||||
|         return ares; | ||||
|       } | ||||
|  | ||||
| 			if (!decoder.WantMore) { | ||||
| 				no_more_data = nread == 0; | ||||
|       if (!_decoder.WantMore) { | ||||
|         _noMoreData = nread == 0; | ||||
|         ares.Count = nread; | ||||
|         ares.Complete (); | ||||
|  | ||||
|         return ares; | ||||
|       } | ||||
|  | ||||
| 			ares.Buffer = new byte [8192]; | ||||
|       ares.Buffer = new byte [_bufferSize]; | ||||
|       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); | ||||
|       ares.Count = _bufferSize; | ||||
|  | ||||
|       var readState = new ReadBufferState (buffer, offset, count, ares); | ||||
|       readState.InitialCount += nread; | ||||
|       base.BeginRead (ares.Buffer, ares.Offset, ares.Count, onRead, readState); | ||||
|  | ||||
|       return ares; | ||||
|     } | ||||
|  | ||||
|     public override void Close () | ||||
|     { | ||||
| 			if (!disposed) { | ||||
| 				disposed = true; | ||||
|       if (_disposed) | ||||
|         return; | ||||
|  | ||||
|       _disposed = true; | ||||
|       base.Close (); | ||||
|     } | ||||
| 		} | ||||
|  | ||||
| 		public override int EndRead (IAsyncResult ares) | ||||
|     public override int EndRead (IAsyncResult asyncResult) | ||||
|     { | ||||
| 			if (disposed) | ||||
|       if (_disposed) | ||||
|         throw new ObjectDisposedException (GetType ().ToString ()); | ||||
|  | ||||
|       if (asyncResult == null) | ||||
|         throw new ArgumentNullException ("asyncResult"); | ||||
|  | ||||
|       var ares = asyncResult as HttpStreamAsyncResult; | ||||
|       if (ares == null) | ||||
| 				throw new ArgumentException ("Invalid IAsyncResult.", "ares"); | ||||
|         throw new ArgumentException ("Wrong IAsyncResult.", "asyncResult"); | ||||
|  | ||||
|       if (!ares.IsCompleted) | ||||
|         ares.AsyncWaitHandle.WaitOne (); | ||||
|  | ||||
| 			var ares_ = ares as HttpStreamAsyncResult; | ||||
| 			if (ares_.Error != null) | ||||
|       if (ares.Error != null) | ||||
|         throw new HttpListenerException (400, "I/O operation aborted."); | ||||
|  | ||||
| 			return ares_.Count; | ||||
|       return ares.Count; | ||||
|     } | ||||
|  | ||||
| 		public override int Read ([In,Out] byte [] buffer, int offset, int count) | ||||
|     public override int Read (byte [] buffer, int offset, int count) | ||||
|     { | ||||
|       var ares = BeginRead (buffer, offset, count, null, null); | ||||
|       return EndRead (ares); | ||||
|   | ||||
							
								
								
									
										84
									
								
								websocket-sharp/Net/ReadBufferState.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								websocket-sharp/Net/ReadBufferState.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <gonzalo@novell.com> | ||||
|  */ | ||||
| #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 | ||||
|   } | ||||
| } | ||||
| @@ -131,6 +131,7 @@ | ||||
|     <Compile Include="Net\InputState.cs" /> | ||||
|     <Compile Include="Net\LineState.cs" /> | ||||
|     <Compile Include="WebSocketStream.cs" /> | ||||
|     <Compile Include="Net\ReadBufferState.cs" /> | ||||
|   </ItemGroup> | ||||
|   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> | ||||
|   <ItemGroup> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user