private void ConfigureRequest(HttpWebRequest request) { request.Proxy = _proxyCache.GetProxy(request.RequestUri); if (request.Proxy != null && request.Proxy.Credentials == null) { request.Proxy.Credentials = CredentialCache.DefaultCredentials; } if (_previousResponse == null || ShouldKeepAliveBeUsedInRequest(_previousRequest, _previousResponse)) { // Try to use the cached credentials (if any, for the first request) request.Credentials = _credentialCache.GetCredentials(request.RequestUri); // If there are no cached credentials, use the default ones if (request.Credentials == null) { request.UseDefaultCredentials = true; } } else if (_previousStatusCode == HttpStatusCode.ProxyAuthenticationRequired) { request.Proxy.Credentials = _credentialProvider.GetCredentials( request, CredentialType.ProxyCredentials, retrying: _proxyCredentialsRetryCount > 0); _continueIfFailed = request.Proxy.Credentials != null; _proxyCredentialsRetryCount++; } else if (_previousStatusCode == HttpStatusCode.Unauthorized) { SetCredentialsOnAuthorizationError(request); } SetKeepAliveHeaders(request, _previousResponse); if (_usingSTSAuth) { // Add request headers if the server requires STS based auth. STSAuthHelper.PrepareSTSRequest(request); } // Wrap the credentials in a CredentialCache in case there is a redirect // and credentials need to be kept around. request.Credentials = request.Credentials.AsCredentialCache(request.RequestUri); }
public HttpWebResponse GetResponse(CancellationToken token) { _previousRequest = null; _previousResponse = null; _previousStatusCode = null; _usingSTSAuth = false; _continueIfFailed = true; _proxyCredentialsRetryCount = 0; _credentialsRetryCount = 0; int failureCount = 0; const int MaxFailureCount = 10; while (true) { // Create the request var request = (HttpWebRequest)_createRequest(); MakeCancelable(request, token); ConfigureRequest(request); try { var auth = request.Headers["Authorization"]; _basicAuthIsUsedInPreviousRequest = (auth != null) && auth.StartsWith("Basic ", StringComparison.Ordinal); // Prepare the request, we do something like write to the request stream // which needs to happen last before the request goes out _prepareRequest(request); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // Cache the proxy and credentials _proxyCache.Add(request.Proxy); ICredentials credentials = request.Credentials; _credentialCache.Add(request.RequestUri, credentials); _credentialCache.Add(response.ResponseUri, credentials); return(response); } catch (WebException ex) { ++failureCount; if (failureCount >= MaxFailureCount) { throw; } using (IHttpWebResponse response = GetResponse(ex.Response)) { if (response == null && ex.Status != WebExceptionStatus.SecureChannelFailure) { // No response, something went wrong so just rethrow throw; } // Special case https connections that might require authentication if (ex.Status == WebExceptionStatus.SecureChannelFailure) { if (_continueIfFailed) { // Act like we got a 401 so that we prompt for credentials on the next request _previousStatusCode = HttpStatusCode.Unauthorized; continue; } throw; } // If we were trying to authenticate the proxy or the request and succeeded, cache the result. if (_previousStatusCode == HttpStatusCode.ProxyAuthenticationRequired && response.StatusCode != HttpStatusCode.ProxyAuthenticationRequired) { _proxyCache.Add(request.Proxy); } else if (_previousStatusCode == HttpStatusCode.Unauthorized && response.StatusCode != HttpStatusCode.Unauthorized) { _credentialCache.Add(request.RequestUri, request.Credentials); _credentialCache.Add(response.ResponseUri, request.Credentials); } _usingSTSAuth = STSAuthHelper.TryRetrieveSTSToken(request.RequestUri, response); if (!IsAuthenticationResponse(response) || !_continueIfFailed) { throw; } _previousRequest = request; _previousResponse = response; _previousStatusCode = _previousResponse.StatusCode; } } } }