/// <summary> /// Performs the given WebRequestFunction, retrying if an error occurs, and handling /// proxy authentication. /// </summary> /// <param name="func">The WebRequestFunction to execute.</param> /// <param name="arg">The WebRequestFunction argument.</param> /// <returns>The WebRequestFunction return value.</returns> private object PerformWebRequest(WebRequestFunction func, Object arg) { int retries = 2; while (retries-- > 0) { try { Object ret; WebException proxyAuthException; return(ProxyAuthHandler(func, arg, out ret, out proxyAuthException)); } catch { if (retries == 0) { throw; // rethrow only if no more retries left } } } return(null); }
/// <summary> /// Performs the actual WebRequestFunction and returns whether or not we require proxy auth. /// </summary> /// <returns>True if we received HTTP 407: Proxy Authentication Required.</returns> private bool IsProxyAuthRequired(WebRequestFunction func, Object arg, out Object ret, out WebException proxyAuthException) { try { ret = func(arg); proxyAuthException = null; return(false); } catch (WebException ex) { if (ex.Status == WebExceptionStatus.ProtocolError && ((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.ProxyAuthenticationRequired) { // proxy auth required ret = null; proxyAuthException = ex; return(true); } else { // other error throw; } } }
/// <summary> /// If proxy auth is required then the proxy password is retrieved from saved credentials /// or requested from the user. This is repeated until the WebRequestFunction succeeds /// (upon which the credentials are saved), or the user cancels. /// </summary> private object ProxyAuthHandler(WebRequestFunction func, Object arg, out Object ret, out WebException proxyAuthException) { if (!IsProxyAuthRequired(func, arg, out ret, out proxyAuthException)) { return(ret); } // got HTTP 407 // extract realm string realm = proxyAuthException.Response.Headers[HttpResponseHeader.ProxyAuthenticate]; Match match = Regex.Match(realm, @"realm=\""(.+?)\""", RegexOptions.IgnoreCase); // eg, "Basic realm=\"The realm name\"" (inc quotes) if (match.Success) { realm = match.Groups[1].Value; } else if (WebRequest.DefaultWebProxy is WebProxy) // custom { realm = ((WebProxy)WebRequest.DefaultWebProxy).Address.Host; } else { realm = Language.NetManager_PleaseEnterCredentials; } // ask for credentials until succeeds or cancelled while (true) { // remove save check if auth failed if (WebRequest.DefaultWebProxy.Credentials != null) { proxyCredDialog.SaveChecked = false; } // get proxy credentials (prompt if not stored) NetworkCredential cred = GetProxyCredentials(realm); if (cred == null) { throw proxyAuthException; // user cancelled, return original 407 exception } WebRequest.DefaultWebProxy.Credentials = cred; // try again if (!IsProxyAuthRequired(func, arg, out ret, out proxyAuthException)) // success { proxyCredDialog.AlwaysDisplay = false; try { if (proxyCredDialog.SaveChecked) { proxyCredDialog.Confirm(true); // store } else { proxyCredDialog.Confirm(false); // unstore } } catch { } return(ret); } else // failed again { proxyCredDialog.AlwaysDisplay = true; proxyCredDialog.Password = ""; try // throws an exception if didn't actually show dialog (ie, stored password was wrong) { proxyCredDialog.Confirm(false); } catch { } } } // end while }