public void CopyToAsync(System.IO.Stream stream)
        {
            Timeout timeout           = null;
            StreamAsyncEventArgs args = new StreamAsyncEventArgs();

            args.Complete  = CopyToAsync_Callback;
            args.UserToken = new Tuple <Timeout, System.IO.Stream>(timeout, stream);
            args.SetBuffer(new byte[_socket.ReceiveBufferSize], 0, _socket.ReceiveBufferSize);

            if (!TryStartTimeout(_socket.ReceiveTimeout, out timeout,
                                 new Timeout.TimeoutEvent(CopyToAsync_OnTimeout)))
            {
                return;
            }

            try
            {
                _stream.ReadAsync(args);
            }
            catch (Exception e)
            {
                Logger.Network.Error("An exception occurred while calling CopyToAsync.", e);
                if (OnError != null)
                {
                    OnError(this, "Exception calling CopyToAsync", e);
                }
                else
                {
                    throw;
                }
            }
        }
        private void ReadAsync_UnknownContentLength(byte[] buffer, int offset, int count)
        {
            StreamAsyncEventArgs args  = new StreamAsyncEventArgs();
            Timeout timeout            = null;
            int     lengthMinusPrepend = count;

            if (!TryStartTimeout(_socket.ReceiveTimeout, out timeout,
                                 new Timeout.TimeoutEvent(ReadAsync_OnTimeout)))
            {
                return;
            }

            args.Complete  = ReadAsync_Callback;
            args.UserToken = timeout;

            args.SetBuffer(buffer, offset, count);

            try
            {
                _stream.ReadAsync(args);
            }
            catch (Exception e)
            {
                Logger.Network.Error("An exception occurred while calling _stream.BeginRead.", e);
                if (OnError != null)
                {
                    OnError(this, "Exception calling _stream.BeginRead", e);
                }
                else
                {
                    throw;
                }
            }
        }
        private void ReadAsync_KnownContentLength(byte[] buffer, int offset, int count)
        {
            StreamAsyncEventArgs args  = new StreamAsyncEventArgs();
            Timeout timeout            = null;
            int     lengthMinusPrepend = count;

            if (!TryStartTimeout(_socket.ReceiveTimeout, out timeout,
                                 new Timeout.TimeoutEvent(ReadAsync_OnTimeout)))
            {
                return;
            }


            // We should only try if the total bytes received is less than the content length
            // otherwise we fall into an infinite wait
            if (_contentLength > 0 &&
                _bytesReceived < _contentLength)
            {
                args.Complete  = ReadAsync_Callback;
                args.UserToken = timeout;

                // Trim down the length to read to the content length if necessary
                if (_contentLength < (ulong)args.Count + _bytesReceived)
                {
                    throw new ContentLengthExceededException("Content length exceeded.");
                }

                args.SetBuffer(buffer, offset, count);

                try
                {
                    _stream.ReadAsync(args);
                }
                catch (Exception e)
                {
                    Logger.Network.Error("An exception occurred while calling _stream.BeginRead.", e);
                    if (OnError != null)
                    {
                        OnError(this, "Exception calling _stream.BeginRead", e);
                    }
                    else
                    {
                        throw;
                    }
                }
            }
            else
            {
                throw new ContentLengthExceededException("The read was requested starting outside the content length.");
            }
        }
        public void WriteAsync(StreamAsyncEventArgs e)
        {
            if (_unknownContentLength)
            {
                throw new HttpNetworkStreamException("Content length must be set to call WriteAsync.");
            }

            Timeout timeout = null;

            if (!TryStartTimeout(_socket.SendTimeout, out timeout,
                                 new Timeout.TimeoutEvent(WriteAsync_OnTimeout)))
            {
                return;
            }

            if (_unknownContentLength)
            {
                throw new HttpNetworkStreamException("Content length must be set to call WriteAsync.");
            }

            if (_bytesSent >= _contentLength)
            {
                throw new ContentLengthExceededException("The read was requested starting outside the content length.");
            }

            e.Complete  = WriteAsync_Callback;
            e.UserToken = timeout;

            try
            {
                _stream.WriteAsync(e);
            }
            catch (Exception ex)
            {
                Logger.Network.Error("An exception occurred while calling _stream.BeginWrite.", ex);
                if (OnError != null)
                {
                    OnError(this, "Exception calling _stream.BeginWrite", ex);
                }
                else
                {
                    throw;
                }
            }
        }
        public void ReadToEndAsync()
        {
            if (_unknownContentLength)
            {
                throw new HttpNetworkStreamException("Content length must be set to call WriteAsync.");
            }

            Timeout timeout           = null;
            StreamAsyncEventArgs args = new StreamAsyncEventArgs();

            if (!TryStartTimeout(_socket.ReceiveTimeout, out timeout,
                                 new Timeout.TimeoutEvent(ReadToEndAsync_OnTimeout)))
            {
                return;
            }

            args.Complete  = ReadToEndAsync_Callback;
            args.UserToken = new Tuple <Timeout, string>(timeout, "");
            args.SetBuffer(new byte[_socket.ReceiveBufferSize], 0, _socket.ReceiveBufferSize);

            try
            {
                _stream.ReadAsync(args);
            }
            catch (Exception e)
            {
                Logger.Network.Error("An exception occurred while calling ReadToEndAsync.", e);
                if (OnError != null)
                {
                    OnError(this, "Exception calling ReadToEndAsync", e);
                }
                else
                {
                    throw;
                }
            }
        }
        private void WriteAsync_Callback(StreamAsyncEventArgs e)
        {
            _bytesSent += (ulong)e.Count;

            if (!TryStopTimeout((Timeout)e.UserToken))
            {
                return;
            }

            try
            {
                if (OnProgress != null)
                {
                    OnProgress(this, DirectionType.Upload, e.Count);
                }
            }
            catch (Exception ex)
            {
                // Ignore it, its the higher level's job to deal with it.
                Logger.Network.Error("An unhandled exception was caught by HttpNetworkStream.WriteAsync_Callback in the OnProgress event.", ex);
            }

            try
            {
                if (OnBufferOperationComplete != null)
                {
                    OnBufferOperationComplete(this, DirectionType.Upload,
                                              e.Buffer, e.Offset, e.Count);
                }
            }
            catch (Exception ex)
            {
                // Ignore it, its the higher level's job to deal with it.
                Logger.Network.Error("An unhandled exception was caught by HttpNetworkStream.WriteAsync_Callback in the OnBufferOperationComplete event.", ex);
            }
        }
        private void ReadToEndAsync_Callback(StreamAsyncEventArgs e)
        {
            Timeout timeout = null;
            Tuple <Timeout, string> userToken = (Tuple <Timeout, string>)e.UserToken;
            string str = userToken.Item2;

            if (!TryStopTimeout(userToken.Item1))
            {
                return;
            }

            _bytesReceived += (ulong)e.Count;

            if (_bytesReceived > _contentLength)
            {
                throw new ContentLengthExceededException("Content received was longer than the Content Length specified.");
            }

            try
            {
                str += System.Text.Encoding.ASCII.GetString(e.Buffer, e.Offset, e.Count);
            }
            catch (Exception ex)
            {
                Logger.Network.Error("An exception occurred while getting a string from the buffer.", ex);
                if (OnError != null)
                {
                    OnError(this, "Exception while getting a string from the buffer.", ex);
                    return;
                }
            }

            // Progress Event
            try
            {
                if (OnProgress != null)
                {
                    OnProgress(this, DirectionType.Download, e.Count);
                }
            }
            catch (Exception ex)
            {
                // Ignore it, its the higher level's job to deal with it.
                Logger.Network.Error("An unhandled exception was caught by HttpNetworkStream.ReadToEndAsync_Callback in the OnProgress event.", ex);
            }

            // End?
            if (_bytesReceived == _contentLength)
            {
                try
                {
                    if (OnStringOperationComplete != null)
                    {
                        OnStringOperationComplete(this, str);
                    }
                }
                catch (Exception ex)
                {
                    // Ignore it, its the higher level's job to deal with it.
                    Logger.Network.Error("An unhandled exception was caught by HttpNetworkStream.ReadToEndAsync_Callback in the OnStringOperationComplete event.", ex);
                }
            }
            else
            {
                // content left to stream
                if (!TryStartTimeout(_socket.ReceiveTimeout, out timeout,
                                     new Timeout.TimeoutEvent(ReadToEndAsync_OnTimeout)))
                {
                    return;
                }

                e.UserToken = new Tuple <Timeout, string>(timeout, str);
                e.SetBuffer(e.Buffer, 0, _socket.ReceiveBufferSize);

                try
                {
                    _stream.ReadAsync(e);
                }
                catch (Exception ex)
                {
                    Logger.Network.Error("An exception occurred while calling ReadAsync.", ex);
                    if (OnError != null)
                    {
                        OnError(this, "Exception calling ReadAsync", ex);
                    }
                    else
                    {
                        throw;
                    }
                }
            }
        }
        // Private Methods (10) 

        private void CopyToAsync_Callback(StreamAsyncEventArgs e)
        {
            if (_unknownContentLength)
            {
                throw new HttpNetworkStreamException("Content length must be set to call WriteAsync.");
            }

            Timeout timeout = null;
            Tuple <Timeout, System.IO.Stream> userToken = (Tuple <Timeout, System.IO.Stream>)e.UserToken;

            if (!TryStopTimeout(userToken.Item1))
            {
                return;
            }

            _bytesReceived += (ulong)e.Count;

            if (_bytesReceived > _contentLength)
            {
                throw new ContentLengthExceededException("Received more bytes than the content length specified.");
            }

            try
            {
                userToken.Item2.Write(e.Buffer, e.Offset, e.Count);
            }
            catch (Exception ex)
            {
                Logger.Network.Error("An exception occurred while writing to the argument stream.", ex);
                if (OnError != null)
                {
                    OnError(this, "Exception writing to stream.", ex);
                    return;
                }
                else
                {
                    throw;
                }
            }

            // Progress Event
            try
            {
                if (OnProgress != null)
                {
                    OnProgress(this, DirectionType.Download, e.Count);
                }
            }
            catch (Exception ex)
            {
                // Ignore it, its the higher level's job to deal with it.
                Logger.Network.Error("An unhandled exception was caught by HttpNetworkStream.CopyToAsync_Callback in the OnProgress event.", ex);
            }

            // End?
            if (_bytesReceived == _contentLength)
            {
                try
                {
                    if (OnStreamOperationComplete != null)
                    {
                        OnStreamOperationComplete(this, userToken.Item2);
                    }
                }
                catch (Exception ex)
                {
                    // Ignore it, its the higher level's job to deal with it.
                    Logger.Network.Error("An unhandled exception was caught by HttpNetworkStream.CopyToAsync_Callback in the OnStreamOperationComplete event.", ex);
                }
            }
            else
            {
                // content left to stream
                if (!TryStartTimeout(_socket.ReceiveTimeout, out timeout,
                                     new Timeout.TimeoutEvent(ReadToEndAsync_OnTimeout)))
                {
                    return;
                }

                e.UserToken = new Tuple <Timeout, System.IO.Stream>(timeout, userToken.Item2);
                e.SetBuffer(e.Buffer, 0, _socket.ReceiveBufferSize);

                try
                {
                    _stream.ReadAsync(e);
                }
                catch (Exception ex)
                {
                    Logger.Network.Error("An exception occurred while calling ReadAsync.", ex);
                    if (OnError != null)
                    {
                        OnError(this, "Exception calling ReadAsync", ex);
                    }
                    else
                    {
                        throw;
                    }
                }
            }
        }
        private void WriteAsync_Callback(StreamAsyncEventArgs e)
        {
            _bytesSent += (ulong)e.Count;

            if (!TryStopTimeout((Timeout)e.UserToken))
                return;

            try
            {
                if (OnProgress != null)
                    OnProgress(this, DirectionType.Upload, e.Count);

            }
            catch (Exception ex)
            {
                // Ignore it, its the higher level's job to deal with it.
                Logger.Network.Error("An unhandled exception was caught by HttpNetworkStream.WriteAsync_Callback in the OnProgress event.", ex);
            }

            try
            {
                if (OnBufferOperationComplete != null)
                    OnBufferOperationComplete(this, DirectionType.Upload,
                        e.Buffer, e.Offset, e.Count);

            }
            catch (Exception ex)
            {
                // Ignore it, its the higher level's job to deal with it.
                Logger.Network.Error("An unhandled exception was caught by HttpNetworkStream.WriteAsync_Callback in the OnBufferOperationComplete event.", ex);
            }
        }
        // Private Methods (10) 

        private void CopyToAsync_Callback(StreamAsyncEventArgs e)
        {
            if (_unknownContentLength)
                throw new HttpNetworkStreamException("Content length must be set to call WriteAsync.");

            Timeout timeout = null;
            Tuple<Timeout, System.IO.Stream> userToken = (Tuple<Timeout, System.IO.Stream>)e.UserToken;

            if (!TryStopTimeout(userToken.Item1))
                return;

            _bytesReceived += (ulong)e.Count;

            if (_bytesReceived > _contentLength)
                throw new ContentLengthExceededException("Received more bytes than the content length specified.");

            try
            {
                userToken.Item2.Write(e.Buffer, e.Offset, e.Count);
            }
            catch (Exception ex)
            {
                Logger.Network.Error("An exception occurred while writing to the argument stream.", ex);
                if (OnError != null)
                {
                    OnError(this, "Exception writing to stream.", ex);
                    return;
                }
                else throw;
            }

            // Progress Event
            try
            {
                if (OnProgress != null)
                    OnProgress(this, DirectionType.Download, e.Count);
            }
            catch (Exception ex)
            {
                // Ignore it, its the higher level's job to deal with it.
                Logger.Network.Error("An unhandled exception was caught by HttpNetworkStream.CopyToAsync_Callback in the OnProgress event.", ex);
            }

            // End?
            if (_bytesReceived == _contentLength)
            {
                try
                {
                    if (OnStreamOperationComplete != null)
                        OnStreamOperationComplete(this, userToken.Item2);
                }
                catch (Exception ex)
                {
                    // Ignore it, its the higher level's job to deal with it.
                    Logger.Network.Error("An unhandled exception was caught by HttpNetworkStream.CopyToAsync_Callback in the OnStreamOperationComplete event.", ex);
                }
            }
            else
            {
                // content left to stream
                if (!TryStartTimeout(_socket.ReceiveTimeout, out timeout,
                    new Timeout.TimeoutEvent(ReadToEndAsync_OnTimeout)))
                    return;

                e.UserToken = new Tuple<Timeout, System.IO.Stream>(timeout, userToken.Item2);
                e.SetBuffer(e.Buffer, 0, _socket.ReceiveBufferSize);

                try
                {
                    _stream.ReadAsync(e);
                }
                catch (Exception ex)
                {
                    Logger.Network.Error("An exception occurred while calling ReadAsync.", ex);
                    if (OnError != null) OnError(this, "Exception calling ReadAsync", ex);
                    else throw;
                }
            }
        }
        private void ReadToEndAsync_Callback(StreamAsyncEventArgs e)
        {
            Timeout timeout = null;
            Tuple<Timeout, string> userToken = (Tuple<Timeout, string>)e.UserToken;
            string str = userToken.Item2;

            if (!TryStopTimeout(userToken.Item1))
                return;

            _bytesReceived += (ulong)e.Count;

            if (_bytesReceived > _contentLength)
                throw new ContentLengthExceededException("Content received was longer than the Content Length specified.");

            try
            {
                str += System.Text.Encoding.ASCII.GetString(e.Buffer, e.Offset, e.Count);
            }
            catch (Exception ex)
            {
                Logger.Network.Error("An exception occurred while getting a string from the buffer.", ex);
                if (OnError != null)
                {
                    OnError(this, "Exception while getting a string from the buffer.", ex);
                    return;
                }
            }

            // Progress Event
            try
            {
                if (OnProgress != null)
                    OnProgress(this, DirectionType.Download, e.Count);
            }
            catch (Exception ex)
            {
                // Ignore it, its the higher level's job to deal with it.
                Logger.Network.Error("An unhandled exception was caught by HttpNetworkStream.ReadToEndAsync_Callback in the OnProgress event.", ex);
            }

            // End?
            if (_bytesReceived == _contentLength)
            {
                try
                {
                    if (OnStringOperationComplete != null)
                        OnStringOperationComplete(this, str);
                }
                catch (Exception ex)
                {
                    // Ignore it, its the higher level's job to deal with it.
                    Logger.Network.Error("An unhandled exception was caught by HttpNetworkStream.ReadToEndAsync_Callback in the OnStringOperationComplete event.", ex);
                }
            }
            else
            {
                // content left to stream
                if (!TryStartTimeout(_socket.ReceiveTimeout, out timeout,
                    new Timeout.TimeoutEvent(ReadToEndAsync_OnTimeout)))
                    return;

                e.UserToken = new Tuple<Timeout, string>(timeout, str);
                e.SetBuffer(e.Buffer, 0, _socket.ReceiveBufferSize);

                try
                {
                    _stream.ReadAsync(e);
                }
                catch (Exception ex)
                {
                    Logger.Network.Error("An exception occurred while calling ReadAsync.", ex);
                    if (OnError != null) OnError(this, "Exception calling ReadAsync", ex);
                    else throw;
                }
            }
        }
        public void WriteAsync(StreamAsyncEventArgs e)
        {
            if (_unknownContentLength)
                throw new HttpNetworkStreamException("Content length must be set to call WriteAsync.");

            Timeout timeout = null;

            if (!TryStartTimeout(_socket.SendTimeout, out timeout,
                new Timeout.TimeoutEvent(WriteAsync_OnTimeout)))
                return;

            if (_unknownContentLength)
                throw new HttpNetworkStreamException("Content length must be set to call WriteAsync.");

            if (_bytesSent >= _contentLength)
                throw new ContentLengthExceededException("The read was requested starting outside the content length.");

            e.Complete = WriteAsync_Callback;
            e.UserToken = timeout;

            try
            {
                _stream.WriteAsync(e);
            }
            catch (Exception ex)
            {
                Logger.Network.Error("An exception occurred while calling _stream.BeginWrite.", ex);
                if (OnError != null) OnError(this, "Exception calling _stream.BeginWrite", ex);
                else throw;
            }
        }
        public void ReadToEndAsync()
        {
            if (_unknownContentLength)
                throw new HttpNetworkStreamException("Content length must be set to call WriteAsync.");

            Timeout timeout = null;
            StreamAsyncEventArgs args = new StreamAsyncEventArgs();

            if (!TryStartTimeout(_socket.ReceiveTimeout, out timeout,
                new Timeout.TimeoutEvent(ReadToEndAsync_OnTimeout)))
                return;

            args.Complete = ReadToEndAsync_Callback;
            args.UserToken = new Tuple<Timeout, string>(timeout, "");
            args.SetBuffer(new byte[_socket.ReceiveBufferSize], 0, _socket.ReceiveBufferSize);

            try
            {
                _stream.ReadAsync(args);
            }
            catch (Exception e)
            {
                Logger.Network.Error("An exception occurred while calling ReadToEndAsync.", e);
                if (OnError != null) OnError(this, "Exception calling ReadToEndAsync", e);
                else throw;
            }
        }
        private void ReadAsync_UnknownContentLength(byte[] buffer, int offset, int count)
        {
            StreamAsyncEventArgs args = new StreamAsyncEventArgs();
            Timeout timeout = null;
            int lengthMinusPrepend = count;

            if (!TryStartTimeout(_socket.ReceiveTimeout, out timeout,
                new Timeout.TimeoutEvent(ReadAsync_OnTimeout)))
                return;

            args.Complete = ReadAsync_Callback;
            args.UserToken = timeout;

            args.SetBuffer(buffer, offset, count);

            try
            {
                _stream.ReadAsync(args);
            }
            catch (Exception e)
            {
                Logger.Network.Error("An exception occurred while calling _stream.BeginRead.", e);
                if (OnError != null) OnError(this, "Exception calling _stream.BeginRead", e);
                else throw;
            }
        }
        private void ReadAsync_KnownContentLength(byte[] buffer, int offset, int count)
        {
            StreamAsyncEventArgs args = new StreamAsyncEventArgs();
            Timeout timeout = null;
            int lengthMinusPrepend = count;

            if (!TryStartTimeout(_socket.ReceiveTimeout, out timeout,
                new Timeout.TimeoutEvent(ReadAsync_OnTimeout)))
                return;


            // We should only try if the total bytes received is less than the content length
            // otherwise we fall into an infinite wait
            if (_contentLength > 0 &&
                _bytesReceived < _contentLength)
            {
                args.Complete = ReadAsync_Callback;
                args.UserToken = timeout;

                // Trim down the length to read to the content length if necessary
                if (_contentLength < (ulong)args.Count + _bytesReceived)
                    throw new ContentLengthExceededException("Content length exceeded.");

                args.SetBuffer(buffer, offset, count);

                try
                {
                    _stream.ReadAsync(args);
                }
                catch (Exception e)
                {
                    Logger.Network.Error("An exception occurred while calling _stream.BeginRead.", e);
                    if (OnError != null) OnError(this, "Exception calling _stream.BeginRead", e);
                    else throw;
                }
            }
            else
                throw new ContentLengthExceededException("The read was requested starting outside the content length.");
        }
        public void CopyToAsync(System.IO.Stream stream)
        {
            Timeout timeout = null;
            StreamAsyncEventArgs args = new StreamAsyncEventArgs();

            args.Complete = CopyToAsync_Callback;
            args.UserToken = new Tuple<Timeout, System.IO.Stream>(timeout, stream);
            args.SetBuffer(new byte[_socket.ReceiveBufferSize], 0, _socket.ReceiveBufferSize);

            if (!TryStartTimeout(_socket.ReceiveTimeout, out timeout,
                new Timeout.TimeoutEvent(CopyToAsync_OnTimeout)))
                return;

            try
            {
                _stream.ReadAsync(args);
            }
            catch (Exception e)
            {
                Logger.Network.Error("An exception occurred while calling CopyToAsync.", e);
                if (OnError != null) OnError(this, "Exception calling CopyToAsync", e);
                else throw;
            }
        }