示例#1
0
        private async Task <bool> HandleUnsuccessfulResponse <TResult>(ChoosenNode choosenNode, JsonOperationContext context, RavenCommand <TResult> command,
                                                                       HttpResponseMessage response, string url)
        {
            switch (response.StatusCode)
            {
            case HttpStatusCode.NotFound:
                command.SetResponse(null);
                return(true);

            case HttpStatusCode.Unauthorized:
            case HttpStatusCode.PreconditionFailed:
                if (string.IsNullOrEmpty(choosenNode.Node.ApiKey))
                {
                    throw new UnauthorizedAccessException(
                              $"Got unauthorized response exception for {url}. Please specify an API Key.");
                }
                if (++command.AuthenticationRetries > 1)
                {
                    throw new UnauthorizedAccessException(
                              $"Got unauthorized response exception for {url} after trying to authenticate using ApiKey.");
                }

                var oauthSource = response.Headers.GetFirstValue("OAuth-Source");

#if DEBUG && FIDDLER
// Make sure to avoid a cross DNS security issue, when running with Fiddler
                if (string.IsNullOrEmpty(oauthSource) == false)
                {
                    oauthSource = oauthSource.Replace("localhost:", "localhost.fiddler:");
                }
#endif

                await HandleUnauthorized(oauthSource, choosenNode.Node, context).ConfigureAwait(false);
                await ExecuteAsync(choosenNode, context, command).ConfigureAwait(false);

                return(true);

            case HttpStatusCode.Forbidden:
                throw new UnauthorizedAccessException(
                          $"Forbidan access to {url}. Make sure you're using the correct ApiKey.");

            case HttpStatusCode.BadGateway:
            case HttpStatusCode.ServiceUnavailable:
                await HandleServerDown(choosenNode, context, command, null);

                break;

            case HttpStatusCode.Conflict:
                // TODO: Conflict resolution
                // current implementation is temporary
                object message;
                using (var stream = await response.Content.ReadAsStreamAsync())
                {
                    var blittableJsonReaderObject = await context.ReadForMemoryAsync(stream, "PutResult");

                    blittableJsonReaderObject.TryGetMember("Message", out message);
                }
                throw new ConcurrencyException(message.ToString());

            default:
                await ThrowServerError(context, response);

                break;
            }
            return(false);
        }
示例#2
0
        public async Task ExecuteAsync <TResult>(ChoosenNode choosenNode, JsonOperationContext context, RavenCommand <TResult> command, CancellationToken token = default(CancellationToken))
        {
            string url;
            var    request = CreateRequest(choosenNode.Node, command, out url);

            long cachedEtag;
            BlittableJsonReaderObject cachedValue;

            HttpCache.ReleaseCacheItem cachedItem;
            using (cachedItem = GetFromCache(context, command, request, url, out cachedEtag, out cachedValue))
            {
                if (cachedEtag != 0)
                {
                    var aggresiveCacheOptions = AggressiveCaching.Value;
                    if (aggresiveCacheOptions != null && cachedItem.Age < aggresiveCacheOptions.Duration)
                    {
                        command.SetResponse(cachedValue);
                        return;
                    }

                    request.Headers.IfNoneMatch.Add(new EntityTagHeaderValue("\"" + cachedEtag + "\""));
                }

                var sp = Stopwatch.StartNew();
                HttpResponseMessage response;
                try
                {
                    response = await _httpClient.SendAsync(request, token).ConfigureAwait(false);

                    sp.Stop();
                }
                catch (HttpRequestException e) // server down, network down
                {
                    sp.Stop();
                    await HandleServerDown(choosenNode, context, command, e);

                    return;
                }
                finally
                {
                    var requestTimeInMilliseconds = sp.ElapsedMilliseconds;
                    choosenNode.Node.UpdateRequestTime(requestTimeInMilliseconds);
                    if (choosenNode.SkippedNodes != null)
                    {
                        foreach (var skippedNode in choosenNode.SkippedNodes)
                        {
                            skippedNode.DecreaseRate(requestTimeInMilliseconds);
                        }
                    }
                }

                if (response.StatusCode == HttpStatusCode.NotModified)
                {
                    cachedItem.NotModified();
                    command.SetResponse(cachedValue);
                    return;
                }
                if (response.IsSuccessStatusCode == false)
                {
                    if (await HandleUnsuccessfulResponse(choosenNode, context, command, response, url))
                    {
                        return;
                    }
                }

                if (response.Content.Headers.ContentLength.HasValue && response.Content.Headers.ContentLength == 0)
                {
                    return;
                }

                await command.ProcessResponse(context, _cache, response, url);
            }
        }