-
- }
-
- class HttpWebResponseStream : NetworkStream
- {
- bool disposed;
- bool chunked;
- int chunkSize;
- int chunkLeft;
- bool readingChunkSize;
- EventHandler onClose;
-
- public HttpWebResponseStream (Socket socket, EventHandler onClose)
- : base (socket, FileAccess.Read, false)
- {
- this.onClose = onClose;
- chunkSize = -1;
- chunkLeft = 0;
- }
-
- public bool Chunked {
- get { return chunked; }
- set { chunked = value; }
- }
-
- protected override void Dispose (bool disposing)
- {
- if (disposed)
- return;
-
- disposed = true;
- if (disposing) {
- /* This does not work !??
- if (Socket.Connected)
- Socket.Shutdown (SocketShutdown.Receive);
- */
-
- if (onClose != null)
- onClose (this, EventArgs.Empty);
- }
-
- onClose = null;
- base.Dispose (disposing);
- }
-
- void ReadChunkSize ()
- {
- bool cr = false;
- bool lf = false;
- int size = 0;
- // 8 hex digits should be enough
- for (int i = 0; i < 10; i++) {
- char c = Char.ToUpper ((char) ReadByte ());
- if (c == '\r') {
- if (!cr) {
- cr = true;
- continue;
- }
- throw new IOException ("Bad stream: 2 CR");
- }
-
- if (c == '\n' && cr == true) {
- if (!lf) {
- lf = true;
- break;
- }
-
- throw new IOException ("Bad stream: got LF but no CR");
- }
-
- if (i < 8 && ((c >= '0' && c <= '9') || c >= 'A' && c <= 'F')) {
- size = size << 4;
- if (c >= 'A' && c <= 'F')
- size += c - 'A' + 10;
- else
- size += c - '0';
- continue;
- }
-
- throw new IOException ("Bad stream: got " + c);
- }
-
- if (!cr || !lf)
- throw new IOException ("Bad stream: no CR or LF after chunk size");
-
- chunkSize = size;
- chunkLeft = size;
- }
-
- int GetMaxSizeFromChunkLeft (int requestedSize)
- {
- if (!chunked)
- return requestedSize;
-
- if (chunkSize == -1 || chunkLeft == 0) {
- lock (this) {
- if (chunkSize == -1 || chunkLeft == 0) {
- readingChunkSize = true;
- try {
- ReadChunkSize ();
- } finally {
- readingChunkSize = false;
- }
- }
- }
- }
-
- return (chunkLeft < requestedSize) ? chunkLeft : requestedSize;
- }
-
- public override IAsyncResult BeginRead (byte [] buffer, int offset, int size,
- AsyncCallback callback, object state)
- {
- CheckDisposed ();
- IAsyncResult retval;
-
- if (buffer == null)
- throw new ArgumentNullException ("buffer is null");
-
- int len = buffer.Length;
- if (offset < 0 || offset >= len)
- throw new ArgumentOutOfRangeException ("offset exceeds the size of buffer");
-
- if (offset + size < 0 || offset+size > len)
- throw new ArgumentOutOfRangeException ("offset+size exceeds the size of buffer");
-
- if (!readingChunkSize)
- size = GetMaxSizeFromChunkLeft (size);
-
- try {
- retval = base.BeginRead (buffer, offset, size, callback, state);
- } catch {
- throw new IOException ("BeginReceive failure");
- }
-
- return retval;
- }
-
- public override int EndRead (IAsyncResult ar)
- {
- CheckDisposed ();
- int res;
-
- if (ar == null)
- throw new ArgumentNullException ("async result is null");
-
- try {
- res = base.EndRead (ar);
- } catch (Exception e) {
- throw new IOException ("EndRead failure", e);
- }
-
- AdjustChunkLeft (res);
- return res;
- }
-
- public override int Read (byte [] buffer, int offset, int size)
- {
- CheckDisposed ();
- int res;
-
- if (buffer == null)
- throw new ArgumentNullException ("buffer is null");
-
- if (offset < 0 || offset >= buffer.Length)
- throw new ArgumentOutOfRangeException ("offset exceeds the size of buffer");
-
- if (offset + size < 0 || offset + size > buffer.Length)
- throw new ArgumentOutOfRangeException ("offset+size exceeds the size of buffer");
-
- if (!readingChunkSize)
- size = GetMaxSizeFromChunkLeft (size);
-
- try {
- res = base.Read (buffer, offset, size);
- } catch (Exception e) {
- throw new IOException ("Read failure", e);
- }
-
- AdjustChunkLeft (res);
-
- return res;
- }
-
- void CheckDisposed ()
- {
- if (disposed)
- throw new ObjectDisposedException (GetType ().FullName);
- }
-
- void AdjustChunkLeft (int read)
- {
- if (!chunked)
- return;
-
- chunkLeft -= read;
- if (chunkLeft < 0)
- chunkLeft = 0;
- }