Example #1
0
 internal static void Add(ref ConnectionReturnResult returnResult, HttpWebRequest request, CoreResponseData coreResponseData)
 {
     if (coreResponseData == null)
     {
         throw new InternalException();
     }
     if (returnResult == null)
     {
         returnResult = new ConnectionReturnResult();
     }
     returnResult.m_Context.Add(new RequestContext(request, coreResponseData));
 }
 internal static void Add(ref ConnectionReturnResult returnResult, HttpWebRequest request, CoreResponseData coreResponseData)
 {
     if (coreResponseData == null)
     {
         throw new InternalException();
     }
     if (returnResult == null)
     {
         returnResult = new ConnectionReturnResult();
     }
     returnResult.m_Context.Add(new RequestContext(request, coreResponseData));
 }
Example #3
0
 internal static void AddExceptionRange(ref ConnectionReturnResult returnResult, HttpWebRequest[] requests, Exception exception, Exception firstRequestException)
 {
     if (exception == null)
     {
         throw new InternalException();
     }
     if (returnResult == null)
     {
         returnResult = new ConnectionReturnResult(requests.Length);
     }
     for (int i = 0; i < requests.Length; i++)
     {
         if (i == 0)
         {
             returnResult.m_Context.Add(new RequestContext(requests[i], firstRequestException));
         }
         else
         {
             returnResult.m_Context.Add(new RequestContext(requests[i], exception));
         }
     }
 }
 internal static void AddExceptionRange(ref ConnectionReturnResult returnResult, HttpWebRequest[] requests, Exception exception, Exception firstRequestException)
 {
     if (exception == null)
     {
         throw new InternalException();
     }
     if (returnResult == null)
     {
         returnResult = new ConnectionReturnResult(requests.Length);
     }
     for (int i = 0; i < requests.Length; i++)
     {
         if (i == 0)
         {
             returnResult.m_Context.Add(new RequestContext(requests[i], firstRequestException));
         }
         else
         {
             returnResult.m_Context.Add(new RequestContext(requests[i], exception));
         }
     }
 }
 internal static void SetResponses(ConnectionReturnResult returnResult)
 {
     if (returnResult != null)
     {
         for (int i = 0; i < returnResult.m_Context.Count; i++)
         {
             try
             {
                 returnResult.m_Context[i].Request.SetAndOrProcessResponse(returnResult.m_Context[i].CoreResponse);
             }
             catch (Exception)
             {
                 returnResult.m_Context.RemoveRange(0, i + 1);
                 if (returnResult.m_Context.Count > 0)
                 {
                     ThreadPool.UnsafeQueueUserWorkItem(s_InvokeConnectionCallback, returnResult);
                 }
                 throw;
             }
         }
         returnResult.m_Context.Clear();
     }
 }
Example #6
0
 internal static void SetResponses(ConnectionReturnResult returnResult)
 {
     if (returnResult != null)
     {
         for (int i = 0; i < returnResult.m_Context.Count; i++)
         {
             try
             {
                 returnResult.m_Context[i].Request.SetAndOrProcessResponse(returnResult.m_Context[i].CoreResponse);
             }
             catch (Exception)
             {
                 returnResult.m_Context.RemoveRange(0, i + 1);
                 if (returnResult.m_Context.Count > 0)
                 {
                     ThreadPool.UnsafeQueueUserWorkItem(s_InvokeConnectionCallback, returnResult);
                 }
                 throw;
             }
         }
         returnResult.m_Context.Clear();
     }
 }
Example #7
0
        private void CallDone(ConnectionReturnResult returnResult)
        {
            GlobalLog.Enter("ConnectStream#" + ValidationHelper.HashString(this) + "::CallDone");
            if ( Interlocked.Increment( ref m_DoneCalled) == 1 )
            {
                if (!WriteStream)
                {
#if DEBUG
                    GlobalLog.DebugRemoveRequest(m_Request);
#endif
                    if (returnResult == null) {
                        //readstartnextrequest will call setresponses internally.

                        if (m_Chunked)
                        {
                            int leftoverBufferOffset;
                            int leftoverBufferSize;
                            byte[] leftoverBuffer;

                            if (m_ChunkParser.TryGetLeftoverBytes(out leftoverBuffer, out leftoverBufferOffset, 
                                out leftoverBufferSize))
                            {
                                m_Connection.SetLeftoverBytes(leftoverBuffer, leftoverBufferOffset, leftoverBufferSize);
                            }
                        }
                        m_Connection.ReadStartNextRequest(m_Request, ref returnResult);
                    }
                    else{
                        ConnectionReturnResult.SetResponses(returnResult);
                    }
                }
                else
                {
                    m_Request.WriteCallDone(this, returnResult);
                }
            }
            GlobalLog.Leave("ConnectStream#" + ValidationHelper.HashString(this) + "::CallDone");
        }
 private void HandleError(bool writeDone, bool readDone, WebExceptionStatus webExceptionStatus, ref ConnectionReturnResult returnResult)
 {
     lock (this)
     {
         if (writeDone)
         {
             this.m_WriteDone = true;
         }
         if (readDone)
         {
             this.m_ReadDone = true;
         }
         if (webExceptionStatus == WebExceptionStatus.Success)
         {
             throw new InternalException();
         }
         this.m_Error = webExceptionStatus;
         this.PrepareCloseConnectionSocket(ref returnResult);
         base.Close(0);
     }
 }
        /*++

            PrepareCloseConnectionSocket - reset the connection requests list.

            This method is called when we want to close the conection.
            It must be called with the critical section held.
            The caller must call this.Close if decided to call this method.

            All connection closes (either ours or server initiated) eventually go through here.

            As to what we do: we loop through our write and wait list and pull requests
            off it, and give each request an error failure. Then the caller will
            dispatch the responses.

        --*/

        private void PrepareCloseConnectionSocket(ref ConnectionReturnResult returnResult)
        {
            GlobalLog.Enter("Connection#" + ValidationHelper.HashString(this) + "::PrepareCloseConnectionSocket", m_Error.ToString());

            // Effectivelly, closing a connection makes it exempted from the "Idling" logic
            m_IdleSinceUtc = DateTime.MinValue;
            CanBePooled = false;

            if (m_WriteList.Count != 0 || m_WaitList.Count != 0)
            {

                GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::PrepareCloseConnectionSocket() m_WriteList.Count:" + m_WriteList.Count);
                DebugDumpWriteListEntries();
                GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::PrepareCloseConnectionSocket() m_WaitList.Count:" + m_WaitList.Count);
                DebugDumpWaitListEntries();

                HttpWebRequest lockedRequest = LockedRequest;

                if (lockedRequest != null)
                {
                    bool callUnlockRequest = false;
                    GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::PrepareCloseConnectionSocket() looking for HttpWebRequest#" + ValidationHelper.HashString(lockedRequest));

                    foreach (HttpWebRequest request in m_WriteList)
                    {
                        if (request == lockedRequest) {
                            callUnlockRequest = true;
                        }
                    }

                    if (!callUnlockRequest) {
                        foreach (WaitListItem item in m_WaitList) {
                            if (item.Request == lockedRequest) {
                                callUnlockRequest = true;
                                break;
                            }
                        }
                    }
                    if (callUnlockRequest) {
                        UnlockRequest();
                    }
                }

                HttpWebRequest[] requestArray = null;

                // WaitList gets Isolated exception status, free to retry multiple times
                if (m_WaitList.Count != 0)
                {
                    requestArray = new HttpWebRequest[m_WaitList.Count];
                    for (int i = 0; i < m_WaitList.Count; i++)
                    {
                        requestArray[i] = m_WaitList[i].Request;
                    }
                    ConnectionReturnResult.AddExceptionRange(ref returnResult, requestArray, ExceptionHelper.IsolatedException);
                }

                //
                // WriteList (except for single request list) gets Recoverable exception status, may be retired if not failed once
                // For a single request list the exception is computed here
                // InnerExeption if any may tell more details in both cases
                //
                if (m_WriteList.Count != 0)
                {
                    Exception theException = m_InnerException;


                    if(theException != null)
                       GlobalLog.Print(theException.ToString());

                    GlobalLog.Print("m_Error = "+ m_Error.ToString());

                    if (!(theException is WebException) && !(theException is SecurityException))
                    {
                        if (m_Error == WebExceptionStatus.ServerProtocolViolation)
                        {
                            string errorString = NetRes.GetWebStatusString(m_Error);

                            string detailedInfo = "";
                            if (m_ParseError.Section != WebParseErrorSection.Generic)
                                detailedInfo += " Section=" + m_ParseError.Section.ToString();
                            if (m_ParseError.Code != WebParseErrorCode.Generic) {
                                detailedInfo += " Detail=" + SR.GetString("net_WebResponseParseError_" + m_ParseError.Code.ToString());
                            }
                            if (detailedInfo.Length != 0)
                                errorString += "." + detailedInfo;

                            theException = new WebException(errorString,
                                                            theException,
                                                            m_Error,
                                                            null,
                                                            WebExceptionInternalStatus.RequestFatal);
                        }
                        else if (m_Error == WebExceptionStatus.SecureChannelFailure)
                        {
                            theException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.SecureChannelFailure),
                                                            WebExceptionStatus.SecureChannelFailure);
                        }

                        else if (m_Error == WebExceptionStatus.Timeout)
                        {
                            theException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.Timeout),
                                                            WebExceptionStatus.Timeout);
                        }
                        else if(m_Error == WebExceptionStatus.RequestCanceled)
                        {
                            theException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled),
                                                            WebExceptionStatus.RequestCanceled,
                                                            WebExceptionInternalStatus.RequestFatal,
                                                            theException);
                        }
                        else if(m_Error == WebExceptionStatus.MessageLengthLimitExceeded ||
                                m_Error == WebExceptionStatus.TrustFailure)
                        {
                            theException = new WebException(NetRes.GetWebStatusString("net_connclosed", m_Error),
                                                            m_Error,
                                                            WebExceptionInternalStatus.RequestFatal,
                                                            theException);
                        }
                        else
                        {
                            if (m_Error == WebExceptionStatus.Success)
                            {
                                throw new InternalException();              // TODO: replace it with a generic error for the product bits
                                //m_Error = WebExceptionStatus.UnknownError;
                            }

                            bool retry = false;
                            bool isolatedKeepAliveFailure = false;

                            if (m_WriteList.Count != 1)
                            {
                                // Real scenario: SSL against IIS-5 would fail if pipelinning.
                                // retry = true will cover a general case when >>the server<< aborts a pipeline
                                // Basically all pipelined requests are marked with recoverable error including the very active request.
                                retry = true;
                            }
                            else if (m_Error == WebExceptionStatus.KeepAliveFailure)
                            {
                                HttpWebRequest request = (HttpWebRequest) m_WriteList[0];
                                // Check that the active request did not start the body yet
                                if (!request.BodyStarted)
                                    isolatedKeepAliveFailure = true;
                            }
                            else{
                                retry = (!AtLeastOneResponseReceived && !((HttpWebRequest) m_WriteList[0]).BodyStarted);
                            }
                                theException = new WebException(NetRes.GetWebStatusString("net_connclosed", m_Error),
                                                            m_Error,
                                                            (isolatedKeepAliveFailure? WebExceptionInternalStatus.Isolated:
                                                                retry? WebExceptionInternalStatus.Recoverable:
                                                                WebExceptionInternalStatus.RequestFatal),
                                                            theException);
                        }
                    }

                    WebException pipelineException = new WebException(NetRes.GetWebStatusString("net_connclosed", WebExceptionStatus.PipelineFailure),
                                                                      WebExceptionStatus.PipelineFailure,
                                                                      WebExceptionInternalStatus.Recoverable,
                                                                      theException);

                    requestArray = new HttpWebRequest[m_WriteList.Count];
                    m_WriteList.CopyTo(requestArray, 0);
                    ConnectionReturnResult.AddExceptionRange(ref returnResult, requestArray, pipelineException, theException);
                }

#if TRAVE
                foreach (WaitListItem item in m_WaitList) {
                    GlobalLog.Print("Request removed from WaitList#"+ValidationHelper.HashString(item.Request));
                }

                foreach (HttpWebRequest request in m_WriteList) {
                    GlobalLog.Print("Request removed from m_WriteList#"+ValidationHelper.HashString(request));
                }
#endif

                m_WriteList.Clear();

                foreach (WaitListItem item in m_WaitList)
                {
                    NetworkingPerfCounters.Instance.IncrementAverage(NetworkingPerfCounterName.HttpWebRequestAvgQueueTime,
                        item.QueueStartTime);
                }
                m_WaitList.Clear();
            }

            CheckIdle();

            if (m_Idle)
            {
                GC.SuppressFinalize(this);
            }
            if (!m_RemovedFromConnectionList && ConnectionGroup != null)
            {
                m_RemovedFromConnectionList = true;
                ConnectionGroup.Disassociate(this);
            }
            GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::PrepareCloseConnectionSocket");
        }
 //
 private void HandleErrorWithReadDone(WebExceptionStatus webExceptionStatus, ref ConnectionReturnResult returnResult)
 {
     HandleError(false, true, webExceptionStatus, ref returnResult);
 }
        internal static void AddExceptionRange(ref ConnectionReturnResult returnResult, HttpWebRequest [] requests, Exception exception, Exception firstRequestException)
        {

            //This may cause duplicate requests if we let it through in retail
            if (exception == null)
                throw new InternalException();

            if (returnResult == null) {
                returnResult = new ConnectionReturnResult(requests.Length);
            }
            // "abortedRequestExeption" is assigned to the "abortedRequest" or to the very first request if the latest is null
            // Everyone else will get "exception"
            for (int i = 0; i < requests.Length; ++i)
            {
#if DEBUG
                //This may cause duplicate requests if we let it through in retail but it's may be expensive to catch here
                for (int j = 0; j <  returnResult.m_Context.Count; ++j)
                    if ((object)returnResult.m_Context[j].Request == (object) requests[i])
                        throw new InternalException();
#endif

                if (i == 0)
                    returnResult.m_Context.Add(new RequestContext(requests[i], firstRequestException));
                else
                    returnResult.m_Context.Add(new RequestContext(requests[i], exception));
            }
        }
        /*++

            ParseStreamData

            Handles parsing of the blocks of data received after buffer,
             distributes the data to stream constructors as needed

            returnResult - contains a object containing Requests
                that must be notified upon return from callback

        --*/
        private DataParseStatus ParseStreamData(ref ConnectionReturnResult returnResult)
        {
            GlobalLog.Enter("Connection#" + ValidationHelper.HashString(this) + "::ParseStreamData");

            if (m_CurrentRequest == null)
            {
                GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::ParseStreamData - Aborted Request, return DataParseStatus.Invalid");
                m_ParseError.Section = WebParseErrorSection.Generic;
                m_ParseError.Code    = WebParseErrorCode.UnexpectedServerResponse;
                return DataParseStatus.Invalid;
            }

            bool fHaveChunked = false;
            bool dummyResponseStream;
            // content-length if there is one
            long contentLength = ProcessHeaderData(ref fHaveChunked, m_CurrentRequest, out dummyResponseStream);

            GlobalLog.Assert(!fHaveChunked || contentLength == -1, "Connection#{0}::ParseStreamData()|fHaveChunked but contentLength != -1", ValidationHelper.HashString(this));

            if (contentLength == c_InvalidContentLength)
            {
                m_ParseError.Section = WebParseErrorSection.ResponseHeader;
                m_ParseError.Code    = WebParseErrorCode.InvalidContentLength;
                return DataParseStatus.Invalid;
            }

            // bytes left over that have not been parsed
            int bufferLeft = (m_BytesRead - m_BytesScanned);

            if (m_ResponseData.m_StatusCode > HttpWebRequest.MaxOkStatus)
            {
                // This will tell the request to be prepared for possible connection drop
                // Also that will stop writing on the wire if the connection is not kept alive
                m_CurrentRequest.ErrorStatusCodeNotify(this, m_KeepAlive, false);
            }

            int bytesToCopy;
            //
            //  If pipelining, then look for extra data that could
            //  be part of of another stream, if its there,
            //  then we need to copy it, add it to a stream,
            //  and then continue with the next headers
            //

            if (dummyResponseStream)
            {
                bytesToCopy = 0;
                fHaveChunked = false;
            }
            else
            {
                bytesToCopy = -1;

                if (!fHaveChunked && (contentLength <= (long)Int32.MaxValue))
                {
                    bytesToCopy = (int)contentLength;
                }
            }

            DataParseStatus result;

            GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseStreamData() bytesToCopy:" + bytesToCopy + " bufferLeft:" + bufferLeft);

            if (m_CurrentRequest.IsWebSocketRequest && m_ResponseData.m_StatusCode == HttpStatusCode.SwitchingProtocols)
            {
                m_ResponseData.m_ConnectStream = new ConnectStream(this, m_ReadBuffer, m_BytesScanned, bufferLeft, bufferLeft, fHaveChunked, m_CurrentRequest);

                // The parsing will be resumed from m_BytesScanned when response stream is closed.
                result = DataParseStatus.Done;
                ClearReaderState();
            }
            else if (bytesToCopy != -1 && bytesToCopy <= bufferLeft)
            {
                m_ResponseData.m_ConnectStream = new ConnectStream(this, m_ReadBuffer, m_BytesScanned, bytesToCopy, dummyResponseStream? 0: contentLength, fHaveChunked, m_CurrentRequest);

                // The parsing will be resumed from m_BytesScanned when response stream is closed.
                result = DataParseStatus.ContinueParsing;
                m_BytesScanned += bytesToCopy;
            }
            else
            {
                m_ResponseData.m_ConnectStream = new ConnectStream(this, m_ReadBuffer, m_BytesScanned, bufferLeft, dummyResponseStream? 0: contentLength, fHaveChunked, m_CurrentRequest);

                // This is the default case where we have a buffer with no more streams except the last one to create so we create it.
                // Note the buffer is fully consumed so we can reset the buffer offests.
                result = DataParseStatus.Done;
                ClearReaderState();
            }

            m_ResponseData.m_ContentLength = contentLength;
            ConnectionReturnResult.Add(ref returnResult, m_CurrentRequest, m_ResponseData.Clone());

#if DEBUG
            GlobalLog.DebugUpdateRequest(m_CurrentRequest, this, GlobalLog.WaitingForReadDoneFlag);
#endif

            GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::ParseStreamData");
            return result; // response stream is taking over the reading
        }
 internal void WriteStartNextRequest(HttpWebRequest request, ref ConnectionReturnResult returnResult)
 {
     TriState unspecified = TriState.Unspecified;
     HttpWebRequest nextRequest = null;
     bool calledCloseConnection = false;
     this.InternalWriteStartNextRequest(request, ref calledCloseConnection, ref unspecified, ref nextRequest, ref returnResult);
     if (!calledCloseConnection && (unspecified != TriState.Unspecified))
     {
         this.CompleteStartRequest(false, nextRequest, unspecified);
     }
 }
        /*++

            ReadStartNextRequest

            This method is called by a stream interface when it's done reading.
            We might possible free up the connection for another request here.

            Called when we think we might need to start another request because
            a read completed.

        --*/
        internal void ReadStartNextRequest(WebRequest currentRequest, ref ConnectionReturnResult returnResult)
        {
            GlobalLog.Enter("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest" + " WriteDone:" + m_WriteDone + " ReadDone:" + m_ReadDone + " WaitList:" + m_WaitList.Count + " WriteList:" + m_WriteList.Count);
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest");

            HttpWebRequest nextRequest = null;
            TriState startRequestResult = TriState.Unspecified;
            bool calledCloseConnection = false;
            bool mustExit = false;

            // ReadStartNextRequest is called by ConnectStream.CallDone: This guarantees that the request
            // is done and the response (response stream) was closed. Remove the reservation for the request.
            int currentCount = Interlocked.Decrement(ref m_ReservedCount);
            GlobalLog.Assert(currentCount >= 0, "m_ReservedCount must not be < 0 when decremented.");

            try {
                lock(this) {
                    if (m_WriteList.Count > 0 && (object)currentRequest == m_WriteList[0])
                    {
                        // advance back to state 0
                        m_ReadState = ReadState.Start;
                        m_WriteList.RemoveAt(0);

                        // Must reset ConnectStream here to prevent a leak through the stream of the last request on each connection.
                        m_ResponseData.m_ConnectStream = null;

                        GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest() Removed request#" + ValidationHelper.HashString(currentRequest) + " from m_WriteList. New m_WriteList.Count:" + m_WriteList.Count.ToString());
                    }
                    else
                    {
                        GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest() The request#" + ValidationHelper.HashString(currentRequest) + " was disassociated so do nothing.  m_WriteList.Count:" + m_WriteList.Count.ToString());
                        mustExit = true;;
                    }

                    //
                    // Since this is called after we're done reading the current
                    // request, if we're not doing keepalive and we're done
                    // writing we can close the connection now.
                    //
                    if(!mustExit)
                    {
                        //
                        // m_ReadDone==true is implied because we just finished a request but really the value must still be false here
                        //
                        if (m_ReadDone)
                            throw new InternalException();  // other requests may already started reading on this connection, need a QFE

                        if (!m_KeepAlive || m_Error != WebExceptionStatus.Success || !CanBePooled)
                        {
                            GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest() KeepAlive:" + m_KeepAlive + " WriteDone:" + m_WriteDone);
                            // Finished one request and connection is closing.
                            // We will not read from this connection so set readDone = true
                            m_ReadDone = true;

                            if (m_WriteDone)
                            {

                                // We could be closing because of an unexpected keep-alive
                                // failure, ie we pipelined a few requests and in the middle
                                // the remote server stopped doing keep alive. In this
                                // case m_Error could be success, which would be misleading.
                                // So in that case we'll set it to KeepAliveFailure.

                                if (m_Error == WebExceptionStatus.Success) {
                                    // Only reason we could have gotten here is because
                                    // we're not keeping the connection alive.
                                    m_Error = WebExceptionStatus.KeepAliveFailure;
                                }

                                // PrepareCloseConnectionSocket has to be called with the critical section held.
                                PrepareCloseConnectionSocket(ref returnResult);
                                calledCloseConnection = true;
                                Close();
                            }
                        }
                        else
                        {
                            // We try to sort out KeepAliveFailure thing (search by context)
                            m_AtLeastOneResponseReceived = true;

                            if (m_WriteList.Count != 0)
                            {
                                // If a *pipelined* request that is being submitted has finished with the headers, post a receive
                                nextRequest = m_WriteList[0] as HttpWebRequest;
                                // If the active request has not finished its headers we can set m_ReadDone = true
                                // and that will be changed when said request will call CheckStartReceive
                                if (!nextRequest.HeadersCompleted)
                                {
                                    nextRequest = null;
                                    m_ReadDone = true;
                                }
                            }
                            // If there are no requests left to write (means pipeline),
                            // we can get the next request from wait list going now.
                            else
                            {
                                m_ReadDone = true;

                                // Sometime we get a response before completing the body in which case
                                // we defer next request to WriteStartNextRequest
                                if (m_WriteDone)
                                {
                                    nextRequest = CheckNextRequest();

                                    if (nextRequest != null )
                                    {
                                        // We cannot have HeadersCompleted on the request that was not placed yet on the write list
                                        if(nextRequest.HeadersCompleted) // TODO: change to be Assert but only when stress got stable-stable
                                            throw new InternalException();

                                        // This codepath doesn't handle the case where the server has closed the
                                        // Connection because we just finished using it and didn't get a
                                        // Connection: close header.
                                        startRequestResult = StartRequest(nextRequest, false);
                                        GlobalLog.Assert(startRequestResult != TriState.Unspecified, "ReadStartNextRequest got TriState.Unspecified from StartRequest, things are about to hang!");
                                    }
                                    else
                                    {
                                        //There are no other requests to process, so make connection avaliable for all
                                        m_Free = true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            finally
            {
                CheckIdle();
                //set result here to prevent nesting of readstartnextrequest.
                if(returnResult != null){
                    ConnectionReturnResult.SetResponses(returnResult);
                }
            }

            if(!mustExit && !calledCloseConnection)
            {
                if (startRequestResult != TriState.Unspecified)
                {
                    CompleteStartRequest(false, nextRequest, startRequestResult);
                }
                else if (nextRequest != null)
                {
                    // Handling receive, note that is for pipelinning case only !
                    if (!nextRequest.Async)
                    {
                        nextRequest.ConnectionReaderAsyncResult.InvokeCallback();
                    }
                    else
                    {
                        if (m_BytesScanned < m_BytesRead)
                        {
                            GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest() Calling ReadComplete, bytes unparsed = " + (m_BytesRead - m_BytesScanned));
                            ReadComplete(0, WebExceptionStatus.Success);
                        }
                        else if (Thread.CurrentThread.IsThreadPoolThread)
                        {
                            GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest() Calling PostReceive().");
                            PostReceive();
                        }
                        else
                        {
                            // Offload to the threadpool to protect against the case where one request's thread posts IO that another request
                            // depends on, but the first thread dies in the mean time.
                            GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest() ThreadPool.UnsafeQueueUserWorkItem(m_PostReceiveDelegate, this)");
                            ThreadPool.UnsafeQueueUserWorkItem(m_PostReceiveDelegate, this);
                        }
                    }
                }
            }
            GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::ReadStartNextRequest");
        }
Example #15
0
        /*
            Method: DoSubmitRequestProcessing

            Does internal processing of redirect and request retries for authentication
            Assumes that it cannot block, this returns a state var indicating when it
            needs to block

            Assumes that we are never called with a null response

            Input:
                none

            Returns:
                HttpProcessingResult -

        */

        //
        // ASSUMPTION: If this method throws the exception must be caught and handled
        // appropriatelly by the caller.
        //
        private HttpProcessingResult DoSubmitRequestProcessing(ref Exception exception)
        {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::DoSubmitRequestProcessing");
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::ErrorStatusCodeNotify");
            HttpProcessingResult result = HttpProcessingResult.Continue;

            m_Retry = false;
            bool ntlmFollowupRequest = NtlmKeepAlive;

            try
            {
                //
                // We have a response of some sort, see if we need to resubmit
                // it do to authentication, redirection or something
                // else, then handle clearing out state and draining out old response.
                //
                if (_HttpResponse != null) {
                    // give apps the chance to examine the headers of the new response
                    if (_CookieContainer != null) {
                        CookieModule.OnReceivedHeaders(this);
                    }

                    ProxyAuthenticationState.Update(this);
                    ServerAuthenticationState.Update(this);
                }

                bool resubmit = false;
                bool checkNextProxy = true;
                bool disableUpload = false;
                if (_HttpResponse == null)
                {
                    resubmit = true;
                }
                else if (CheckResubmitForCache(ref exception) || CheckResubmit(ref exception, ref disableUpload))
                {
                    resubmit = true;
                    checkNextProxy = false;
                }
                else if (disableUpload) // but !CheckResubmit
                {
                    // The user needs to upload the data before we do the redirect.  Reprocess the response in
                    // Begin/GetResponse CheckDeferredCallDone.
                    resubmit = false;
                    checkNextProxy = false;

                    result = HttpProcessingResult.WriteWait; // Waiting for upload
                    // Undo CheckResubmit's state changes and put the request back in m_PendingReturnResult.
                    _AutoRedirects--;
                    OpenWriteSideResponseWindow();
                    ConnectionReturnResult connectionResult = new ConnectionReturnResult(1);
                    ConnectionReturnResult.Add(ref connectionResult, this, _HttpResponse.CoreResponseData);
                    m_PendingReturnResult = connectionResult;
                    _HttpResponse = null;
                    // We're not expecting a response from the server after the user finishes uploading.
                    _SubmitWriteStream.FinishedAfterWrite = true;
                    SetRequestContinue();
                }

                // See if we're doing proxy failover.  If so, see if there's another one.
                // 

                ServicePoint servicePoint = null;
                if (checkNextProxy)
                {
                    WebException webException = exception as WebException;
                    if (webException != null && webException.InternalStatus == WebExceptionInternalStatus.ServicePointFatal)
                    {
                        ProxyChain chain = _ProxyChain;
                        if (chain != null)
                        {
                            servicePoint = ServicePointManager.FindServicePoint(chain);
                        }
                        resubmit = servicePoint != null;
                    }
                }

                if (resubmit)
                {
                    GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::DoSubmitRequestProcessing() resubmiting this request.");

                    // Here is a little hack for [....] looping through BeginSubmitRequest.
                    // We want to unlock cache protocol only if this is NOT a retry.
                    if (CacheProtocol != null && _HttpResponse != null)
                        CacheProtocol.Reset();

                    ClearRequestForResubmit(ntlmFollowupRequest);

                    // In these cases, we don't know whether to keep the credentials for the follow-up request or not.
                    // Different auth schemes have different requirements.  The typical case is to keep them - NTLM
                    // requires this path in order to work at all.  But Kerberos for example can give a 401 here.
                    // Set a flag saying that if we get a 401, start over without credentials.
                    WebException e = exception as WebException;
                    if(e != null){
                        if (e.Status == WebExceptionStatus.PipelineFailure || e.Status == WebExceptionStatus.KeepAliveFailure) {
                            m_Extra401Retry = true;
                        }
                    }

                    if (servicePoint == null)
                    {
                        servicePoint = FindServicePoint(true);
                    }
                    else
                    {
                        _ServicePoint = servicePoint;
                    }

                    if (Async) {
                        SubmitRequest(servicePoint);
                    }
                    else {
                        // under [....] conditions, we let GetResponse() loop calling BeginSubmitRequest() until we're done
                        m_Retry = true;
                    }
                    result = HttpProcessingResult.WriteWait;
                }
            }
            finally
            {
                if (result == HttpProcessingResult.Continue)
                {
                    ClearAuthenticatedConnectionResources();
                }
            }

            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::DoSubmitRequestProcessing", result.ToString());
            return result;
        }
Example #16
0
        internal void WriteCallDone(ConnectStream stream, ConnectionReturnResult returnResult)
        {
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone()");

            // Make sure this is the user stream.
            if (!object.ReferenceEquals(stream, _OldSubmitWriteStream != null ? _OldSubmitWriteStream : _SubmitWriteStream))
            {
                GlobalLog.Assert(object.ReferenceEquals(stream, _SubmitWriteStream), "HttpWebRequest#{0}::CallDone|Called from invalid stream.", ValidationHelper.HashString(this));
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone() - called for resubmit stream");
                stream.ProcessWriteCallDone(returnResult);
                return;
            }

            // If we're still writing headers in GetRequestStream, don't delay, or GetRequestStream will hang.
            if (!UserRetrievedWriteStream)
            {
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone() - called during headers");
                stream.ProcessWriteCallDone(returnResult);
                return;
            }

            // In some cases such as redirects, we do not expect a response from the server after we finish writing.
            if (stream.FinishedAfterWrite)
            {
                stream.ProcessWriteCallDone(returnResult);
                return;
            }

            object pendResult = returnResult == null ? (object) Missing.Value : returnResult;
            object oldResult = Interlocked.CompareExchange(ref m_PendingReturnResult, pendResult, null);
            if (oldResult == DBNull.Value)
            {
                stream.ProcessWriteCallDone(returnResult);
            }
#if TRAVE
            else if (oldResult == null)
            {
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone() - deferring processing");
            }
            else
            {
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone() - ignoring duplicate call.  typeof(oldResult):" + oldResult.GetType().ToString());
            }
#endif
        }
Example #17
0
        internal void WriteCallDone(ConnectStream stream, ConnectionReturnResult returnResult)
        {
            GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone()");

            // Make sure this is the user stream.
            if (!object.ReferenceEquals(stream, _OldSubmitWriteStream != null ? _OldSubmitWriteStream : _SubmitWriteStream))
            {
                GlobalLog.Assert(object.ReferenceEquals(stream, _SubmitWriteStream), "HttpWebRequest#{0}::CallDone|Called from invalid stream.", ValidationHelper.HashString(this));
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone() - called for resubmit stream");
                stream.ProcessWriteCallDone(returnResult);
                return;
            }

            // If we're still writing headers in GetRequestStream, don't delay, or GetRequestStream will hang.
            if (!UserRetrievedWriteStream)
            {
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::WriteCallDone() - called during headers");
                stream.ProcessWriteCallDone(returnResult);
                return;
            }

            object pendResult = returnResult == null ? (object) Missing.Value : returnResult;
            object oldResult = Interlocked.CompareExchange(ref m_PendingReturnResult, pendResult, null);
            if (oldResult == DBNull.Value)
            {
                stream.ProcessWriteCallDone(returnResult);
            }
        }
        private DataParseStatus ParseResponseData(ref ConnectionReturnResult returnResult, out bool requestDone, out CoreResponseData continueResponseData)
        {
            DataParseStatus status2;
            DataParseStatus needMoreData = DataParseStatus.NeedMoreData;
            requestDone = false;
            continueResponseData = null;
            switch (this.m_ReadState)
            {
                case ReadState.Start:
                    break;

                case ReadState.StatusLine:
                    goto Label_00F6;

                case ReadState.Headers:
                    goto Label_0299;

                case ReadState.Data:
                    goto Label_050A;

                default:
                    goto Label_0515;
            }
        Label_002C:
            if (this.m_CurrentRequest == null)
            {
                lock (this)
                {
                    if ((this.m_WriteList.Count == 0) || ((this.m_CurrentRequest = this.m_WriteList[0] as HttpWebRequest) == null))
                    {
                        this.m_ParseError.Section = WebParseErrorSection.Generic;
                        this.m_ParseError.Code = WebParseErrorCode.Generic;
                        needMoreData = DataParseStatus.Invalid;
                        goto Label_0515;
                    }
                }
            }
            this.m_KeepAlive &= this.m_CurrentRequest.KeepAlive || this.m_CurrentRequest.NtlmKeepAlive;
            this.m_MaximumResponseHeadersLength = this.m_CurrentRequest.MaximumResponseHeadersLength * 0x400;
            this.m_ResponseData = new CoreResponseData();
            this.m_ReadState = ReadState.StatusLine;
            this.m_TotalResponseHeadersLength = 0;
            this.InitializeParseStatusLine();
        Label_00F6:
            if (SettingsSectionInternal.Section.UseUnsafeHeaderParsing)
            {
                int[] numArray2 = new int[4];
                numArray2[1] = this.m_StatusLineValues.MajorVersion;
                numArray2[2] = this.m_StatusLineValues.MinorVersion;
                numArray2[3] = this.m_StatusLineValues.StatusCode;
                int[] statusLineInts = numArray2;
                if (this.m_StatusLineValues.StatusDescription == null)
                {
                    this.m_StatusLineValues.StatusDescription = "";
                }
                status2 = this.ParseStatusLine(this.m_ReadBuffer, this.m_BytesRead, ref this.m_BytesScanned, ref statusLineInts, ref this.m_StatusLineValues.StatusDescription, ref this.m_StatusState, ref this.m_ParseError);
                this.m_StatusLineValues.MajorVersion = statusLineInts[1];
                this.m_StatusLineValues.MinorVersion = statusLineInts[2];
                this.m_StatusLineValues.StatusCode = statusLineInts[3];
            }
            else
            {
                status2 = ParseStatusLineStrict(this.m_ReadBuffer, this.m_BytesRead, ref this.m_BytesScanned, ref this.m_StatusState, this.m_StatusLineValues, this.m_MaximumResponseHeadersLength, ref this.m_TotalResponseHeadersLength, ref this.m_ParseError);
            }
            if (status2 == DataParseStatus.Done)
            {
                if (Logging.On)
                {
                    Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_received_status_line", new object[] { this.m_StatusLineValues.MajorVersion + "." + this.m_StatusLineValues.MinorVersion, this.m_StatusLineValues.StatusCode, this.m_StatusLineValues.StatusDescription }));
                }
                this.SetStatusLineParsed();
                this.m_ReadState = ReadState.Headers;
                this.m_ResponseData.m_ResponseHeaders = new WebHeaderCollection(WebHeaderCollectionType.HttpWebResponse);
            }
            else
            {
                if (status2 != DataParseStatus.NeedMoreData)
                {
                    needMoreData = status2;
                }
                goto Label_0515;
            }
        Label_0299:
            if (this.m_BytesScanned >= this.m_BytesRead)
            {
                goto Label_0515;
            }
            if (SettingsSectionInternal.Section.UseUnsafeHeaderParsing)
            {
                status2 = this.m_ResponseData.m_ResponseHeaders.ParseHeaders(this.m_ReadBuffer, this.m_BytesRead, ref this.m_BytesScanned, ref this.m_TotalResponseHeadersLength, this.m_MaximumResponseHeadersLength, ref this.m_ParseError);
            }
            else
            {
                status2 = this.m_ResponseData.m_ResponseHeaders.ParseHeadersStrict(this.m_ReadBuffer, this.m_BytesRead, ref this.m_BytesScanned, ref this.m_TotalResponseHeadersLength, this.m_MaximumResponseHeadersLength, ref this.m_ParseError);
            }
            if ((status2 == DataParseStatus.Invalid) || (status2 == DataParseStatus.DataTooBig))
            {
                needMoreData = status2;
                goto Label_0515;
            }
            if (status2 != DataParseStatus.Done)
            {
                goto Label_0515;
            }
            if (Logging.On)
            {
                Logging.PrintInfo(Logging.Web, this, SR.GetString("net_log_received_headers", new object[] { this.m_ResponseData.m_ResponseHeaders.ToString(true) }));
            }
            if (this.m_IISVersion == -1)
            {
                int num;
                string server = this.m_ResponseData.m_ResponseHeaders.Server;
                if (((server != null) && server.ToLower(CultureInfo.InvariantCulture).Contains("microsoft-iis")) && ((server.IndexOf("/")++ > 0) && (num < server.Length)))
                {
                    this.m_IISVersion = server[num++] - '0';
                    while ((num < server.Length) && char.IsDigit(server[num]))
                    {
                        this.m_IISVersion = ((this.m_IISVersion * 10) + server[num++]) - 0x30;
                    }
                }
                if ((this.m_IISVersion == -1) && (this.m_ResponseData.m_StatusCode != HttpStatusCode.Continue))
                {
                    this.m_IISVersion = 0;
                }
            }
            if ((this.m_ResponseData.m_StatusCode == HttpStatusCode.Continue) || (this.m_ResponseData.m_StatusCode == HttpStatusCode.BadRequest))
            {
                if (this.m_ResponseData.m_StatusCode == HttpStatusCode.BadRequest)
                {
                    if (((this.ServicePoint.HttpBehaviour == HttpBehaviour.HTTP11) && (this.m_CurrentRequest.HttpWriteMode == HttpWriteMode.Chunked)) && ((this.m_ResponseData.m_ResponseHeaders.Via != null) && (string.Compare(this.m_ResponseData.m_StatusDescription, "Bad Request ( The HTTP request includes a non-supported header. Contact the Server administrator.  )", StringComparison.OrdinalIgnoreCase) == 0)))
                    {
                        this.ServicePoint.HttpBehaviour = HttpBehaviour.HTTP11PartiallyCompliant;
                    }
                }
                else
                {
                    this.m_CurrentRequest.Saw100Continue = true;
                    if (!this.ServicePoint.Understands100Continue)
                    {
                        this.ServicePoint.Understands100Continue = true;
                    }
                    continueResponseData = this.m_ResponseData;
                    goto Label_002C;
                }
            }
            this.m_ReadState = ReadState.Data;
        Label_050A:
            requestDone = true;
            needMoreData = this.ParseStreamData(ref returnResult);
        Label_0515:
            if (this.m_BytesScanned == this.m_BytesRead)
            {
                this.ClearReaderState();
            }
            return needMoreData;
        }
 private void InternalWriteStartNextRequest(HttpWebRequest request, ref bool calledCloseConnection, ref TriState startRequestResult, ref HttpWebRequest nextRequest, ref ConnectionReturnResult returnResult)
 {
     lock (this)
     {
         this.m_WriteDone = true;
         if ((!this.m_KeepAlive || (this.m_Error != WebExceptionStatus.Success)) || !base.CanBePooled)
         {
             if (this.m_ReadDone)
             {
                 if (this.m_Error == WebExceptionStatus.Success)
                 {
                     this.m_Error = WebExceptionStatus.KeepAliveFailure;
                 }
                 this.PrepareCloseConnectionSocket(ref returnResult);
                 calledCloseConnection = true;
                 this.Close();
             }
             else if (this.m_Error != WebExceptionStatus.Success)
             {
             }
         }
         else
         {
             if (this.m_Pipelining || this.m_ReadDone)
             {
                 nextRequest = this.CheckNextRequest();
             }
             if (nextRequest != null)
             {
                 startRequestResult = this.StartRequest(nextRequest, false);
             }
         }
     }
 }
        internal static void Add(ref ConnectionReturnResult returnResult, HttpWebRequest request, CoreResponseData coreResponseData)
        {
            if (coreResponseData == null)
                throw new InternalException(); //This may cause duplicate requests if we let it through in retail

            if (returnResult == null) {
                returnResult = new ConnectionReturnResult();
            }

#if DEBUG
            //This may cause duplicate requests if we let it through in retail but it's may be expensive to catch here
            for (int j = 0; j <  returnResult.m_Context.Count; ++j)
                if ((object)returnResult.m_Context[j].Request == (object) request)
                    throw new InternalException();
#endif

            returnResult.m_Context.Add(new RequestContext(request, coreResponseData));
        }
Example #21
0
 internal static void AddExceptionRange(ref ConnectionReturnResult returnResult, HttpWebRequest[] requests, Exception exception)
 {
     AddExceptionRange(ref returnResult, requests, exception, exception);
 }
        internal void WriteStartNextRequest(HttpWebRequest request, ref ConnectionReturnResult returnResult) {
            GlobalLog.Enter("Connection#" + ValidationHelper.HashString(this) + "::WriteStartNextRequest" + " WriteDone:" + m_WriteDone + " ReadDone:" + m_ReadDone + " WaitList:" + m_WaitList.Count + " WriteList:" + m_WriteList.Count);
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "Connection#" + ValidationHelper.HashString(this) + "::WriteStartNextRequest");

            TriState startRequestResult = TriState.Unspecified;
            HttpWebRequest nextRequest = null;
            bool calledCloseConnection = false;

            InternalWriteStartNextRequest(request, ref calledCloseConnection, ref startRequestResult, ref nextRequest, ref returnResult);

            GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::WriteStartNextRequest: Pipelining:" + m_Pipelining + " nextRequest#"+ValidationHelper.HashString(nextRequest));

            if (!calledCloseConnection && startRequestResult != TriState.Unspecified)
            {
                GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::WriteStartNextRequest calling CompleteStartRequest");
                CompleteStartRequest(false, nextRequest, startRequestResult);
            }

            GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::WriteStartNextRequest");
        }
 internal void ReadStartNextRequest(WebRequest currentRequest, ref ConnectionReturnResult returnResult)
 {
     HttpWebRequest request = null;
     TriState unspecified = TriState.Unspecified;
     bool flag = false;
     bool flag2 = false;
     Interlocked.Decrement(ref this.m_ReservedCount);
     try
     {
         lock (this)
         {
             if ((this.m_WriteList.Count > 0) && (currentRequest == this.m_WriteList[0]))
             {
                 this.m_ReadState = ReadState.Start;
                 this.m_WriteList.RemoveAt(0);
                 this.m_ResponseData.m_ConnectStream = null;
             }
             else
             {
                 flag2 = true;
             }
             if (!flag2)
             {
                 if (this.m_ReadDone)
                 {
                     throw new InternalException();
                 }
                 if ((!this.m_KeepAlive || (this.m_Error != WebExceptionStatus.Success)) || !base.CanBePooled)
                 {
                     this.m_ReadDone = true;
                     if (this.m_WriteDone)
                     {
                         if (this.m_Error == WebExceptionStatus.Success)
                         {
                             this.m_Error = WebExceptionStatus.KeepAliveFailure;
                         }
                         this.PrepareCloseConnectionSocket(ref returnResult);
                         flag = true;
                         this.Close();
                     }
                 }
                 else
                 {
                     this.m_AtLeastOneResponseReceived = true;
                     if (this.m_WriteList.Count != 0)
                     {
                         request = this.m_WriteList[0] as HttpWebRequest;
                         if (!request.HeadersCompleted)
                         {
                             request = null;
                             this.m_ReadDone = true;
                         }
                     }
                     else
                     {
                         this.m_ReadDone = true;
                         if (this.m_WriteDone)
                         {
                             request = this.CheckNextRequest();
                             if (request != null)
                             {
                                 if (request.HeadersCompleted)
                                 {
                                     throw new InternalException();
                                 }
                                 unspecified = this.StartRequest(request, false);
                             }
                             else
                             {
                                 this.m_Free = true;
                             }
                         }
                     }
                 }
             }
         }
     }
     finally
     {
         this.CheckIdle();
         if (returnResult != null)
         {
             ConnectionReturnResult.SetResponses(returnResult);
         }
     }
     if (!flag2 && !flag)
     {
         if (unspecified != TriState.Unspecified)
         {
             this.CompleteStartRequest(false, request, unspecified);
         }
         else if (request != null)
         {
             if (!request.Async)
             {
                 request.ConnectionReaderAsyncResult.InvokeCallback();
             }
             else if (this.m_BytesScanned < this.m_BytesRead)
             {
                 this.ReadComplete(0, WebExceptionStatus.Success);
             }
             else if (Thread.CurrentThread.IsThreadPoolThread)
             {
                 this.PostReceive();
             }
             else
             {
                 ThreadPool.UnsafeQueueUserWorkItem(m_PostReceiveDelegate, this);
             }
         }
     }
 }
 internal static void AddExceptionRange(ref ConnectionReturnResult returnResult, HttpWebRequest [] requests, Exception exception)
 {
     AddExceptionRange(ref returnResult, requests, exception, exception);
 }
Example #25
0
        private static void InvokeConnectionCallback(object objectReturnResult)
        {
            ConnectionReturnResult returnResult = (ConnectionReturnResult)objectReturnResult;

            SetResponses(returnResult);
        }
        internal static void SetResponses(ConnectionReturnResult returnResult) {
            if (returnResult==null){
                return;
            }

            GlobalLog.Print("ConnectionReturnResult#" + ValidationHelper.HashString(returnResult) + "::SetResponses() count=" + returnResult.m_Context.Count.ToString());
            for (int i = 0; i < returnResult.m_Context.Count; i++)
            {
                try {
                    HttpWebRequest request = returnResult.m_Context[i].Request;
#if DEBUG
                    CoreResponseData coreResponseData = returnResult.m_Context[i].CoreResponse as CoreResponseData;
                    if (coreResponseData == null)
                        GlobalLog.DebugRemoveRequest(request);
#endif
                    request.SetAndOrProcessResponse(returnResult.m_Context[i].CoreResponse);
                }
                catch(Exception e) {
                    //ASYNCISSUE
                    // on error, with more than one callback need to queue others off to another thread

                    GlobalLog.Print("ConnectionReturnResult#" + ValidationHelper.HashString(returnResult) + "::Exception"+e);
                    returnResult.m_Context.RemoveRange(0,(i+1));
                    if (returnResult.m_Context.Count > 0)
                    {
                        ThreadPool.UnsafeQueueUserWorkItem(s_InvokeConnectionCallback, returnResult);
                    }
                    throw;
                }
            }

            returnResult.m_Context.Clear();
        }
 private void PrepareCloseConnectionSocket(ref ConnectionReturnResult returnResult)
 {
     this.m_IdleSinceUtc = DateTime.MinValue;
     base.CanBePooled = false;
     if ((this.m_WriteList.Count != 0) || (this.m_WaitList.Count != 0))
     {
         HttpWebRequest lockedRequest = this.LockedRequest;
         if (lockedRequest != null)
         {
             bool flag = false;
             foreach (HttpWebRequest request2 in this.m_WriteList)
             {
                 if (request2 == lockedRequest)
                 {
                     flag = true;
                 }
             }
             if (!flag)
             {
                 foreach (WaitListItem item in this.m_WaitList)
                 {
                     if (item.Request == lockedRequest)
                     {
                         flag = true;
                         break;
                     }
                 }
             }
             if (flag)
             {
                 this.UnlockRequest();
             }
         }
         HttpWebRequest[] requests = null;
         if (this.m_WaitList.Count != 0)
         {
             requests = new HttpWebRequest[this.m_WaitList.Count];
             for (int i = 0; i < this.m_WaitList.Count; i++)
             {
                 requests[i] = this.m_WaitList[i].Request;
             }
             ConnectionReturnResult.AddExceptionRange(ref returnResult, requests, ExceptionHelper.IsolatedException);
         }
         if (this.m_WriteList.Count != 0)
         {
             Exception innerException = this.m_InnerException;
             if (!(innerException is WebException) && !(innerException is SecurityException))
             {
                 if (this.m_Error == WebExceptionStatus.ServerProtocolViolation)
                 {
                     string webStatusString = NetRes.GetWebStatusString(this.m_Error);
                     string str2 = "";
                     if (this.m_ParseError.Section != WebParseErrorSection.Generic)
                     {
                         str2 = str2 + " Section=" + this.m_ParseError.Section.ToString();
                     }
                     if (this.m_ParseError.Code != WebParseErrorCode.Generic)
                     {
                         str2 = str2 + " Detail=" + SR.GetString("net_WebResponseParseError_" + this.m_ParseError.Code.ToString());
                     }
                     if (str2.Length != 0)
                     {
                         webStatusString = webStatusString + "." + str2;
                     }
                     innerException = new WebException(webStatusString, innerException, this.m_Error, null, WebExceptionInternalStatus.RequestFatal);
                 }
                 else if (this.m_Error == WebExceptionStatus.SecureChannelFailure)
                 {
                     innerException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.SecureChannelFailure), WebExceptionStatus.SecureChannelFailure);
                 }
                 else if (this.m_Error == WebExceptionStatus.Timeout)
                 {
                     innerException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.Timeout), WebExceptionStatus.Timeout);
                 }
                 else if (this.m_Error == WebExceptionStatus.RequestCanceled)
                 {
                     innerException = new WebException(NetRes.GetWebStatusString("net_requestaborted", WebExceptionStatus.RequestCanceled), WebExceptionStatus.RequestCanceled, WebExceptionInternalStatus.RequestFatal, innerException);
                 }
                 else if ((this.m_Error == WebExceptionStatus.MessageLengthLimitExceeded) || (this.m_Error == WebExceptionStatus.TrustFailure))
                 {
                     innerException = new WebException(NetRes.GetWebStatusString("net_connclosed", this.m_Error), this.m_Error, WebExceptionInternalStatus.RequestFatal, innerException);
                 }
                 else
                 {
                     if (this.m_Error == WebExceptionStatus.Success)
                     {
                         throw new InternalException();
                     }
                     bool flag2 = false;
                     bool flag3 = false;
                     if (this.m_WriteList.Count != 1)
                     {
                         flag2 = true;
                     }
                     else if (this.m_Error == WebExceptionStatus.KeepAliveFailure)
                     {
                         HttpWebRequest request3 = (HttpWebRequest) this.m_WriteList[0];
                         if (!request3.BodyStarted)
                         {
                             flag3 = true;
                         }
                     }
                     else
                     {
                         flag2 = !this.AtLeastOneResponseReceived && !((HttpWebRequest) this.m_WriteList[0]).BodyStarted;
                     }
                     innerException = new WebException(NetRes.GetWebStatusString("net_connclosed", this.m_Error), this.m_Error, flag3 ? WebExceptionInternalStatus.Isolated : (flag2 ? WebExceptionInternalStatus.Recoverable : WebExceptionInternalStatus.RequestFatal), innerException);
                 }
             }
             WebException exception = new WebException(NetRes.GetWebStatusString("net_connclosed", WebExceptionStatus.PipelineFailure), WebExceptionStatus.PipelineFailure, WebExceptionInternalStatus.Recoverable, innerException);
             requests = new HttpWebRequest[this.m_WriteList.Count];
             this.m_WriteList.CopyTo(requests, 0);
             ConnectionReturnResult.AddExceptionRange(ref returnResult, requests, exception, innerException);
         }
         this.m_WriteList.Clear();
         foreach (WaitListItem item2 in this.m_WaitList)
         {
             NetworkingPerfCounters.Instance.IncrementAverage(NetworkingPerfCounterName.HttpWebRequestAvgQueueTime, item2.QueueStartTime);
         }
         this.m_WaitList.Clear();
     }
     this.CheckIdle();
     if (this.m_Idle)
     {
         GC.SuppressFinalize(this);
     }
     if (!this.m_RemovedFromConnectionList && (this.ConnectionGroup != null))
     {
         this.m_RemovedFromConnectionList = true;
         this.ConnectionGroup.Disassociate(this);
     }
 }
        /*++

            ParseResponseData - Parses the incomming headers, and handles
              creation of new streams that are found while parsing, and passes
              extra data the new streams

            Input:

                returnResult - returns an object containing items that need to be called
                    at the end of the read callback

            Returns:

                bool - true if one should continue reading more data

        --*/
        private DataParseStatus ParseResponseData(ref ConnectionReturnResult returnResult, out bool requestDone, out CoreResponseData continueResponseData)
        {
            GlobalLog.Enter("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData()");

            DataParseStatus parseStatus = DataParseStatus.NeedMoreData;
            DataParseStatus parseSubStatus;

            // Indicates whether or not at least one whole request was processed in this loop.
            // (i.e. Whether ParseStreamData() was called.
            requestDone = false;
            continueResponseData = null;

            // loop in case of multiple sets of headers or streams,
            //  that may be generated due to a pipelined response

                // Invariants: at the start of this loop, m_BytesRead
                // is the number of bytes in the buffer, and m_BytesScanned
                // is how many bytes of the buffer we've consumed so far.
                // and the m_ReadState var will be updated at end of
                // each code path, call to this function to reflect,
                // the state, or error condition of the parsing of data
                //
                // We use the following variables in the code below:
                //
                //  m_ReadState - tracks the current state of our Parsing in a
                //      response. z.B.
                //      Start - initial start state and begining of response
                //      StatusLine - the first line sent in response, include status code
                //      Headers - \r\n delimiated Header parsing until we find entity body
                //      Data - Entity Body parsing, if we have all data, we create stream directly
                //
                //  m_ResponseData - An object used to gather Stream, Headers, and other
                //      tidbits so that a request/Response can receive this data when
                //      this code is finished processing
                //
                //  m_ReadBuffer - Of course the buffer of data we are parsing from
                //
                //  m_BytesScanned - The bytes scanned in this buffer so far,
                //      since its always assumed that parse to completion, this
                //      var becomes ended of known data at the end of this function,
                //      based off of 0
                //
                //  m_BytesRead - The total bytes read in buffer, should be const,
                //      till its updated at end of function.
                //

                //
                // Now attempt to parse the data,
                //   we first parse status line,
                //   then read headers,
                //   and finally transfer results to a new stream, and tell request
                //

                switch (m_ReadState) {

                    case ReadState.Start:


                        if (m_CurrentRequest == null)
                        {
                            lock (this)
                            {
                                if (m_WriteList.Count == 0 || ((m_CurrentRequest = m_WriteList[0] as HttpWebRequest) == null))
                                {
                                    m_ParseError.Section = WebParseErrorSection.Generic;
                                    m_ParseError.Code    = WebParseErrorCode.Generic;
                                    parseStatus = DataParseStatus.Invalid;
                                    break;
                                }
                            }
                        }

                        //
                        // Start of new response. Transfer the keep-alive context from the corresponding request to
                        // the connection
                        //
                        m_KeepAlive &= (m_CurrentRequest.KeepAlive || m_CurrentRequest.NtlmKeepAlive);

                        m_MaximumResponseHeadersLength = m_CurrentRequest.MaximumResponseHeadersLength * 1024;
                        m_ResponseData = new CoreResponseData();
                        m_ReadState = ReadState.StatusLine;
                        m_TotalResponseHeadersLength = 0;

                        InitializeParseStatusLine();
                        goto case ReadState.StatusLine;

                    case ReadState.StatusLine:
                        //
                        // Reads HTTP status response line
                        //
                        if (SettingsSectionInternal.Section.UseUnsafeHeaderParsing)
                        {
                            // This one uses an array to store the parsed values in.  Marshal between this legacy way.
                            int[] statusInts = new int[] { 0, m_StatusLineValues.MajorVersion, m_StatusLineValues.MinorVersion, m_StatusLineValues.StatusCode };
                            if (m_StatusLineValues.StatusDescription == null)
                                m_StatusLineValues.StatusDescription = "";

                            parseSubStatus = ParseStatusLine(
                                m_ReadBuffer, // buffer we're working with
                                m_BytesRead,  // total bytes read so far
                                ref m_BytesScanned, // index off of what we've scanned
                                ref statusInts,
                                ref m_StatusLineValues.StatusDescription,
                                ref m_StatusState,
                                ref m_ParseError);

                            m_StatusLineValues.MajorVersion = statusInts[1];
                            m_StatusLineValues.MinorVersion = statusInts[2];
                            m_StatusLineValues.StatusCode = statusInts[3];
                        }
                        else
                        {
                            parseSubStatus = ParseStatusLineStrict(
                                m_ReadBuffer, // buffer we're working with
                                m_BytesRead,  // total bytes read so far
                                ref m_BytesScanned, // index off of what we've scanned
                                ref m_StatusState,
                                m_StatusLineValues,
                                m_MaximumResponseHeadersLength,
                                ref m_TotalResponseHeadersLength,
                                ref m_ParseError);
                        }

                        if (parseSubStatus == DataParseStatus.Done)
                        {
                            if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_received_status_line, m_StatusLineValues.MajorVersion+"."+m_StatusLineValues.MinorVersion, m_StatusLineValues.StatusCode, m_StatusLineValues.StatusDescription));
                            SetStatusLineParsed();
                            m_ReadState = ReadState.Headers;
                            m_ResponseData.m_ResponseHeaders = new WebHeaderCollection(WebHeaderCollectionType.HttpWebResponse);
                            goto case ReadState.Headers;
                        }
                        else if (parseSubStatus != DataParseStatus.NeedMoreData)
                        {
                            //
                            // report error - either Invalid or DataTooBig
                            //
                            GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() ParseStatusLine() parseSubStatus:" + parseSubStatus.ToString());
                            parseStatus = parseSubStatus;
                            break;
                        }

                        break; // read more data

                    case ReadState.Headers:
                        //
                        // Parse additional lines of header-name: value pairs
                        //
                        if (m_BytesScanned >= m_BytesRead) {
                            //
                            // we already can tell we need more data
                            //
                            break;
                        }

                        if (SettingsSectionInternal.Section.UseUnsafeHeaderParsing)
                        {
                            parseSubStatus = m_ResponseData.m_ResponseHeaders.ParseHeaders(
                                m_ReadBuffer,
                                m_BytesRead,
                                ref m_BytesScanned,
                                ref m_TotalResponseHeadersLength,
                                m_MaximumResponseHeadersLength,
                                ref m_ParseError);
                        }
                        else
                        {
                            parseSubStatus = m_ResponseData.m_ResponseHeaders.ParseHeadersStrict(
                                m_ReadBuffer,
                                m_BytesRead,
                                ref m_BytesScanned,
                                ref m_TotalResponseHeadersLength,
                                m_MaximumResponseHeadersLength,
                                ref m_ParseError);
                        }

                        if (parseSubStatus == DataParseStatus.Invalid || parseSubStatus == DataParseStatus.DataTooBig)
                        {
                            //
                            // report error
                            //
                            GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() ParseHeaders() parseSubStatus:" + parseSubStatus.ToString());
                            parseStatus = parseSubStatus;
                            break;
                        }
                        else if (parseSubStatus == DataParseStatus.Done)
                        {
                            if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_received_headers, m_ResponseData.m_ResponseHeaders.ToString(true)));

                            GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() DataParseStatus.Done StatusCode:" + (int)m_ResponseData.m_StatusCode + " m_BytesRead:" + m_BytesRead + " m_BytesScanned:" + m_BytesScanned);

                            //get the IIS server version
                            if(m_IISVersion == -1){
                                string server = m_ResponseData.m_ResponseHeaders.Server;
                                if (server != null && server.ToLower(CultureInfo.InvariantCulture).Contains("microsoft-iis")){
                                    int i = server.IndexOf("/");
                                    if(i++>0 && i <server.Length){
                                        m_IISVersion = server[i++] - '0';
                                        while(i < server.Length && Char.IsDigit(server[i])) {
                                            m_IISVersion = m_IISVersion*10 + server[i++] - '0';
                                        }
                                    }
                                }
                                //we got a response,so if we don't know the server by now and it wasn't a 100 continue,
                                //we can't assume we will ever know it.  IIS5 sends its server header w/ the continue

                                if(m_IISVersion == -1 && m_ResponseData.m_StatusCode != HttpStatusCode.Continue){
                                    m_IISVersion = 0;
                                }
                            }

                            if (m_ResponseData.m_StatusCode == HttpStatusCode.Continue || m_ResponseData.m_StatusCode == HttpStatusCode.BadRequest) {

                                GlobalLog.Assert(m_CurrentRequest != null, "Connection#{0}::ParseResponseData()|m_CurrentRequest == null", ValidationHelper.HashString(this));
                                GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() HttpWebRequest#" + ValidationHelper.HashString(m_CurrentRequest));

                                if (m_ResponseData.m_StatusCode == HttpStatusCode.BadRequest) {
                                    // If we have a 400 and we were sending a chunked request going through to a proxy with a chunked upload,
                                    // this proxy is a partially compliant so shut off fancy features (pipelining and chunked uploads)
                                    GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() got a 400 StatusDescription:" + m_ResponseData.m_StatusDescription);
                                    if (ServicePoint.HttpBehaviour == HttpBehaviour.HTTP11
                                        && m_CurrentRequest.HttpWriteMode==HttpWriteMode.Chunked
                                        && m_ResponseData.m_ResponseHeaders.Via != null
                                        && string.Compare(m_ResponseData.m_StatusDescription, "Bad Request ( The HTTP request includes a non-supported header. Contact the Server administrator.  )", StringComparison.OrdinalIgnoreCase)==0) {
                                        GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() downgrading server to HTTP11PartiallyCompliant.");
                                        ServicePoint.HttpBehaviour = HttpBehaviour.HTTP11PartiallyCompliant;
                                    }
                                }
                                else {
                                    // If we have an HTTP continue, eat these headers and look
                                    //  for the 200 OK
                                    //
                                    // we got a 100 Continue. set this on the HttpWebRequest
                                    //
                                    m_CurrentRequest.Saw100Continue = true;
                                    if (!ServicePoint.Understands100Continue) {
                                        //
                                        // and start expecting it again if this behaviour was turned off
                                        //
                                        GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() HttpWebRequest#" + ValidationHelper.HashString(m_CurrentRequest) + " ServicePoint#" + ValidationHelper.HashString(ServicePoint) + " sent UNexpected 100 Continue");
                                        ServicePoint.Understands100Continue = true;
                                    }

                                    //
                                    // set Continue Ack on request.
                                    //
                                    GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() calling SetRequestContinue()");
                                    continueResponseData = m_ResponseData;

                                    //if we got a 100continue we ---- it and start looking for a final response
                                    goto case ReadState.Start;
                                }
                            }

                            m_ReadState = ReadState.Data;
                            goto case ReadState.Data;
                        }

                        // need more data,
                        break;

                    case ReadState.Data:

                        // (check status code for continue handling)
                        // 1. Figure out if its Chunked, content-length, or encoded
                        // 2. Takes extra data, place in stream(s)
                        // 3. Wake up blocked stream requests
                        //

                        // Got through one entire response
                        requestDone = true;

                        // parse and create a stream if needed
                        parseStatus = ParseStreamData(ref returnResult);

                        GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() result:" + parseStatus);
                        GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData()" + " WriteDone:" + m_WriteDone + " ReadDone:" + m_ReadDone + " WaitList:" + m_WaitList.Count + " WriteList:" + m_WriteList.Count);
                        break;
                }

            if (m_BytesScanned == m_BytesRead)
                ClearReaderState();

            GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() m_ReadState:" + m_ReadState);
            GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData()", parseStatus.ToString());
            return parseStatus;
        }
Example #29
0
        /*

            HandleError - Handle a protocol error from the server.

            This method is called when we've detected some sort of fatal protocol
            violation while parsing a response, receiving data from the server,
            or failing to connect to the server. We'll fabricate
            a WebException and then call CloseConnection which closes the
            connection as well as informs the request through a callback.

            Input:
                    webExceptionStatus -
                    connectFailure -
                    readFailure -

            Returns: Nothing

        --*/
        internal void HandleConnectStreamException(bool writeDone, bool readDone, WebExceptionStatus webExceptionStatus, ref ConnectionReturnResult returnResult, Exception e)
        {
            if (m_InnerException == null)
            {
                m_InnerException = e;
                if (e is ObjectDisposedException)
                {
                    webExceptionStatus = WebExceptionStatus.RequestCanceled;
                }
            }
            HandleError(writeDone, readDone, webExceptionStatus, ref returnResult);
        }
        /*++

            HandleError - Handle a protocol error from the server.

            This method is called when we've detected some sort of fatal protocol
            violation while parsing a response, receiving data from the server,
            or failing to connect to the server. We'll fabricate
            a WebException and then call CloseConnection which closes the
            connection as well as informs the request through a callback.

            Input:
                    webExceptionStatus -
                    connectFailure -
                    readFailure -

            Returns: Nothing

        --*/
        internal void HandleConnectStreamException(bool writeDone, bool readDone, WebExceptionStatus webExceptionStatus, ref ConnectionReturnResult returnResult, Exception e)
        {
            if (m_InnerException == null)
            {
                m_InnerException = e;
                if (!(e is WebException) && NetworkStream is TlsStream)
                {
                    // Unless a WebException is passed the Connection knows better the error code if the transport is TlsStream
                    webExceptionStatus = ((TlsStream) NetworkStream).ExceptionStatus;
                }
                else if (e is ObjectDisposedException)
                {
                    webExceptionStatus = WebExceptionStatus.RequestCanceled;
                }
            }
            HandleError(writeDone, readDone, webExceptionStatus, ref returnResult);
        }
        private void CallDone(ConnectionReturnResult returnResult)
        {
            GlobalLog.Enter("ConnectStream#" + ValidationHelper.HashString(this) + "::CallDone");
            if ( Interlocked.Increment( ref m_DoneCalled) == 1 )
            {
                if (!WriteStream)
                {
#if DEBUG
                    GlobalLog.DebugRemoveRequest(m_Request);
#endif
                    if (returnResult == null) {
                        //readstartnextrequest will call setresponses internally.
                        m_Connection.ReadStartNextRequest(m_Request, ref returnResult);
                    }
                    else{
                        ConnectionReturnResult.SetResponses(returnResult);
                    }
                }
                else
                {
                    m_Request.WriteCallDone(this, returnResult);
                }
            }
            GlobalLog.Leave("ConnectStream#" + ValidationHelper.HashString(this) + "::CallDone");
        }
        //
        private void HandleError(bool writeDone, bool readDone, WebExceptionStatus webExceptionStatus, ref ConnectionReturnResult returnResult)
        {
            lock(this)
            {
                if (writeDone)
                    m_WriteDone = true;
                if (readDone)
                    m_ReadDone = true;

                GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::HandleError() m_WriteList.Count:" + m_WriteList.Count +
                                " m_WaitList.Count:" + m_WaitList.Count +
                                " new WriteDone:" + m_WriteDone + " new ReadDone:" + m_ReadDone);
                GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::HandleError() current HttpWebRequest#" + ValidationHelper.HashString(m_CurrentRequest));

                if(webExceptionStatus == WebExceptionStatus.Success)
                    throw new InternalException(); //consider making an assert later.

                m_Error = webExceptionStatus;

                PrepareCloseConnectionSocket(ref returnResult);
                // This will kill the socket
                // Must be done inside the lock.  (Stream Close() isn't threadsafe.)
                Close(0);
            }
        }
        private void InternalWriteStartNextRequest(HttpWebRequest request, ref bool calledCloseConnection, ref TriState startRequestResult, ref HttpWebRequest nextRequest, ref ConnectionReturnResult returnResult) {
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "Connection#" + ValidationHelper.HashString(this) + "::InternalWriteStartNextRequest");

            lock(this) {

                GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::WriteStartNextRequest() setting WriteDone:" + m_WriteDone.ToString() + " to true");
                m_WriteDone = true;

                //
                // If we're not doing keep alive, and the read on this connection
                // has already completed, now is the time to close the
                // connection.
                //
                //need to wait for read to set the error
                if (!m_KeepAlive || m_Error != WebExceptionStatus.Success || !CanBePooled) {
                    GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::WriteStartNextRequest() m_WriteList.Count:" + m_WriteList.Count);
                    if (m_ReadDone) {
                        // We could be closing because of an unexpected keep-alive
                        // failure, ie we pipelined a few requests and in the middle
                        // the remote server stopped doing keep alive. In this
                        // case m_Error could be success, which would be misleading.
                        // So in that case we'll set it to connection closed.

                        if (m_Error == WebExceptionStatus.Success) {
                            // Only reason we could have gotten here is because
                            // we're not keeping the connection alive.
                            m_Error = WebExceptionStatus.KeepAliveFailure;
                        }

                        // PrepareCloseConnectionSocket is called with the critical section
                        // held. Note that we know since it's not a keep-alive
                        // connection the read half wouldn't have posted a receive
                        // for this connection, so it's OK to call PrepareCloseConnectionSocket now.
                        PrepareCloseConnectionSocket(ref returnResult);
                        calledCloseConnection = true;
                        Close();
                    }
                    else {
                        if (m_Error!=WebExceptionStatus.Success) {
                            GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::WriteStartNextRequest() a Failure, m_Error = " + m_Error.ToString());
                        }
                    }
                }
                else {
                    // If we're pipelining, we get get the next request going
                    // as soon as the write is done. Otherwise we have to wait
                    // until both read and write are done.


                    GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::WriteStartNextRequest() Non-Error m_WriteList.Count:" + m_WriteList.Count + " m_WaitList.Count:" + m_WaitList.Count);

                    if (m_Pipelining || m_ReadDone)
                    {
                        nextRequest = CheckNextRequest();
                    }
                    if (nextRequest != null)
                    {
                        // This codepath doesn't handle the case where the server has closed the Connection because we
                        // just finished using it and didn't get a Connection: close header.
                        startRequestResult = StartRequest(nextRequest, false);
                        GlobalLog.Assert(startRequestResult != TriState.Unspecified, "WriteStartNextRequest got TriState.Unspecified from StartRequest, things are about to hang!");
                    }
                }
            } // lock
        }
Example #34
0
        internal void ProcessWriteCallDone(ConnectionReturnResult returnResult)
        {
            GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::ProcessWriteCallDone()");

            try {
                if (returnResult == null) {
                    m_Connection.WriteStartNextRequest(m_Request, ref returnResult);

                    // If the request is Sync, then we do our Read here for data
                    if (!m_Request.Async)
                    {
                        object syncReaderResult = m_Request.ConnectionReaderAsyncResult.InternalWaitForCompletion();

                        //we should only do a syncread if we didn't already read the response
                        //via poll when we handed back the request stream
                        if (syncReaderResult == null && m_Request.NeedsToReadForResponse)
#if DEBUG
                            // Remove once mixed sync/async requests are supported.
                            using (GlobalLog.SetThreadKind(ThreadKinds.Sync))
#endif
                        {
                            m_Connection.SyncRead(m_Request, true, false);
                        }
                    }

                    m_Request.NeedsToReadForResponse = true;
                }

                ConnectionReturnResult.SetResponses(returnResult);
            }
            finally {
                // This will decrement the response window on the write side AND may
                // result in either immediate or delayed processing of a response for the m_Request instance
                if (IsPostStream || m_Request.Async)
                    m_Request.CheckWriteSideResponseProcessing();
            }
        }
 internal void HandleConnectStreamException(bool writeDone, bool readDone, WebExceptionStatus webExceptionStatus, ref ConnectionReturnResult returnResult, Exception e)
 {
     if (this.m_InnerException == null)
     {
         this.m_InnerException = e;
         if (!(e is WebException) && (base.NetworkStream is TlsStream))
         {
             webExceptionStatus = ((TlsStream) base.NetworkStream).ExceptionStatus;
         }
         else if (e is ObjectDisposedException)
         {
             webExceptionStatus = WebExceptionStatus.RequestCanceled;
         }
     }
     this.HandleError(writeDone, readDone, webExceptionStatus, ref returnResult);
 }