protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken)
        {
            int retryCount;

            do
            {
                if (Authenticator != null && response.StatusCode == HttpStatusCode.Unauthorized)
                {
                    retryCount = _retryMessages.GetOrAdd(response, 0);
                    if (retryCount >= 5)
                    {
                        // Multiple concurrent requests means that the Nc can sometimes get out of order
                        // so try again, but within reason.
                        break;
                    }

                    _retryMessages.TryUpdate(response, retryCount + 1, retryCount);
                    var newRequest = new HttpRequestMessage(response.RequestMessage.Method, response.RequestMessage.RequestUri);
                    foreach (var header in response.RequestMessage.Headers)
                    {
                        if (header.Key != "Authorization")
                        {
                            newRequest.Headers.Add(header.Key, header.Value);
                        }
                    }

                    newRequest.Content = response.RequestMessage.Content;
                    var challengeResponse = Authenticator.ResponseFromChallenge(response);
                    if (challengeResponse != null)
                    {
                        newRequest.Headers.Add("Authorization", challengeResponse);
                        return(ProcessResponse(SendAsync(newRequest, cancellationToken).Result, cancellationToken));
                    }
                }
            }  while(false);

            var hasSetCookie = response.Headers.Contains("Set-Cookie");

            if (hasSetCookie)
            {
                var cookie = default(Cookie);
                if (CookieParser.TryParse(response.Headers.GetValues("Set-Cookie").ElementAt(0), response.RequestMessage.RequestUri.Host,
                                          out cookie))
                {
                    lock (_locker) {
                        try {
                            _cookieStore.Add(cookie);
                        } catch (CookieException e) {
                            var headerValue = new SecureLogString(response.Headers.GetValues("Set-Cookie").ElementAt(0),
                                                                  LogMessageSensitivity.Insecure);
                            Log.To.Sync.W("DefaultAuthHandler",
                                          $"Invalid cookie string received from remote: {headerValue}", e);
                        }
                    }
                }
            }

            _retryMessages.TryRemove(response, out retryCount);
            return(response);
        }
        private void AddRequestHeaders(HttpRequestMessage request)
        {
            foreach (var requestHeaderKey in RequestHeaders.Keys)
            {
                if (requestHeaderKey.ToLowerInvariant() == "cookie")
                {
                    Cookie cookie;
                    var    cookieStr = RequestHeaders[requestHeaderKey];
                    if (!CookieParser.TryParse(cookieStr, request.RequestUri.Host, out cookie))
                    {
                        Log.To.Sync.W(Tag, "Invalid cookie string received, {0}",
                                      new SecureLogString(cookieStr, LogMessageSensitivity.Insecure));
                    }
                    else
                    {
                        try {
                            CookieStore.Add(cookie);
                        } catch (CookieException e) {
                            var headerValue = new SecureLogString(cookieStr, LogMessageSensitivity.Insecure);
                            Log.To.Sync.W(Tag, $"Invalid cookie string received, {headerValue}", e);
                        }
                    }

                    request.Headers.Add("Cookie", CookieStore.GetCookieHeader(request.RequestUri));
                    continue;
                }


                request.Headers.Add(requestHeaderKey, RequestHeaders.Get(requestHeaderKey));
            }
        }
Beispiel #3
0
        // This is used by the listener
        internal Replication ReplicationWithProperties(IDictionary <string, object> properties)
        {
            // Extract the parameters from the JSON request body:
            // http://wiki.apache.org/couchdb/Replication

            bool push, createTarget;
            var  results = new Dictionary <string, object>()
            {
                { "database", null },
                { "remote", null },
                { "headers", null },
                { "authorizer", null }
            };

            Status result = ParseReplicationProperties(properties, out push, out createTarget, results);

            if (result.IsError)
            {
                throw Misc.CreateExceptionAndLog(Log.To.Listener, result.Code, TAG, "Failed to create replication");
            }

            object continuousObj = properties.Get("continuous");
            bool   continuous    = false;

            if (continuousObj is bool)
            {
                continuous = (bool)continuousObj;
            }

            var         scheduler = new SingleTaskThreadpoolScheduler();
            Replication rep       = null;

            if (push)
            {
                rep = new Pusher((Database)results["database"], (Uri)results["remote"], continuous, new TaskFactory(scheduler));
            }
            else
            {
                rep = new Puller((Database)results["database"], (Uri)results["remote"], continuous, new TaskFactory(scheduler));
            }

            rep.Filter       = properties.Get("filter") as string;
            rep.FilterParams = properties.Get("query_params").AsDictionary <string, object>();
            rep.DocIds       = properties.Get("doc_ids").AsList <string>();
            rep.Headers      = new Dictionary <string, string>();
            foreach (var header in results.Get("headers").AsDictionary <string, string>())
            {
                if (header.Key.ToLowerInvariant() == "cookie")
                {
                    var cookie = default(Cookie);
                    if (CookieParser.TryParse(header.Value, ((Uri)results["remote"]).GetLeftPart(UriPartial.Authority), out cookie))
                    {
                        rep.SetCookie(cookie.Name, cookie.Value, cookie.Path, cookie.Expires, cookie.Secure, cookie.HttpOnly);
                    }
                    else
                    {
                        Log.To.Listener.W(TAG, "Invalid cookie string received ({0}), ignoring...", header.Value);
                    }
                }
                else
                {
                    rep.Headers.Add(header.Key, header.Value);
                }
            }
            rep.Headers       = results.Get("headers").AsDictionary <string, string>();
            rep.Authenticator = results.Get("authorizer") as IAuthenticator;
            if (push)
            {
                ((Pusher)rep).CreateTarget = createTarget;
            }

            var db = (Database)results["database"];

            // If this is a duplicate, reuse an existing replicator:
            var activeReplicators = default(IList <Replication>);
            var existing          = default(Replication);

            if (db.ActiveReplicators.AcquireTemp(out activeReplicators))
            {
                existing = activeReplicators.FirstOrDefault(x => x.LocalDatabase == rep.LocalDatabase &&
                                                            x.RemoteUrl == rep.RemoteUrl && x.IsPull == rep.IsPull &&
                                                            x.RemoteCheckpointDocID().Equals(rep.RemoteCheckpointDocID()));
            }


            return(existing ?? rep);
        }