示例#1
0
 /// <summary>
 /// Create an instance of <see cref="LocalServerCodeReceiver"/>.
 /// </summary>
 /// <param name="closePageResponse">Custom close page response for this instance</param>
 /// <param name="strategy">The strategy to use to determine the callback URI</param>
 public LocalServerCodeReceiver(string closePageResponse, CallbackUriChooserStrategy strategy)
 {
     _closePageResponse = closePageResponse;
     // Set the instance field of which callback URI to use.
     // An instance field is used to ensure any one instance of this class
     // uses a consistent callback URI.
     _callbackUriTemplate = CallbackUriChooser.Default.GetUriTemplate(strategy);
 }
示例#2
0
            internal string GetUriTemplate(CallbackUriChooserStrategy strategy)
            {
                lock (_lock)
                {
                    if (strategy == CallbackUriChooserStrategy.ForceLoopbackIp)
                    {
                        // We still want to know what happens, we just won't do the initial check.
                        InitUriStatisticsIfNeeded(ref _loopbackIp, CallbackUriTemplate127001, false);
                        return(_loopbackIp.Uri);
                    }

                    if (strategy == CallbackUriChooserStrategy.ForceLocalhost)
                    {
                        // We still want to know what happens, we just won't do the initial check.
                        InitUriStatisticsIfNeeded(ref _localhost, CallbackUriTemplateLocalhost, false);
                        return(_localhost.Uri);
                    }

                    // Listening on 127.0.0.1 is recommended, but can't be done in non-admin Windows 7 & 8 at least.
                    // So use some tests/heuristics to maybe listen on localhost instead.

                    // If this is the first time that we are called, try with the recommended IP.
                    InitUriStatisticsIfNeeded(ref _loopbackIp, CallbackUriTemplate127001, true);
                    // We now know something about the loopback IP for sure. Let's see if we can use it. If so,
                    // let's return it.
                    if (_loopbackIp.CanBeUsed)
                    {
                        return(_loopbackIp.Uri);
                    }

                    // If we are here, we know we can't use the loopback IP, either because it failed or because it
                    // timed out.

                    // Let's try with localhost.
                    InitUriStatisticsIfNeeded(ref _localhost, CallbackUriTemplateLocalhost, true);
                    // We now know something about localhost for sure. Let's see if we can use it. If so,
                    // let's return it.
                    if (_localhost.CanBeUsed)
                    {
                        return(_localhost.Uri);
                    }

                    // If we are here then we haven't been able to use loopback IP or localhost, either
                    // because of failure, or timeout.
                    // This is probably bad, but we can still recover if
                    // a) Timeouts were because of user inaction.
                    // b) Failures were transient.
                    // Let's try our best.

                    UriStatistics retriable = _loopbackIp.TotalResets switch
                    {
                        // We always prefer the one with less resets.
                        var loopbackResets when loopbackResets <_localhost.TotalResets => _loopbackIp,
                                                                var loopbackResets when loopbackResets> _localhost.TotalResets => _localhost,
                        // If they have the same amount of resets, then we prefer the one that has timed out
                        // and we prefer loopback if both have timed out.
                                  _ when _loopbackIp.IsTimedOut => _loopbackIp,
                                  _ when _localhost.IsTimedOut => _localhost,
                        // If they have the same amount of resets and none has timed out (they have failed), then we prefer loopback.
                                  _ => _loopbackIp
                    };

                    retriable.Reset();
                    return(retriable.Uri);
                }

                void InitUriStatisticsIfNeeded(ref UriStatistics statistics, string uri, bool checkListener)
                {
                    if (statistics == null)
                    {
                        statistics = new UriStatistics(uri, _timeout, _clock);

                        // If possible, preemptively check that the uri works on this environment.
                        // For instance, the loopback IP fails at least on Windows 7 and 8, for non-admin users.
                        if (checkListener && _listenerFailsFor(statistics.Uri))
                        {
                            statistics.Failed();
                        }
                    }
                }
            }