internal void SyncRead(HttpWebRequest request, bool userRetrievedStream, bool probeRead) { if (t_SyncReadNesting <= 0) { bool flag = !probeRead; try { bool flag2; t_SyncReadNesting++; int num = probeRead ? request.RequestContinueCount : 0; int bytesRead = -1; WebExceptionStatus receiveFailure = WebExceptionStatus.ReceiveFailure; if (this.m_BytesScanned < this.m_BytesRead) { flag = true; bytesRead = 0; receiveFailure = WebExceptionStatus.Success; } do { flag2 = true; try { if (bytesRead != 0) { receiveFailure = WebExceptionStatus.ReceiveFailure; if (!flag) { flag = base.Poll(0x55730, SelectMode.SelectRead); } if (flag) { this.ReadTimeout = request.Timeout; bytesRead = this.Read(this.m_ReadBuffer, this.m_BytesRead, this.m_ReadBuffer.Length - this.m_BytesRead); receiveFailure = WebExceptionStatus.Success; if (bytesRead == 0) { bytesRead = -1; } } } } catch (Exception exception) { if (NclUtilities.IsFatal(exception)) { throw; } if (this.m_InnerException == null) { this.m_InnerException = exception; } if (exception.GetType() == typeof(ObjectDisposedException)) { receiveFailure = WebExceptionStatus.RequestCanceled; } else if (base.NetworkStream is TlsStream) { receiveFailure = ((TlsStream) base.NetworkStream).ExceptionStatus; } else { SocketException innerException = exception.InnerException as SocketException; if (innerException != null) { if (innerException.ErrorCode == 0x274c) { receiveFailure = WebExceptionStatus.Timeout; } else { receiveFailure = WebExceptionStatus.ReceiveFailure; } } } } if (flag) { flag2 = this.ReadComplete(bytesRead, receiveFailure); } bytesRead = -1; } while (!flag2 && (userRetrievedStream || (num == request.RequestContinueCount))); } finally { t_SyncReadNesting--; } if (probeRead) { if (flag) { if (!request.Saw100Continue && !userRetrievedStream) { request.SawInitialResponse = true; } } else { request.SetRequestContinue(); } } } }
// // Peforms a [....] Read and calls the ReadComplete to process the result // The reads are done iteratively, until the Request has received enough // data to contruct a response, or a 100-Continue is read, allowing the HttpWebRequest // to return a write stream // // probeRead = true only for POST request and when the caller needs to wait for 100-continue // internal void SyncRead(HttpWebRequest request, bool userRetrievedStream, bool probeRead) { GlobalLog.Enter("Connection#" + ValidationHelper.HashString(this) + "::SyncRead(byte[]) request#" + ValidationHelper.HashString(request) + (probeRead? ", Probe read = TRUE":string.Empty)); GlobalLog.ThreadContract(ThreadKinds.Sync, "Connection#" + ValidationHelper.HashString(this) + "::SyncRead"); // prevent recursive calls to this function if (t_SyncReadNesting > 0) { GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::SyncRead() - nesting"); return; } bool pollSuccess = probeRead? false: true; try { t_SyncReadNesting++; // grab a counter to tell us whenever the SetRequestContinue is called int requestContinueCount = probeRead ? request.RequestContinueCount : 0; bool requestDone; int bytesRead = -1; WebExceptionStatus errorStatus = WebExceptionStatus.ReceiveFailure; if (m_BytesScanned < m_BytesRead) { // left over from previous read pollSuccess = true; bytesRead = 0; //tell it we want to use buffered data on the first iteration errorStatus = WebExceptionStatus.Success; } do { requestDone = true; try { if (bytesRead != 0) { errorStatus = WebExceptionStatus.ReceiveFailure; if (!pollSuccess) { pollSuccess = Poll(request.ContinueTimeout * 1000, SelectMode.SelectRead); // Timeout is in microseconds GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::SyncRead() PollSuccess : " + pollSuccess); } if (pollSuccess) { //Ensures that we'll timeout eventually on an appdomain unload. //Will be a no-op if the timeout doesn't change from request to request. ReadTimeout = request.Timeout; bytesRead = Read(m_ReadBuffer, m_BytesRead, m_ReadBuffer.Length - m_BytesRead); errorStatus = WebExceptionStatus.Success; if (bytesRead == 0) bytesRead = -1; // 0 is reserved for re-entry on already buffered data } } } catch (Exception exception) { if (NclUtilities.IsFatal(exception)) throw; if (m_InnerException == null) m_InnerException = exception; if (exception.GetType() == typeof(ObjectDisposedException)) errorStatus = WebExceptionStatus.RequestCanceled; // need to handle SSL errors too #if !FEATURE_PAL else if (NetworkStream is TlsStream) { errorStatus = ((TlsStream)NetworkStream).ExceptionStatus; } #endif // !FEATURE_PAL else { SocketException socketException = exception.InnerException as SocketException; if (socketException != null) { if (socketException.ErrorCode == (int) SocketError.TimedOut) errorStatus = WebExceptionStatus.Timeout; else errorStatus = WebExceptionStatus.ReceiveFailure; } } GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::SyncRead() Read() threw errorStatus:" + errorStatus.ToString() + " bytesRead:" + bytesRead.ToString()); } if (pollSuccess) requestDone = ReadComplete(bytesRead, errorStatus); bytesRead = -1; } while (!requestDone && (userRetrievedStream || requestContinueCount == request.RequestContinueCount)); } finally { t_SyncReadNesting--; } if (probeRead) { // [....] 100-Continue wait only request.FinishContinueWait(); if (pollSuccess) { if (!request.Saw100Continue && !userRetrievedStream) { //During polling, we got a response that wasn't a 100 continue. request.NeedsToReadForResponse = false; } } else { GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::SyncRead() Poll has timed out, calling SetRequestContinue()."); request.SetRequestContinue(); } } GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::SyncRead()"); }
private void StartRequest(HttpWebRequest Request, bool PostReceive) { GlobalLog.Enter("StartRequest", "Request=#"+ValidationHelper.HashString(Request) + ", PostReceive=" + PostReceive); GlobalLog.Enter("Connection#" + ValidationHelper.HashString(this) + "::StartRequest", ValidationHelper.HashString(Request) + ", " + PostReceive); bool needReConnect = false; // Initialze state, and add the request to the write queue. // disable pipeling in certain cases such as when the Request disables it, // OR if the request is made using a Verb that cannot be pipelined, // BUT!! What about special verbs with data?? Should we not disable then too? m_Pipelining = m_CanPipeline && Request.InternalPipelined && (!Request.RequireBody); m_KeepAlive = Request.KeepAlive; // start of write process, disable done-ness flag GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::StartRequest() setting m_WriteDone:" + m_WriteDone.ToString() + " to false"); m_WriteDone = false; GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::StartRequest() _WriteList Add " + ValidationHelper.HashString(Request) + " - cnt#" + ValidationHelper.HashString(this) ); m_WriteList.Add(Request); GlobalLog.Print(m_WriteList.Count+" requests queued"); CheckNonIdle(); // with no transport around, we will have to create one, therefore, we can't have // the possiblity to even have a DoneReading(). if (Transport == null) { m_ReadDone = false; needReConnect = true; } if (Request is HttpProxyTunnelRequest) { Tunnelling = true; } Monitor.Exit(this); // // When we're uploading data, to a 1.0 server, we need to buffer // in order to determine content length // if (Request.CheckBuffering) { Request.SetRequestContinue(); } // If we need to post a receive, do so now. if (PostReceive) { GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::StartRequest() ThreadPool.QueueUserWorkItem(m_PostReceiveDelegate, this)"); ThreadPool.QueueUserWorkItem(m_PostReceiveDelegate, this); } if (needReConnect) { // Socket is not alive. Queue a request to the thread pool // to get it going. GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::StartRequest() Queue StartConnection Delegate "); #if DEBUG m_StartDelegateQueued = true; try { #endif ThreadPool.RegisterWaitForSingleObject( m_ReadCallbackEvent, m_StartConnectionDelegate, Request, -1, true); #if DEBUG } catch (Exception exception) { GlobalLog.Assert(false, exception.ToString(), ""); } #endif GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::StartRequest", "needReConnect"); return; } // Call the Request to let them know that we have a write-stream Request.SetRequestSubmitDone( new ConnectStream( this, Request.SendChunked ? -1 : (Request.ContentLength>0 ? Request.ContentLength : 0), Request ) ); GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::StartRequest"); }