// // 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()"); }