Inheritance: IReadChunkBytes
        /*++
            RemoveTrailers

            This handles possible trailer headers that are found after the
            last chunk.  Currently we throw them away for this version.

            Input:

               ReadByteBuffer -

            Returns:

               None - throws on exception

        --*/
        private void RemoveTrailers(StreamChunkBytes ReadByteBuffer) {
            while (m_TempBuffer[0] != '\r' && m_TempBuffer[1] != '\n') {
                int BytesRead = ChunkParse.SkipPastCRLF(ReadByteBuffer);

                if (BytesRead <= 0) {
                    throw new IOException(SR.GetString(SR.net_io_readfailure, SR.GetString(SR.net_io_connectionclosed)));
                }

                ReadCRLF(m_TempBuffer);
            }
        }
        /*++
            ProcessReadChunkedSize

            This is a continuation of the ReadChunkedCallback,
            and is used to parse out the size of a chunk

            Input:

               TheByteRead - single byte read from wire to process

               castedAsyncResult - Async Chunked State information

            Returns:

               None

        --*/
        private int ProcessReadChunkedSize(StreamChunkBytes ReadByteBuffer) {
            GlobalLog.Enter("ConnectStream#" + ValidationHelper.HashString(this) + "::ProcessReadChunkedSize");

            // now get the chunk size.
            int chunkSize;
            int BytesRead = ChunkParse.GetChunkSize(ReadByteBuffer, out chunkSize);

            if (BytesRead <= 0) {
                GlobalLog.Leave("ConnectStream#" + ValidationHelper.HashString(this) + "::ProcessReadChunkedSize - error");
                throw new IOException(SR.GetString(SR.net_io_readfailure, SR.GetString(SR.net_io_connectionclosed)));
            }

            // Now skip past and extensions and the CRLF.
            BytesRead = ChunkParse.SkipPastCRLF(ReadByteBuffer);

            if (BytesRead <= 0) {
                GlobalLog.Leave("ConnectStream#" + ValidationHelper.HashString(this) + "::ProcessReadChunkedSize - error");
                throw new IOException(SR.GetString(SR.net_io_readfailure, SR.GetString(SR.net_io_connectionclosed)));
            }

            GlobalLog.Leave("ConnectStream#" + ValidationHelper.HashString(this) + "::ProcessReadChunkedSize", chunkSize);
            return chunkSize;
        }
        /*++
            ReadChunkedCallback

            This is callback, that parses and does a chunked read.
            It is here that we attempt to Read enough bytes
            to determine the size of the next chunk of data,
            and parse through any headers/control information
            asscoiated with that chunk.

            Input:

               asyncResult - IAsyncResult generated from ConnectStream.BeginRead

        --*/
        private static void ReadChunkedCallback(object state) {
#if DEBUG
            GlobalLog.SetThreadSource(ThreadKinds.Worker);
            using (GlobalLog.SetThreadKind(ThreadKinds.System | ThreadKinds.Sync)) {
#endif

// ********** WARNING - updating logic below should also be updated in ReadChunkedSync *****************

            NestedSingleAsyncResult castedAsyncResult = state as NestedSingleAsyncResult;
            ConnectStream thisConnectStream = castedAsyncResult.AsyncObject as ConnectStream;

            GlobalLog.Enter("ConnectStream#" + ValidationHelper.HashString(thisConnectStream) + "::ReadChunkedCallback", ValidationHelper.HashString(castedAsyncResult));

            try {
                if (!thisConnectStream.m_Draining && thisConnectStream.IsClosed) {
                    // throw on shutdown only if we're not draining the socket.
                    Exception exception =
                        new WebException(
                            NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.ConnectionClosed),
                            WebExceptionStatus.ConnectionClosed);

                    castedAsyncResult.InvokeCallback(exception);
                    GlobalLog.LeaveException("ReadChunkedCallback", exception);
                    return;
                }
                else if (thisConnectStream.m_ErrorException!=null) {
                    // throw on IO error even if we're draining the socket.
                    castedAsyncResult.InvokeCallback(thisConnectStream.m_ErrorException);
                    GlobalLog.LeaveException("ReadChunkedCallback", thisConnectStream.m_ErrorException);
                    return;
                }
                if (thisConnectStream.m_ChunkedNeedCRLFRead) {
                    thisConnectStream.ReadCRLF(thisConnectStream.m_TempBuffer);
                    thisConnectStream.m_ChunkedNeedCRLFRead = false;
                }

                StreamChunkBytes ReadByteBuffer = new StreamChunkBytes(thisConnectStream);

                // We need to determine size of next chunk,
                // by carefully reading, byte by byte

                thisConnectStream.m_ChunkSize = thisConnectStream.ProcessReadChunkedSize(ReadByteBuffer);

                // If this isn't a zero length chunk, read it.
                if (thisConnectStream.m_ChunkSize != 0) {
                    thisConnectStream.m_ChunkedNeedCRLFRead = true;

                    int bytesToRead = Math.Min(castedAsyncResult.Size, thisConnectStream.m_ChunkSize);

                    //
                    // Attempt to fill in our entired read from,
                    //  data previously buffered, if this completely
                    //  satisfies us, then we are done, complete sync
                    //
                    int bytesAlreadyRead = 0;
                    if (thisConnectStream.m_ReadBufferSize > 0)
                    {
                        bytesAlreadyRead = thisConnectStream.FillFromBufferedData(castedAsyncResult.Buffer, ref castedAsyncResult.Offset, ref bytesToRead);
                        if (bytesToRead == 0)
                        {
                            castedAsyncResult.InvokeCallback(bytesAlreadyRead);
                            GlobalLog.Leave("ConnectStream::ReadChunkedCallback");
                            return;
                        }
                    }

                    //
                    // otherwise, we need to read more data from the connection.
                    //
                    if (thisConnectStream.ErrorInStream)
                    {
                        GlobalLog.LeaveException("ConnectStream::ReadChunkedCallback", thisConnectStream.m_ErrorException);
                        throw thisConnectStream.m_ErrorException;
                    }

                    GlobalLog.Assert(thisConnectStream.m_DoneCalled == 0 || thisConnectStream.m_ReadBytes != -1, "ConnectStream::ReadChunkedCallback|Calling BeginRead after ReadDone.");

                    // Keep track of this during the read so it can be added back at the end.
                    thisConnectStream.m_BytesAlreadyTransferred = bytesAlreadyRead;

                    IAsyncResult asyncResult = thisConnectStream.m_Connection.BeginRead(castedAsyncResult.Buffer, castedAsyncResult.Offset, bytesToRead, m_ReadCallbackDelegate, castedAsyncResult);

                    // a null return indicates that the connection was closed underneath us.
                    if (asyncResult == null)
                    {
                        thisConnectStream.m_BytesAlreadyTransferred = 0;
                        thisConnectStream.m_ErrorException = new WebException(
                            NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled),
                            WebExceptionStatus.RequestCanceled);

                        GlobalLog.LeaveException("ConnectStream::ReadChunkedCallback", thisConnectStream.m_ErrorException);
                        throw thisConnectStream.m_ErrorException;
                    }
                }
                else {
                    // We've found the terminating 0 length chunk. We may be very well looking
                    // at an extension footer or the very final CRLF.

                    thisConnectStream.ReadCRLF(thisConnectStream.m_TempBuffer);
                    thisConnectStream.RemoveTrailers(ReadByteBuffer);

                    // Remember that we've found this, so we don't try and dechunk
                    // more.

                    thisConnectStream.m_ReadBytes = 0;
                    thisConnectStream.m_ChunkEofRecvd = true;

                    thisConnectStream.CallDone();

                    // we're done reading, return 0 bytes
                    castedAsyncResult.InvokeCallback(0);
                }
                GlobalLog.Leave("ReadChunkedCallback");
            }
            catch (Exception exception)
            {
                if (NclUtilities.IsFatal(exception)) throw;

                castedAsyncResult.InvokeCallback(exception);
                GlobalLog.LeaveException("ConnectStream::ReadChunkedCallback", exception);
            }

// ********** WARNING - updating logic above should also be updated in ReadChunkedSync *****************
#if DEBUG
            }
#endif
        }
        /*++
            ReadChunkedSync

            Parses and does a chunked read.
            It is here that we attempt to Read enough bytes
            to determine the size of the next chunk of data,
            and parse through any headers/control information
            asscoiated with that chunk.

            Returns:

               None

        --*/
        private int ReadChunkedSync(byte[] buffer, int offset, int size) {
            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::ReadChunkedSync");

// ********** WARNING - updating logic below should also be updated in ReadChunkedCallback *****************

            if (!m_Draining && IsClosed) {
                // throw on shutdown only if we're not draining the socket.
                Exception exception =
                    new WebException(
                        NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.ConnectionClosed),
                        WebExceptionStatus.ConnectionClosed);

                throw exception;
            }
            else if (m_ErrorException!=null) {
                // throw on IO error even if we're draining the socket.
                throw m_ErrorException;
            }
            if (m_ChunkedNeedCRLFRead) {
                ReadCRLF(m_TempBuffer);
                m_ChunkedNeedCRLFRead = false;
            }

            StreamChunkBytes ReadByteBuffer = new StreamChunkBytes(this);

            // We need to determine size of next chunk,
            // by carefully reading, byte by byte

            m_ChunkSize = ProcessReadChunkedSize(ReadByteBuffer);

            // If this isn't a zero length chunk, read it.
            if (m_ChunkSize != 0) {
                m_ChunkedNeedCRLFRead = true;
                return InternalRead(buffer, offset, Math.Min(size, m_ChunkSize));
            }
            else {
                // We've found the terminating 0 length chunk. We may be very well looking
                // at an extension footer or the very final CRLF.

                ReadCRLF(m_TempBuffer);
                RemoveTrailers(ReadByteBuffer);

                // Remember that we've found this, so we don't try and dechunk
                // more.

                m_ReadBytes = 0;
                m_ChunkEofRecvd = true;

                CallDone();

                // we're done reading, return 0 bytes
                return 0;
            }

 // ********** WARNING - updating logic above should also be updated in ReadChunkedAsync *****************
        }
Ejemplo n.º 5
0
        /*++
            ReadChunkedCallback

            This is callback, that parses and does a chunked read.
            It is here that we attempt to Read enough bytes
            to determine the size of the next chunk of data,
            and parse through any headers/control information
            asscoiated with that chunk.

            Input:

               asyncResult - IAsyncResult generated from ConnectStream.BeginRead

            Returns:

               None

        --*/
        private static void ReadChunkedCallback(object state) {
            NestedSingleAsyncResult castedAsyncResult = state as NestedSingleAsyncResult;
            ConnectStream thisConnectStream = castedAsyncResult.AsyncObject as ConnectStream;

            GlobalLog.Enter("ConnectStream#" + ValidationHelper.HashString(thisConnectStream) + "::ReadChunkedCallback", ValidationHelper.HashString(castedAsyncResult));

            try {
                if (!thisConnectStream.m_Draining && thisConnectStream.m_ShutDown==1) {
                    // throw on shutdown only if we're not draining the socket.
                    Exception exception =
                        new WebException(
                            NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.ConnectionClosed),
                            WebExceptionStatus.ConnectionClosed);

                    castedAsyncResult.InvokeCallback(false, exception);
                    GlobalLog.LeaveException("ReadChunkedCallback", exception);
                    return;
                }
                else if (thisConnectStream.m_ErrorException!=null) {
                    // throw on IO error even if we're draining the socket.
                    castedAsyncResult.InvokeCallback(false, thisConnectStream.m_ErrorException);
                    GlobalLog.LeaveException("ReadChunkedCallback", thisConnectStream.m_ErrorException);
                    return;
                }
                if (thisConnectStream.m_ChunkedNeedCRLFRead) {
                    thisConnectStream.ReadCRLF(thisConnectStream.m_TempBuffer);
                    thisConnectStream.m_ChunkedNeedCRLFRead = false;
                }

                StreamChunkBytes ReadByteBuffer = new StreamChunkBytes(thisConnectStream);

                // We need to determine size of next chunk,
                // by carefully reading, byte by byte

                thisConnectStream.m_ChunkSize = thisConnectStream.ProcessReadChunkedSize(ReadByteBuffer);

                // If this isn't a zero length chunk, read it.
                if (thisConnectStream.m_ChunkSize != 0) {
                    thisConnectStream.m_ChunkedNeedCRLFRead = true;

                    thisConnectStream.InternalBeginRead(Math.Min(castedAsyncResult.Size, thisConnectStream.m_ChunkSize), castedAsyncResult, true);
                }
                else {
                    // We've found the terminating 0 length chunk. We may be very well looking
                    // at an extension footer or the very final CRLF.

                    thisConnectStream.ReadCRLF(thisConnectStream.m_TempBuffer);
                    thisConnectStream.RemoveTrailers(ReadByteBuffer);

                    // Remember that we've found this, so we don't try and dechunk
                    // more.

                    thisConnectStream.m_ReadBytes = 0;
                    thisConnectStream.m_ChunkEofRecvd = true;

                    thisConnectStream.CallDone();

                    // we're done reading, return 0 bytes
                    castedAsyncResult.InvokeCallback(false, 0);
                }
                GlobalLog.Leave("ReadChunkedCallback");
            }
            catch (Exception exception) {
                castedAsyncResult.InvokeCallback(false, exception);
                GlobalLog.LeaveException("ReadChunkedCallback", exception);
            }
        }