internal HttpWebResponse( Uri responseUri, string verb, CoreResponseData coreData, string mediaType, bool usesProxySemantics) { m_Uri = responseUri; m_Verb = verb; m_MediaType = mediaType; m_UsesProxySemantics = usesProxySemantics; m_ConnectStream = coreData.m_ConnectStream; m_HttpResponseHeaders = coreData.m_ResponseHeaders; m_ContentLength = coreData.m_ContentLength; m_StatusCode = coreData.m_StatusCode; m_StatusDescription = coreData.m_StatusDescription; m_Version = coreData.m_Version; // handle Content-Location header, by combining it with the orginal request. string contentLocation = m_HttpResponseHeaders[HttpKnownHeaderNames.ContentLocation]; if (contentLocation != null) { try { m_Uri = new Uri(m_Uri, contentLocation); } catch (Exception e) { GlobalLog.Assert(false, "Exception on Uri parsing", e.ToString()); } } }
internal Connection(System.Net.ConnectionGroup connectionGroup) : base(null) { this.m_IISVersion = -1; this.m_Free = true; this.m_Idle = true; this.m_KeepAlive = true; this.m_MaximumUnauthorizedUploadLength = SettingsSectionInternal.Section.MaximumUnauthorizedUploadLength; if (this.m_MaximumUnauthorizedUploadLength > 0L) { this.m_MaximumUnauthorizedUploadLength *= 0x400L; } this.m_ResponseData = new CoreResponseData(); this.m_ConnectionGroup = connectionGroup; this.m_ReadBuffer = new byte[0x1000]; this.m_ReadState = ReadState.Start; this.m_WaitList = new List<WaitListItem>(); this.m_WriteList = new ArrayList(); this.m_AbortDelegate = new HttpAbortDelegate(this.AbortOrDisassociate); this.m_ConnectionUnlock = new UnlockConnectionDelegate(this.UnlockRequest); this.m_StatusLineValues = new StatusLineValues(); this.m_RecycleTimer = this.ConnectionGroup.ServicePoint.ConnectionLeaseTimerQueue.CreateTimer(); this.ConnectionGroup.Associate(this); this.m_ReadDone = true; this.m_WriteDone = true; this.m_Error = WebExceptionStatus.Success; }
internal HttpWebResponse(Uri responseUri, KnownHttpVerb verb, CoreResponseData coreData, string mediaType, bool usesProxySemantics, DecompressionMethods decompressionMethod) { m_Uri = responseUri; m_Verb = verb; m_MediaType = mediaType; m_UsesProxySemantics = usesProxySemantics; m_ConnectStream = coreData.m_ConnectStream; m_HttpResponseHeaders = coreData.m_ResponseHeaders; m_ContentLength = coreData.m_ContentLength; m_StatusCode = coreData.m_StatusCode; m_StatusDescription = coreData.m_StatusDescription; m_IsVersionHttp11 = coreData.m_IsVersionHttp11; //if the returned contentlength is zero, preemptively invoke calldone on the stream. //this will wake up any pending reads. if (m_ContentLength == 0 && m_ConnectStream is ConnectStream) { ((ConnectStream)m_ConnectStream).CallDone(); } // handle Content-Location header, by combining it with the orginal request. string contentLocation = m_HttpResponseHeaders[HttpKnownHeaderNames.ContentLocation]; if (contentLocation != null) { try { m_Uri = new Uri(m_Uri, contentLocation); } catch (UriFormatException e) { GlobalLog.Assert("Exception on response Uri parsing.", e.ToString()); } } // decompress responses by hooking up a final response Stream - only if user required it if(decompressionMethod != DecompressionMethods.None) { string contentEncoding = m_HttpResponseHeaders[HttpKnownHeaderNames.ContentEncoding]; if (contentEncoding != null){ if(((decompressionMethod & DecompressionMethods.GZip) != 0) && contentEncoding.IndexOf(HttpWebRequest.GZipHeader) != -1) { m_ConnectStream = new GZipWrapperStream(m_ConnectStream, CompressionMode.Decompress); m_ContentLength = -1; // unknown on compressed streams // Setting a response header after parsing will ruin the Common Header optimization. // This seems like a corner case. ContentEncoding could be added as a common header, with a special // property allowing it to be nulled. m_HttpResponseHeaders[HttpKnownHeaderNames.ContentEncoding] = null; } else if (((decompressionMethod & DecompressionMethods.Deflate) != 0) && contentEncoding.IndexOf(HttpWebRequest.DeflateHeader) != -1) { m_ConnectStream = new DeflateWrapperStream(m_ConnectStream, CompressionMode.Decompress); m_ContentLength = -1; // unknown on compressed streams // Setting a response header after parsing will ruin the Common Header optimization. // This seems like a corner case. ContentEncoding could be added as a common header, with a special // property allowing it to be nulled. m_HttpResponseHeaders[HttpKnownHeaderNames.ContentEncoding] = null; } } } }
internal CoreResponseData Clone() { CoreResponseData cloneResponseData = new CoreResponseData(); cloneResponseData.m_StatusCode = m_StatusCode; cloneResponseData.m_StatusDescription = m_StatusDescription; cloneResponseData.m_IsVersionHttp11 = m_IsVersionHttp11; cloneResponseData.m_ContentLength = m_ContentLength; cloneResponseData.m_ResponseHeaders = m_ResponseHeaders; cloneResponseData.m_ConnectStream = m_ConnectStream; return(cloneResponseData); }
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)); }
/// <summary> /// Creates WEB response based on information known just after parsing the status line. /// </summary> /// <param name="method">Http Verb</param> /// <param name="responseUrl">TBD</param> /// <param name="data">Response data</param> /// <param name="httpWebReq">TBD</param> internal HttpWebResponse(string method, Uri responseUrl, CoreResponseData data, HttpWebRequest httpWebReq) { m_httpWebRequest = httpWebReq; m_method = method; m_url = responseUrl; m_version = data.m_version; m_statusCode = data.m_statusCode; m_statusDescription = data.m_statusDescription; m_httpResponseHeaders = data.m_headers; m_contentLength = data.m_contentLength; }
internal HttpWebResponse(Uri responseUri, KnownHttpVerb verb, CoreResponseData coreData, string mediaType, bool usesProxySemantics, DecompressionMethods decompressionMethod) { this.m_Uri = responseUri; this.m_Verb = verb; this.m_MediaType = mediaType; this.m_UsesProxySemantics = usesProxySemantics; this.m_ConnectStream = coreData.m_ConnectStream; this.m_HttpResponseHeaders = coreData.m_ResponseHeaders; this.m_ContentLength = coreData.m_ContentLength; this.m_StatusCode = coreData.m_StatusCode; this.m_StatusDescription = coreData.m_StatusDescription; this.m_IsVersionHttp11 = coreData.m_IsVersionHttp11; if ((this.m_ContentLength == 0L) && (this.m_ConnectStream is ConnectStream)) { ((ConnectStream)this.m_ConnectStream).CallDone(); } string relativeUri = this.m_HttpResponseHeaders["Content-Location"]; if (relativeUri != null) { try { this.m_Uri = new Uri(this.m_Uri, relativeUri); } catch (UriFormatException) { } } if (decompressionMethod != DecompressionMethods.None) { string str2 = this.m_HttpResponseHeaders["Content-Encoding"]; if (str2 != null) { if (((decompressionMethod & DecompressionMethods.GZip) != DecompressionMethods.None) && (str2.IndexOf("gzip") != -1)) { this.m_ConnectStream = new GZipWrapperStream(this.m_ConnectStream, CompressionMode.Decompress); this.m_ContentLength = -1L; this.m_HttpResponseHeaders["Content-Encoding"] = null; } else if (((decompressionMethod & DecompressionMethods.Deflate) != DecompressionMethods.None) && (str2.IndexOf("deflate") != -1)) { this.m_ConnectStream = new DeflateWrapperStream(this.m_ConnectStream, CompressionMode.Decompress); this.m_ContentLength = -1L; this.m_HttpResponseHeaders["Content-Encoding"] = null; } } } }
internal HttpWebResponse(Uri responseUri, KnownHttpVerb verb, CoreResponseData coreData, string mediaType, bool usesProxySemantics, DecompressionMethods decompressionMethod) { this.m_Uri = responseUri; this.m_Verb = verb; this.m_MediaType = mediaType; this.m_UsesProxySemantics = usesProxySemantics; this.m_ConnectStream = coreData.m_ConnectStream; this.m_HttpResponseHeaders = coreData.m_ResponseHeaders; this.m_ContentLength = coreData.m_ContentLength; this.m_StatusCode = coreData.m_StatusCode; this.m_StatusDescription = coreData.m_StatusDescription; this.m_IsVersionHttp11 = coreData.m_IsVersionHttp11; if ((this.m_ContentLength == 0L) && (this.m_ConnectStream is ConnectStream)) { ((ConnectStream) this.m_ConnectStream).CallDone(); } string relativeUri = this.m_HttpResponseHeaders["Content-Location"]; if (relativeUri != null) { try { this.m_Uri = new Uri(this.m_Uri, relativeUri); } catch (UriFormatException) { } } if (decompressionMethod != DecompressionMethods.None) { string str2 = this.m_HttpResponseHeaders["Content-Encoding"]; if (str2 != null) { if (((decompressionMethod & DecompressionMethods.GZip) != DecompressionMethods.None) && (str2.IndexOf("gzip") != -1)) { this.m_ConnectStream = new GZipWrapperStream(this.m_ConnectStream, CompressionMode.Decompress); this.m_ContentLength = -1L; this.m_HttpResponseHeaders["Content-Encoding"] = null; } else if (((decompressionMethod & DecompressionMethods.Deflate) != DecompressionMethods.None) && (str2.IndexOf("deflate") != -1)) { this.m_ConnectStream = new DeflateWrapperStream(this.m_ConnectStream, CompressionMode.Decompress); this.m_ContentLength = -1L; this.m_HttpResponseHeaders["Content-Encoding"] = null; } } } }
/// <summary> /// Reads and parses HTTP response from server. /// After return of function HTTP response is read. /// </summary> /// <param name="inStream">Network stream connected to server.</param> /// <param name="defaultKeepAlive">TBD</param> /// <returns>CoreResponseData that describes server response.</returns> private CoreResponseData ParseHTTPResponse(InputNetworkStreamWrapper inStream, bool defaultKeepAlive) { // CoreResponseData keeps all the information of the response. CoreResponseData ret = new CoreResponseData(); // maximumHeadersLength is maximum total length of http header. Basically this is amount // of memory used for headers. int headersLength = m_maxResponseHeadersLen == -1 ? 0x7FFFFFFF : m_maxResponseHeadersLen * 1024; ret.m_shouldClose = !defaultKeepAlive; // Parse the request line. string line = inStream.Read_HTTP_Line(maxHTTPLineLength).Trim(); // Cutoff white spaces int currentOffset = 0; for (; currentOffset < line.Length && ' ' != line[currentOffset]; ++currentOffset) ; // find HTTP version, read http/1.x string httpVersionString = line.Substring(0, currentOffset).ToLower(); if (httpVersionString.Equals("http/1.1")) { ret.m_version = HttpVersion.Version11; } else if (httpVersionString.Equals("http/1.0")) { ret.m_version = HttpVersion.Version10; } else { ret.m_status = WebExceptionStatus.ServerProtocolViolation; ret.m_exceptionMessage = "Unknown http version: " + httpVersionString; return ret; } //advance to the status code for (; currentOffset < line.Length && ' ' == line[currentOffset]; ++currentOffset) ; // Read the status code int codeStart = currentOffset; for (; currentOffset < line.Length && ' ' != line[currentOffset]; ++currentOffset) ; int statusCode = -1; try { string statusCodeStr = line.Substring(codeStart, currentOffset - codeStart); statusCode = Convert.ToInt32(statusCodeStr); } catch (Exception e) { ret.m_status = WebExceptionStatus.ServerProtocolViolation; ret.m_exceptionMessage = "Missing status code in HTTP reply"; ret.m_innerException = e; return ret; } // If we get here - status code should be read. ret.m_statusCode = statusCode; // Advance to the status message. The message is optional for (; currentOffset < line.Length && ' ' != line[currentOffset]; ++currentOffset) ; ret.m_statusDescription = line.Substring(currentOffset); ret.m_headers = new WebHeaderCollection(true); ret.m_chunked = false; ret.m_contentLength = -1; while ((line = inStream.Read_HTTP_Header(maxHTTPLineLength)).Length > 0) { // line.Length is used for the header. Substruct it. headersLength -= line.Length; // If total length used for header is exceeded, we break if (headersLength < 0) { ret.m_status = WebExceptionStatus.ServerProtocolViolation; ret.m_exceptionMessage = "Headers size exceed limit"; return ret; } // Now parse the header. int sepIdx = line.IndexOf(':'); if (sepIdx == -1) { ret.m_status = WebExceptionStatus.ServerProtocolViolation; ret.m_exceptionMessage = "Illegal header format: " + line; return ret; } string headerName = line.Substring(0, sepIdx); string headerValue = line.Substring(sepIdx + 1).TrimStart(null); string matchableHeaderName = headerName.ToLower(); ret.m_headers.AddInternal(headerName, headerValue); if (matchableHeaderName.Equals("content-length")) { try { ret.m_contentLength = Convert.ToInt32(headerValue); // set the response stream length for the input stream, so that an EOF will be read // if the caller tries to read base the response content length inStream.m_BytesLeftInResponse = ret.m_contentLength; } catch (Exception e) { ret.m_status = WebExceptionStatus.ServerProtocolViolation; ret.m_exceptionMessage = "Content length NAN: " + headerValue; ret.m_innerException = e; return ret; } } else if (matchableHeaderName.Equals("transfer-encoding")) { if (headerValue.ToLower().IndexOf("chunked") != -1) { ret.m_chunked = true; } } else if (matchableHeaderName.Equals("connection")) { if (headerValue.ToLower().IndexOf(HttpKnownHeaderValues.close) != -1) { ret.m_shouldClose = true; } } } return ret; }
internal static void Add(ref ConnectionReturnResult returnResult, HttpWebRequest request, CoreResponseData coreResponseData) { if (returnResult == null) { returnResult = new ConnectionReturnResult(); } request.CoreResponse = coreResponseData; returnResult.m_RequestList.Add(request); }
// // This method has to be invoked as part of the wire response processing. // The wire response can be replaced on return // // ATTN: If the method returns false, the response is invalid and should be retried // private bool CheckCacheRetrieveOnResponse() { GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckCacheRetrieveOnResponse"); if (CacheProtocol == null) { return true; } if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail) { throw CacheProtocol.ProtocolException; } Stream oldResponseStream = _HttpResponse.ResponseStream; CacheProtocol.GetRevalidateStatus(_HttpResponse, _HttpResponse.ResponseStream); if (CacheProtocol.ProtocolStatus == CacheValidationStatus.RetryResponseFromServer) { // Try to resubmit or fail return false; } if (CacheProtocol.ProtocolStatus != CacheValidationStatus.ReturnCachedResponse && CacheProtocol.ProtocolStatus != CacheValidationStatus.CombineCachedAndServerResponse) { // Take current response return true; } if (HttpWriteMode!=HttpWriteMode.None) { // This should never happen in real life throw new NotSupportedException(SR.GetString(SR.net_cache_not_supported_body)); } CoreResponseData responseData = new CoreResponseData(); HttpRequestCacheValidator ctx = (HttpRequestCacheValidator) CacheProtocol.Validator; // If we take it from cache, we have to replace the live response if any responseData.m_IsVersionHttp11 = ctx.CacheHttpVersion.Equals(HttpVersion.Version11); responseData.m_StatusCode = ctx.CacheStatusCode; responseData.m_StatusDescription= ctx.CacheStatusDescription; responseData.m_ResponseHeaders = CacheProtocol.ProtocolStatus == CacheValidationStatus.CombineCachedAndServerResponse ? new WebHeaderCollection(ctx.CacheHeaders) : ctx.CacheHeaders; responseData.m_ContentLength = CacheProtocol.ResponseStreamLength; responseData.m_ConnectStream = CacheProtocol.ResponseStream; _HttpResponse = new HttpWebResponse(GetRemoteResourceUri(), CurrentMethod, responseData, _MediaType, UsesProxySemantics, AutomaticDecompression, IsWebSocketRequest, ConnectionGroupName); if (CacheProtocol.ProtocolStatus == CacheValidationStatus.ReturnCachedResponse) { _HttpResponse.InternalSetFromCache = true; _HttpResponse.InternalSetIsCacheFresh = CacheProtocol.IsCacheFresh; // can only dispose the response stream when not combining the streams // Note the response itself may still be needed for cache update call. if (oldResponseStream != null) { try { oldResponseStream.Close(); } catch { } } } return true; }
// // This method may be invoked as part of the request submission but // before the response is received // Return: // - True = response is ready // - False = Proceed with the request submission private bool CheckCacheRetrieveBeforeSubmit() { GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::CheckCacheRetrieveBeforeSubmit"); if (CacheProtocol == null) { return false; } try { Uri cacheUri = GetRemoteResourceUri(); if (cacheUri.Fragment.Length != 0) cacheUri = new Uri(cacheUri.GetParts(UriComponents.AbsoluteUri & ~UriComponents.Fragment, UriFormat.SafeUnescaped)); CacheProtocol.GetRetrieveStatus(cacheUri, this); if (CacheProtocol.ProtocolStatus == CacheValidationStatus.Fail) { throw CacheProtocol.ProtocolException; } if (CacheProtocol.ProtocolStatus != CacheValidationStatus.ReturnCachedResponse) { return false; } if (HttpWriteMode!=HttpWriteMode.None) { throw new NotSupportedException(SR.GetString(SR.net_cache_not_supported_body)); } // If we take it from cache, we have to kick in response processing // The _CacheStream is good to return as the response stream. HttpRequestCacheValidator ctx = (HttpRequestCacheValidator) CacheProtocol.Validator; CoreResponseData responseData = new CoreResponseData(); responseData.m_IsVersionHttp11 = ctx.CacheHttpVersion.Equals(HttpVersion.Version11); responseData.m_StatusCode = ctx.CacheStatusCode; responseData.m_StatusDescription= ctx.CacheStatusDescription; responseData.m_ResponseHeaders = ctx.CacheHeaders; responseData.m_ContentLength = CacheProtocol.ResponseStreamLength; responseData.m_ConnectStream = CacheProtocol.ResponseStream; _HttpResponse = new HttpWebResponse(GetRemoteResourceUri(), CurrentMethod, responseData, _MediaType, UsesProxySemantics, AutomaticDecompression, IsWebSocketRequest, ConnectionGroupName); _HttpResponse.InternalSetFromCache = true; _HttpResponse.InternalSetIsCacheFresh = (ctx.CacheFreshnessStatus != CacheFreshnessStatus.Stale); ProcessResponse(); return true; } catch (Exception exception) { Abort(exception, AbortState.Public); throw; } }
internal static void SetResponse(ConnectionReturnResult returnResult, HttpWebRequest request, CoreResponseData coreResponseData) { try { request.SetResponse(coreResponseData); } catch { if (returnResult != null && returnResult.m_RequestList.Count>0) { ThreadPool.QueueUserWorkItem(s_InvokeConnectionCallback, returnResult); } throw; } if (returnResult!= null) { ConnectionReturnResult.SetResponses(returnResult); } }
internal Connection(ConnectionGroup connectionGroup) : base(null) { // // add this Connection to the pool in the connection group, // keep a weak reference to it // m_MaximumUnauthorizedUploadLength = SettingsSectionInternal.Section.MaximumUnauthorizedUploadLength; if(m_MaximumUnauthorizedUploadLength > 0){ m_MaximumUnauthorizedUploadLength*=1024; } m_ResponseData = new CoreResponseData(); m_ConnectionGroup = connectionGroup; m_ReadBuffer = new byte[4096]; // Using a fixed 4k read buffer. m_ReadState = ReadState.Start; m_WaitList = new List<WaitListItem>(); m_WriteList = new ArrayList(); m_AbortDelegate = new HttpAbortDelegate(AbortOrDisassociate); m_ConnectionUnlock = new UnlockConnectionDelegate(UnlockRequest); // for status line parsing m_StatusLineValues = new StatusLineValues(); m_RecycleTimer = ConnectionGroup.ServicePoint.ConnectionLeaseTimerQueue.CreateTimer(); // the following line must be the last line of the constructor ConnectionGroup.Associate(this); m_ReadDone = true; m_WriteDone = true; m_Error = WebExceptionStatus.Success; }
/*++ 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) { DataParseStatus parseStatus = DataParseStatus.NeedMoreData; DataParseStatus parseSubStatus; GlobalLog.Enter("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData()"); // loop in case of multiple sets of headers or streams, // that may be generated due to a pipelined response do { // 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_CurrentRequestIndex - index into the window of a buffer where // we are currently parsing. Since there can be multiple requests // this index is used to the track the offset, based off of 0 // // 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. // // m_HeadersBytesUnparsed - The bytes scanned in the headers, // needs to be seperate because headers are not always completely // parsed to completion on each interation // // // 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: m_ResponseData = new CoreResponseData(); m_ReadState = ReadState.StatusLine; m_CurrentRequestIndex = m_BytesScanned; InitializeParseStatueLine(); goto case ReadState.StatusLine; case ReadState.StatusLine: // // Reads HTTP status response line // 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 m_StatusLineInts, ref m_StatusDescription, ref m_StatusState ); if (parseSubStatus == DataParseStatus.Invalid) { // // report error // GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseStatusLine() ParseHeaders() returned Invalid protocol usage"); parseStatus = DataParseStatus.Invalid; // advance back to state 0, in failure m_ReadState = ReadState.Start; break; } else if (parseSubStatus == DataParseStatus.Done) { SetStatusLineParsed(); m_ReadState = ReadState.Headers; m_HeadersBytesUnparsed = m_BytesScanned; m_ResponseData.m_ResponseHeaders = new WebHeaderCollection(true); goto case ReadState.Headers; } break; // read more data case ReadState.Headers: // // Parse additional lines of header-name: value pairs // if (m_HeadersBytesUnparsed>=m_BytesRead) { // // we already can tell we need more data // break; } parseSubStatus = m_ResponseData.m_ResponseHeaders.ParseHeaders( m_ReadBuffer, m_BytesRead, ref m_HeadersBytesUnparsed ); if (parseSubStatus == DataParseStatus.Invalid) { // // report error // GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() ParseHeaders() returned Invalid protocol usage"); parseStatus = DataParseStatus.Invalid; // advance back to state 0, in failure m_ReadState = ReadState.Start; break; } else if (parseSubStatus == DataParseStatus.Done) { m_BytesScanned = m_HeadersBytesUnparsed; // update actual size of scanned headers GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() got (" + ((int)m_ResponseData.m_StatusCode).ToString() + ") from the server"); // If we have an HTTP continue, eat these headers and look // for the 200 OK if (m_ResponseData.m_StatusCode == HttpStatusCode.Continue) { HttpWebRequest Request; // wakeup post code if needed lock(this) { GlobalLog.Assert( m_WriteList.Count > 0, "Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData(): m_WriteList.Count <= 0", ""); if ( m_WriteList.Count == 0 ) { parseStatus = DataParseStatus.Invalid; // advance back to state 0, in failure m_ReadState = ReadState.Start; break; } Request = (HttpWebRequest)m_WriteList[0]; } GlobalLog.Assert( Request != null, "Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData(): Request == null", ""); GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() HttpWebRequest#" + ValidationHelper.HashString(Request)); // // we got a 100 Continue. set this on the HttpWebRequest // Request.Saw100Continue = true; if (!m_Server.Understands100Continue) { // // and start expecting it again if this behaviour was turned off // GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(Request) + " ServicePoint#" + ValidationHelper.HashString(m_Server) + " sent UNexpected 100 Continue"); m_Server.Understands100Continue = true; } // // set Continue Ack on Request. // if (Request.ContinueDelegate != null) { // // invoke the 100 continue delegate if the user supplied one // GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() calling ContinueDelegate()"); Request.ContinueDelegate((int)m_ResponseData.m_StatusCode, m_ResponseData.m_ResponseHeaders); } GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() calling SetRequestContinue()"); Request.SetRequestContinue(); m_ReadState = ReadState.Start; goto case ReadState.Start; } m_ReadState = ReadState.Data; goto case ReadState.Data; } // need more data, // // But unfornately ParseHeaders does not work, // the same way as all other code in this function, // since its old code, it assumes BytesScanned bytes will be always // around between calls until it has all the data, but that is NOT // true, since we can do block copy between calls. // // To handle this we fix up the offsets. // We assume we scanned all the way to the end of valid buffer data m_BytesScanned = m_BytesRead; 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 // // advance back to state 0 m_ReadState = ReadState.Start; // parse and create a stream if needed DataParseStatus result = ParseStreamData(ref returnResult); GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData() result - " + result.ToString()); switch (result) { case DataParseStatus.NeedMoreData: // // cont reading. Only way we can get here is if the request consumed // all the bytes in the buffer. So reset everything. // m_BytesRead = 0; m_BytesScanned = 0; m_CurrentRequestIndex = 0; parseStatus = DataParseStatus.NeedMoreData; break; case DataParseStatus.ContinueParsing: continue; case DataParseStatus.Invalid: case DataParseStatus.Done: // // NOTE: WARNING: READ THIS: // Upon update of this code, keep in mind, // that when DataParseStatus.Done is returned // from ParseStreamData, it can mean that ReadStartNextRequest() // has been called. That means that we should no longer // change ALL this.m_* vars, since those variables, can now // be used on other threads. // // DataParseStatus.Done will cause an error below parseStatus = result; break; } break; } break; } while (true); GlobalLog.Print("m_ReadState - " + m_ReadState.ToString()); GlobalLog.Leave("Connection#" + ValidationHelper.HashString(this) + "::ParseResponseData()", parseStatus.ToString()); return parseStatus; }
internal CoreResponseData Clone() { CoreResponseData cloneResponseData = new CoreResponseData(); cloneResponseData.m_StatusCode = m_StatusCode; cloneResponseData.m_StatusDescription = m_StatusDescription; cloneResponseData.m_IsVersionHttp11 = m_IsVersionHttp11; cloneResponseData.m_ContentLength = m_ContentLength; cloneResponseData.m_ResponseHeaders = m_ResponseHeaders; cloneResponseData.m_ConnectStream = m_ConnectStream; return cloneResponseData; }
/*++ 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 --*/ private void HandleError(WebExceptionStatus webExceptionStatus, ConnectionFailureGroup failureGroup, ref ConnectionReturnResult returnResult) { Monitor.Enter(this); GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::HandleError() writeListcount: " + m_WriteList.Count.ToString() + " m_WriteDone:" + m_WriteDone.ToString() + " failureGroup:" + failureGroup.ToString()); if (failureGroup != ConnectionFailureGroup.Receive) { if ((m_WriteList.Count!=0) && (failureGroup != ConnectionFailureGroup.Connect)) { HttpWebRequest Request = (HttpWebRequest)m_WriteList[0]; Request.OnceFailed = true; GlobalLog.Print("Request = " + ValidationHelper.HashString(Request)); } else { // if there are no WriteList requests, then we can // assume that WriteDone is true, this is usually // caused by servers send illegal data (e.g. bad contentlengths), GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::HandleError() setting m_WriteDone:" + m_WriteDone.ToString() + " to true"); m_WriteDone = true; } } GlobalLog.Print("Connection#" + ValidationHelper.HashString(this) + "::HandleError() m_WriteDone:" + m_WriteDone.ToString()); m_ResponseData = null; //m_ReadState = ReadState.Start; m_ReadDone = true; //Tunnelling = false; m_Error = webExceptionStatus; // It's possible that we could have a write in progress, and we // don't want to close the connection underneath him. Since thisConnection // is a completion of our read buffer, it's safe for us to // set thisConnection.m_ReadDone to true. So if there's not a write in // progress, close the connection. If there a write in progress, // wait for the write to complete before closing the socket. if (m_WriteDone) { CloseConnectionSocket(m_Error, ref returnResult); } else { Monitor.Exit(this); } }
/*++ Routine Description: Wakes up blocked threads, so they can read response object, from the result We also handle the continuation/termination of a BeginGetResponse, by saving out the result and calling its callback if needed. Arguments: coreData - Contains the data used to create the Response object exception - true if we're allowed to throw an exception on error Return Value: none --*/ internal void SetResponse(CoreResponseData coreResponseData) { GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", "*** SETRESP ***"); // // Since we are no longer attached to this Connection, // we null out our abort delegate. // _AbortDelegate = null; try { if (coreResponseData != null) { _HttpResponse = new HttpWebResponse(_Uri, _Verb, coreResponseData, _MediaType, UsesProxySemantics); coreResponseData = null; } else { // // not sure how this would happen, but we should not throw an exception, // which we were earlier doing. // GlobalLog.Assert(false, "coreResponseData == null", ""); GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", "ASSERT"); return; } // // give apps the chance to examine the headers of the new response // if (_CookieContainer != null) { CookieModule.OnReceivedHeaders(this); } // New Response HttpProcessingResult httpResult = HttpProcessingResult.Continue; // handle redirects, authentication, and such httpResult = DoSubmitRequestProcessing(); if (httpResult == HttpProcessingResult.Continue) { // // Now grab crit sec here, before returning, // this is to prevent some one from reading // ReadAResult it as null before we finish // processing our response // LazyAsyncResult asyncResult = null; lock(this) { asyncResult = _ReadAResult; GlobalLog.Assert(asyncResult == null || this == (HttpWebRequest)asyncResult.AsyncObject, "SetResponse: this != asyncResult.AsyncObject", ""); GlobalLog.Assert(asyncResult == null || !asyncResult.IsCompleted, "SetResponse: asyncResult already completed!", ""); _HaveResponse = true; if (asyncResult != null) { _ReadAResult = null; } } if (asyncResult != null) { asyncResult.InvokeCallback(false, _HttpResponse); } if ( _WriteEvent != null ) { GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse(CoreResponseData) calling _WriteEvent.Set()"); _WriteEvent.Set(); } } } catch (Exception exception) { Abort(); GlobalLog.LeaveException("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", exception); throw; } if (_Abort) { try { if ( _HttpResponse != null ) { _HttpResponse.Close(); } } catch { } GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", "ABORT"); return; } GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse"); }
internal Connection(ConnectionGroup connectionGroup) : base(null) { // // add this Connection to the pool in the connection group, // keep a weak reference to it // m_MaximumUnauthorizedUploadLength = SettingsSectionInternal.Section.MaximumUnauthorizedUploadLength; if(m_MaximumUnauthorizedUploadLength > 0){ m_MaximumUnauthorizedUploadLength*=1024; } m_ResponseData = new CoreResponseData(); m_ConnectionGroup = connectionGroup; m_ReadBuffer = s_PinnableBufferCache.AllocateBuffer(); m_ReadBufferFromPinnableCache = true; m_ReadState = ReadState.Start; m_WaitList = new List<WaitListItem>(); m_WriteList = new ArrayList(); m_AbortDelegate = new HttpAbortDelegate(AbortOrDisassociate); m_ConnectionUnlock = new UnlockConnectionDelegate(UnlockRequest); // for status line parsing m_StatusLineValues = new StatusLineValues(); m_RecycleTimer = ConnectionGroup.ServicePoint.ConnectionLeaseTimerQueue.CreateTimer(); // the following line must be the last line of the constructor ConnectionGroup.Associate(this); m_ReadDone = true; m_WriteDone = true; m_Error = WebExceptionStatus.Success; if (PinnableBufferCacheEventSource.Log.IsEnabled()) { PinnableBufferCacheEventSource.Log.DebugMessage1("CTOR: In System.Net.Connection.Connnection", this.GetHashCode()); } }
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)); }
/*++ 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; }
internal void SetRequestContinue(CoreResponseData continueResponse) { GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue"); GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue"); _RequestContinueCount++; if (HttpWriteMode == HttpWriteMode.None) { GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue - not a POST type request, return"); return; } GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue() _RequestContinueCount:" + _RequestContinueCount); if (m_ContinueGate.Complete()) { // Invoke the 100 continue delegate if the user supplied one and we received a 100 Continue. if (continueResponse != null && ContinueDelegate != null) { GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue() calling ContinueDelegate()"); ExecutionContext x = Async ? GetWritingContext().ContextCopy : null; if (x == null) { ContinueDelegate((int)continueResponse.m_StatusCode, continueResponse.m_ResponseHeaders); } else { ExecutionContext.Run(x, new ContextCallback(CallContinueDelegateCallback), continueResponse); } } EndWriteHeaders_Part2(); } GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue"); }
// // When we got a live response, this method will construct the response object // and then consult with caching protocol on the appropriate action. // On return the response can be re-created. // Under some cases this method may initate retrying of the current request. // private void SetResponse(CoreResponseData coreResponseData) { GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse"); GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse - coreResponseData=" + ValidationHelper.HashString(coreResponseData)); try { // Consider removing this block as all these should be already signalled if (!Async) { LazyAsyncResult chkConnectionAsyncResult = ConnectionAsyncResult; LazyAsyncResult chkReaderAsyncResult = ConnectionReaderAsyncResult; chkConnectionAsyncResult.InvokeCallback(coreResponseData); // ref "coreResponseData": could be anything except for AsyncTriState or stream chkReaderAsyncResult.InvokeCallback(coreResponseData); // ref "coreResponseData": could be anything except for null } if (coreResponseData != null) { if (coreResponseData.m_ConnectStream.CanTimeout) { coreResponseData.m_ConnectStream.WriteTimeout = ReadWriteTimeout; coreResponseData.m_ConnectStream.ReadTimeout = ReadWriteTimeout; } _HttpResponse = new HttpWebResponse(GetRemoteResourceUri(), CurrentMethod, coreResponseData, _MediaType, UsesProxySemantics, AutomaticDecompression, IsWebSocketRequest, ConnectionGroupName); if(Logging.On)Logging.Associate(Logging.Web, this, coreResponseData.m_ConnectStream); if(Logging.On)Logging.Associate(Logging.Web, this, _HttpResponse); ProcessResponse(); } else { GlobalLog.Assert("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse()", "coreResponseData == null"); Abort(null, AbortState.Public); GlobalLog.LeaveException("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", new InternalException()); } } catch (Exception exception) { Abort(exception, AbortState.Internal); GlobalLog.LeaveException("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetResponse", exception); } return; }
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; }
internal void SetRequestContinue(CoreResponseData continueResponse) { GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue"); GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue"); _RequestContinueCount++; if (HttpWriteMode == HttpWriteMode.None) { GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue - not a POST type request, return"); return; } GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue() _RequestContinueCount:" + _RequestContinueCount); if (m_ContinueGate.Complete()) { // Generally, in Sync mode there will not be a timer (instead PollAndRead times out). However, in mixed mode // there can be. If there is a timer, whether or not to call EndWriteHeaders_Part2 depends on whether // we can successfully cancel it here. Otherwise, the timeout callback should call it. // // m_ContinueGate guards the synchronization of m_ContinueTimer. TimerThread.Timer timer = m_ContinueTimer; m_ContinueTimer = null; // In the case there was no timer, just call EndWriteHeaders_Part2. if (timer == null || timer.Cancel()) { // Invoke the 100 continue delegate if the user supplied one and we received a 100 Continue. if (continueResponse != null && ContinueDelegate != null) { GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue() calling ContinueDelegate()"); ExecutionContext x = null; if (x == null) { ContinueDelegate((int) continueResponse.m_StatusCode, continueResponse.m_ResponseHeaders); } else { ExecutionContext.Run(x, new ContextCallback(CallContinueDelegateCallback), continueResponse); } } EndWriteHeaders_Part2(); } } GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestContinue"); }