ChunkStream.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. //
  2. // System.Net.ChunkStream
  3. //
  4. // Authors:
  5. // Gonzalo Paniagua Javier ([email protected])
  6. //
  7. // (C) 2003 Ximian, Inc (http://www.ximian.com)
  8. //
  9. using System.Globalization;
  10. using System.IO;
  11. using System.Text;
  12. namespace System.Net
  13. {
  14. class ChunkStream
  15. {
  16. enum State {
  17. None,
  18. Body,
  19. BodyFinished,
  20. Trailer
  21. }
  22. MemoryStream ms;
  23. WebHeaderCollection headers;
  24. int chunkSize;
  25. int chunkRead;
  26. State state;
  27. //byte [] waitBuffer;
  28. StringBuilder saved;
  29. bool sawCR;
  30. bool gotit;
  31. long readPosition;
  32. public ChunkStream (byte [] buffer, int offset, int size, WebHeaderCollection headers)
  33. {
  34. this.headers = headers;
  35. ms = new MemoryStream ();
  36. saved = new StringBuilder ();
  37. chunkSize = -1;
  38. if (offset < size)
  39. Write (buffer, offset, size);
  40. }
  41. public void ResetBuffer ()
  42. {
  43. ms.SetLength (0);
  44. readPosition = 0;
  45. chunkSize = -1;
  46. chunkRead = 0;
  47. }
  48. public void WriteAndReadBack (byte [] buffer, int offset, int size, ref int read)
  49. {
  50. Write (buffer, offset, read);
  51. read = Read (buffer, offset, size);
  52. }
  53. public int Read (byte [] buffer, int offset, int size)
  54. {
  55. ms.Position = readPosition;
  56. int r = ms.Read (buffer, offset, size);
  57. readPosition += r;
  58. ms.Position = ms.Length;
  59. return r;
  60. }
  61. public void Write (byte [] buffer, int offset, int size)
  62. {
  63. InternalWrite (buffer, ref offset, size);
  64. }
  65. void InternalWrite (byte [] buffer, ref int offset, int size)
  66. {
  67. if (state == State.None) {
  68. state = GetChunkSize (buffer, ref offset, size);
  69. if (state == State.None)
  70. return;
  71. saved.Length = 0;
  72. sawCR = false;
  73. gotit = false;
  74. }
  75. if (state == State.Body && offset < size) {
  76. state = ReadBody (buffer, ref offset, size);
  77. if (state == State.Body)
  78. return;
  79. }
  80. if (state == State.BodyFinished && offset < size) {
  81. state = ReadCRLF (buffer, ref offset, size);
  82. if (state == State.BodyFinished)
  83. return;
  84. sawCR = false;
  85. }
  86. if (state == State.Trailer && offset < size) {
  87. state = ReadTrailer (buffer, ref offset, size);
  88. if (state == State.Trailer)
  89. return;
  90. saved.Length = 0;
  91. sawCR = false;
  92. gotit = false;
  93. }
  94. if (offset < size)
  95. InternalWrite (buffer, ref offset, size);
  96. }
  97. public bool WantMore {
  98. get { return (chunkRead != chunkSize || chunkSize != 0); }
  99. }
  100. public bool EOF {
  101. get { return (Available == 0); }
  102. }
  103. public int Available {
  104. get { return (int) (ms.Length - readPosition); }
  105. }
  106. State ReadBody (byte [] buffer, ref int offset, int size)
  107. {
  108. if (chunkSize == 0)
  109. return State.BodyFinished;
  110. int diff = size - offset;
  111. if (diff + chunkRead > chunkSize)
  112. diff = chunkSize - chunkRead;
  113. ms.Write (buffer, offset, diff);
  114. offset += diff;
  115. chunkRead += diff;
  116. return (chunkRead == chunkSize) ? State.BodyFinished : State.Body;
  117. }
  118. State GetChunkSize (byte [] buffer, ref int offset, int size)
  119. {
  120. char c = '\0';
  121. while (offset < size) {
  122. c = (char) buffer [offset++];
  123. if (c == '\r') {
  124. if (sawCR)
  125. throw new ProtocolViolationException ("2 CR found");
  126. sawCR = true;
  127. continue;
  128. }
  129. if (sawCR && c == '\n')
  130. break;
  131. if (c == ' ')
  132. gotit = true;
  133. if (!gotit)
  134. saved.Append (c);
  135. }
  136. if (!sawCR || c != '\n')
  137. return State.None;
  138. chunkRead = 0;
  139. chunkSize = Int32.Parse (saved.ToString (), NumberStyles.HexNumber);
  140. if (chunkSize == 0)
  141. return State.Trailer;
  142. return State.Body;
  143. }
  144. State ReadCRLF (byte [] buffer, ref int offset, int size)
  145. {
  146. if (!sawCR) {
  147. if ((char) buffer [offset++] != '\r')
  148. throw new ProtocolViolationException ("Expecting \\r");
  149. sawCR = true;
  150. if (offset == size)
  151. return State.BodyFinished;
  152. }
  153. if ((char) buffer [offset++] != '\n')
  154. throw new ProtocolViolationException ("Expecting \\n");
  155. return State.None;
  156. }
  157. State ReadTrailer (byte [] buffer, ref int offset, int size)
  158. {
  159. char c = '\0';
  160. // short path
  161. if ((char) buffer [offset] == '\r') {
  162. offset++;
  163. if ((char) buffer [offset] == '\n') {
  164. offset++;
  165. return State.None;
  166. }
  167. offset--;
  168. }
  169. int st = 0;
  170. string stString = "\r\n\r";
  171. while (offset < size && st < 4) {
  172. c = (char) buffer [offset++];
  173. if ((st == 0 || st == 2) && c == '\r') {
  174. st++;
  175. continue;
  176. }
  177. if ((st == 1 || st == 3) && c == '\n') {
  178. st++;
  179. continue;
  180. }
  181. if (st > 0) {
  182. saved.Append (stString.Substring (0, st));
  183. st = 0;
  184. }
  185. }
  186. if (st < 4)
  187. return State.Trailer;
  188. StringReader reader = new StringReader (saved.ToString ());
  189. string line;
  190. while ((line = reader.ReadLine ()) != null && line != "")
  191. headers.Add (line);
  192. return State.None;
  193. }
  194. }
  195. }