private void SetupListener(bool secure)
        {
            var opts = CouchbaseLiteTcpOptions.Default;

            if (_authScheme == AuthenticationSchemes.Basic)
            {
                opts |= CouchbaseLiteTcpOptions.AllowBasicAuth;
            }

            if (secure)
            {
                var cert = X509Manager.GetPersistentCertificate("127.0.0.1", "123abc", System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "unit_test.pfx"));
                _listenerDBUri = new Uri(String.Format("https://localhost:{0}/{1}/", _port, LISTENER_DB_NAME));
                _listener      = new CouchbaseLiteTcpListener(manager, _port, opts | CouchbaseLiteTcpOptions.UseTLS, cert);
            }
            else
            {
                _listenerDBUri = new Uri(String.Format("http://localhost:{0}/{1}/", _port, LISTENER_DB_NAME));
                _listener      = new CouchbaseLiteTcpListener(manager, _port, opts);
            }

            if (_authScheme != AuthenticationSchemes.None)
            {
                _listener.SetPasswords(new Dictionary <string, string> {
                    { "bob", "slack" }
                });
            }

            _listener.Start();
        }
        public CouchbaseLiteTcpListener(Manager manager, ushort port, CouchbaseLiteTcpOptions options, string realm, X509Certificate2 sslCert)
        {
            _manager  = manager;
            _listener = new HttpListener();
            _usesTLS  = options.HasFlag(CouchbaseLiteTcpOptions.UseTLS);
            string prefix = _usesTLS ? String.Format("https://*:{0}/", port) :
                            String.Format("http://*:{0}/", port);

            _listener.Prefixes.Add(prefix);
            _listener.AuthenticationSchemeSelector = SelectAuthScheme;
            HttpListener.DefaultServerString       = "Couchbase Lite " + Manager.VersionString;
            _listener.Realm  = realm;
            _allowsBasicAuth = options.HasFlag(CouchbaseLiteTcpOptions.AllowBasicAuth);

            _listener.UserCredentialsFinder = GetCredential;
            if (options.HasFlag(CouchbaseLiteTcpOptions.UseTLS))
            {
                _listener.SslConfiguration.EnabledSslProtocols       = SslProtocols.Tls12;
                _listener.SslConfiguration.ClientCertificateRequired = false;
                if (sslCert == null)
                {
                    Log.To.Listener.I(TAG, "Generating X509 certificate for listener...");
                    sslCert = X509Manager.GenerateTransientCertificate("Couchbase-P2P");
                }

                Log.To.Listener.I(TAG, "Using X509 certificate {0} (issued by {1})",
                                  sslCert.Subject, sslCert.Issuer);
                _listener.SslConfiguration.ServerCertificate = sslCert;
            }
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="manager">The manager to use for opening DBs, etc</param>
        /// <param name="port">The port to listen on</param>
        /// <param name="options">The options to use when configuring the listener</param>
        /// <param name="realm">The realm to use when sending challenges</param>
        /// <param name="sslCert">The certificate to use when serving the listener over https</param>
        public CouchbaseLiteTcpListener(Manager manager, ushort port, CouchbaseLiteTcpOptions options, string realm, X509Certificate2 sslCert)
        {
            _manager  = manager;
            _listener = new HttpListener();
            _usesTLS  = options.HasFlag(CouchbaseLiteTcpOptions.UseTLS);
            string prefix = _usesTLS ? String.Format("https://*:{0}/", port) :
                            String.Format("http://*:{0}/", port);

            _listener.Prefixes.Add(prefix);
            _listener.AuthenticationSchemeSelector = SelectAuthScheme;
            HttpListener.DefaultServerString       = "Couchbase Lite " + Manager.VersionString;
            _listener.Realm  = realm;
            _allowsBasicAuth = options.HasFlag(CouchbaseLiteTcpOptions.AllowBasicAuth);

            _listener.UserCredentialsFinder = GetCredential;
            if (options.HasFlag(CouchbaseLiteTcpOptions.UseTLS))
            {
                #if NET_3_5
                throw new InvalidOperationException("TLS Listener not supported on .NET 3.5");
                #else
                _listener.SslConfiguration.EnabledSslProtocols       = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
                _listener.SslConfiguration.ClientCertificateRequired = false;
                if (sslCert == null)
                {
                    Log.To.Listener.I(TAG, "Generating X509 certificate for listener...");
                    sslCert = X509Manager.GenerateTransientCertificate("Couchbase-P2P");
                }

                Log.To.Listener.I(TAG, "Using X509 certificate {0} (issued by {1})",
                                  sslCert.Subject, sslCert.Issuer);
                _listener.SslConfiguration.ServerCertificate = sslCert;
                #endif
            }

            _listener.Log.Level  = WebSocketSharp.LogLevel.Trace;
            _listener.Log.Output = (data, msg) =>
            {
                switch (data.Level)
                {
                case WebSocketSharp.LogLevel.Fatal:
                    Log.To.Listener.E("HttpServer", data.Message);
                    break;

                case WebSocketSharp.LogLevel.Error:
                case WebSocketSharp.LogLevel.Warn:
                    Log.To.Listener.W("HttpServer", data.Message);
                    break;

                case WebSocketSharp.LogLevel.Info:
                    Log.To.Listener.I("HttpServer", data.Message);
                    break;

                case WebSocketSharp.LogLevel.Trace:
                case WebSocketSharp.LogLevel.Debug:
                    Log.To.Listener.V("HttpServer", data.Message);
                    break;
                }
            };
        }
        public void TestSsl()
        {
            var cert        = X509Manager.GetPersistentCertificate("127.0.0.1", "123abc", System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "unit_test.pfx"));
            var sslListener = new CouchbaseLiteTcpListener(manager, 59841, CouchbaseLiteTcpOptions.UseTLS, cert);

            sslListener.Start();

            ServicePointManager.ServerCertificateValidationCallback =
                (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) =>
            {
                // If the certificate is a valid, signed certificate, return true.
                if (sslPolicyErrors == SslPolicyErrors.None || sslPolicyErrors == SslPolicyErrors.RemoteCertificateNameMismatch)
                {
                    return(true);
                }

                // If there are errors in the certificate chain, look at each error to determine the cause.
                if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0)
                {
                    if (chain != null && chain.ChainStatus != null)
                    {
                        foreach (X509ChainStatus status in chain.ChainStatus)
                        {
                            if ((certificate.Subject == certificate.Issuer) &&
                                (status.Status == X509ChainStatusFlags.UntrustedRoot))
                            {
                                // Self-signed certificates with an untrusted root are valid.
                                continue;
                            }
                            else
                            {
                                if (status.Status != X509ChainStatusFlags.NoError)
                                {
                                    // If there are any other errors in the certificate chain, the certificate is invalid,
                                    // so the method returns false.
                                    return(false);
                                }
                            }
                        }
                    }

                    // When processing reaches this line, the only errors in the certificate chain are
                    // untrusted root errors for self-signed certificates. These certificates are valid
                    // for default Exchange server installations, so return true.
                    return(true);
                }
                else
                {
                    // In all other cases, return false.
                    return(false);
                }
            };

            try {
                var request  = (HttpWebRequest)WebRequest.Create("https://127.0.0.1:59841/");
                var response = (HttpWebResponse)request.GetResponse();
                Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);

                request = (HttpWebRequest)WebRequest.Create("http://127.0.0.1:59841/");
                Assert.Throws <WebException>(() => response = (HttpWebResponse)request.GetResponse());
            } finally {
                sslListener.Stop();
            }
        }