ChunkedInputStream.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. //
  2. // ChunkedInputStream.cs
  3. // Copied from System.Net.ChunkedInputStream
  4. //
  5. // Authors:
  6. // Gonzalo Paniagua Javier (gonzalo@novell.com)
  7. //
  8. // Copyright (c) 2005 Novell, Inc (http://www.novell.com)
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. using System;
  29. using System.IO;
  30. using System.Net;
  31. using System.Net.Sockets;
  32. using System.Runtime.InteropServices;
  33. namespace WebSocketSharp.Net {
  34. class ChunkedInputStream : RequestStream
  35. {
  36. HttpListenerContext context;
  37. ChunkStream decoder;
  38. bool disposed;
  39. bool no_more_data;
  40. class ReadBufferState {
  41. public HttpStreamAsyncResult Ares;
  42. public byte [] Buffer;
  43. public int Count;
  44. public int InitialCount;
  45. public int Offset;
  46. public ReadBufferState (
  47. byte [] buffer, int offset, int count, HttpStreamAsyncResult ares)
  48. {
  49. Buffer = buffer;
  50. Offset = offset;
  51. Count = count;
  52. InitialCount = count;
  53. Ares = ares;
  54. }
  55. }
  56. public ChunkedInputStream (
  57. HttpListenerContext context, Stream stream, byte [] buffer, int offset, int length)
  58. : base (stream, buffer, offset, length)
  59. {
  60. this.context = context;
  61. WebHeaderCollection coll = (WebHeaderCollection) context.Request.Headers;
  62. decoder = new ChunkStream (coll);
  63. }
  64. public ChunkStream Decoder {
  65. get { return decoder; }
  66. set { decoder = value; }
  67. }
  68. void OnRead (IAsyncResult base_ares)
  69. {
  70. ReadBufferState rb = (ReadBufferState) base_ares.AsyncState;
  71. HttpStreamAsyncResult ares = rb.Ares;
  72. try {
  73. int nread = base.EndRead (base_ares);
  74. decoder.Write (ares.Buffer, ares.Offset, nread);
  75. nread = decoder.Read (rb.Buffer, rb.Offset, rb.Count);
  76. rb.Offset += nread;
  77. rb.Count -= nread;
  78. if (rb.Count == 0 || !decoder.WantMore || nread == 0) {
  79. no_more_data = !decoder.WantMore && nread == 0;
  80. ares.Count = rb.InitialCount - rb.Count;
  81. ares.Complete ();
  82. return;
  83. }
  84. ares.Offset = 0;
  85. ares.Count = Math.Min (8192, decoder.ChunkLeft + 6);
  86. base.BeginRead (ares.Buffer, ares.Offset, ares.Count, OnRead, rb);
  87. } catch (Exception e) {
  88. context.Connection.SendError (e.Message, 400);
  89. ares.Complete (e);
  90. }
  91. }
  92. public override IAsyncResult BeginRead (
  93. byte [] buffer, int offset, int count, AsyncCallback cback, object state)
  94. {
  95. if (disposed)
  96. throw new ObjectDisposedException (GetType ().ToString ());
  97. if (buffer == null)
  98. throw new ArgumentNullException ("buffer");
  99. int len = buffer.Length;
  100. if (offset < 0 || offset > len)
  101. throw new ArgumentOutOfRangeException ("offset exceeds the size of buffer");
  102. if (count < 0 || offset > len - count)
  103. throw new ArgumentOutOfRangeException ("offset+size exceeds the size of buffer");
  104. HttpStreamAsyncResult ares = new HttpStreamAsyncResult ();
  105. ares.Callback = cback;
  106. ares.State = state;
  107. if (no_more_data) {
  108. ares.Complete ();
  109. return ares;
  110. }
  111. int nread = decoder.Read (buffer, offset, count);
  112. offset += nread;
  113. count -= nread;
  114. if (count == 0) {
  115. // got all we wanted, no need to bother the decoder yet
  116. ares.Count = nread;
  117. ares.Complete ();
  118. return ares;
  119. }
  120. if (!decoder.WantMore) {
  121. no_more_data = nread == 0;
  122. ares.Count = nread;
  123. ares.Complete ();
  124. return ares;
  125. }
  126. ares.Buffer = new byte [8192];
  127. ares.Offset = 0;
  128. ares.Count = 8192;
  129. ReadBufferState rb = new ReadBufferState (buffer, offset, count, ares);
  130. rb.InitialCount += nread;
  131. base.BeginRead (ares.Buffer, ares.Offset, ares.Count, OnRead, rb);
  132. return ares;
  133. }
  134. public override void Close ()
  135. {
  136. if (!disposed) {
  137. disposed = true;
  138. base.Close ();
  139. }
  140. }
  141. public override int EndRead (IAsyncResult ares)
  142. {
  143. if (disposed)
  144. throw new ObjectDisposedException (GetType ().ToString ());
  145. HttpStreamAsyncResult my_ares = ares as HttpStreamAsyncResult;
  146. if (ares == null)
  147. throw new ArgumentException ("Invalid IAsyncResult", "ares");
  148. if (!ares.IsCompleted)
  149. ares.AsyncWaitHandle.WaitOne ();
  150. if (my_ares.Error != null)
  151. throw new HttpListenerException (400, "I/O operation aborted.");
  152. return my_ares.Count;
  153. }
  154. public override int Read ([In,Out] byte [] buffer, int offset, int count)
  155. {
  156. IAsyncResult ares = BeginRead (buffer, offset, count, null, null);
  157. return EndRead (ares);
  158. }
  159. }
  160. }