예제 #1
0
        public static bool TryParse(string timedETagValue, out TimedEntityTagHeaderValue value)
        {
            value = null;
            if (timedETagValue == null)
            {
                return(false);
            }

            var strings = timedETagValue.Split(new[] { "\r\n" }, StringSplitOptions.None);

            if (strings.Length != 2)
            {
                return(false);
            }

            EntityTagHeaderValue etag = null;
            DateTimeOffset       lastModified;

            if (!EntityTagHeaderValue.TryParse(strings[0], out etag))
            {
                return(false);
            }

            if (!DateTimeOffset.TryParse(strings[1], out lastModified))
            {
                return(false);
            }

            value = new TimedEntityTagHeaderValue(etag.Tag, etag.IsWeak)
            {
                LastModified = lastModified
            };
            return(true);
        }
예제 #2
0
        private void CheckInvalidTryParse(string input)
        {
            EntityTagHeaderValue result = null;

            Assert.False(EntityTagHeaderValue.TryParse(input, out result));
            Assert.Null(result);
        }
예제 #3
0
        private void CheckInvalidParse(string input)
        {
            Assert.Throws <FormatException>(() => { EntityTagHeaderValue.Parse(input); });

            Assert.False(EntityTagHeaderValue.TryParse(input, out EntityTagHeaderValue result));
            Assert.Null(result);
        }
예제 #4
0
        public void TryParse()
        {
            EntityTagHeaderValue res;

            Assert.IsTrue(EntityTagHeaderValue.TryParse("\"\"", out res), "#1");
            Assert.AreEqual("\"\"", res.Tag, "#2");
        }
예제 #5
0
        public void TryParse_Invalid()
        {
            EntityTagHeaderValue res;

            Assert.IsFalse(EntityTagHeaderValue.TryParse("", out res), "#1");
            Assert.IsNull(res, "#2");
        }
예제 #6
0
        public async Task <CacheCandidateState> CheckRemoteCacheAsync(string url, string appPageVersionCurrent)
        {
            var request = new HttpRequestMessage(HttpMethod.Get, url);

            // Check for remote content based on the app page version
            if (EntityTagHeaderValue.TryParse(appPageVersionCurrent, out var eTagValue))
            {
                request.Headers.IfNoneMatch.Add(eTagValue);
            }

            var serverResponse = await _httpClient.SendAsync(request).ConfigureAwait(false);

            var contentType = serverResponse?.Content?.Headers?.ContentType?.MediaType;

            // Check if request returned some content
            if (serverResponse.StatusCode == HttpStatusCode.NotModified || contentType == null)
            {
                return(null);
            }

            // Check if we have a new entity tag
            var appPageVersion = serverResponse.Headers.ETag?.ToString() ?? string.Empty;

            var responseStream = await serverResponse.Content.ReadAsStreamAsync();

            return(new CacheCandidateState
            {
                ResponseStream = responseStream,
                StatusCode = serverResponse.StatusCode,
                AppPageVersion = appPageVersion,
                ContentType = contentType,
                ContentLength64 = responseStream.Length
            });
        }
예제 #7
0
        private void CheckValidTryParse(string input, EntityTagHeaderValue expectedResult)
        {
            EntityTagHeaderValue result = null;

            Assert.True(EntityTagHeaderValue.TryParse(input, out result));
            Assert.Equal(expectedResult, result);
        }
예제 #8
0
        public async Task <FetchTogglesResult> FetchToggles(string etag, CancellationToken cancellationToken)
        {
            const string resourceUri = "api/client/features";

            using (var request = new HttpRequestMessage(HttpMethod.Get, resourceUri))
            {
                SetRequestHeaders(request, ClientRequestHeaders);

                if (!string.IsNullOrEmpty(etag) && EntityTagHeaderValue.TryParse(etag, out var etagHeaderValue))
                {
                    request.Headers.IfNoneMatch.Add(etagHeaderValue);
                }

                using (var response = await httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false))
                {
                    if (response.StatusCode == HttpStatusCode.NotModified ||
                        (!string.IsNullOrEmpty(etag) && (response.Headers.ETag?.Tag?.Equals(etag) ?? false)))
                    {
                        return(new FetchTogglesResult
                        {
                            HasChanged = false,
                            Etag = response.Headers.ETag.Tag,
                            ToggleCollection = null
                        });
                    }

                    if (!response.IsSuccessStatusCode)
                    {
                        await HandleError(response, resourceUri);

                        return(new FetchTogglesResult
                        {
                            HasChanged = false,
                            Etag = null
                        });
                    }

                    var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);

                    var toggleCollection = JsonSerializer.Deserialize <ToggleCollection>(stream);

                    if (toggleCollection == null)
                    {
                        return(new FetchTogglesResult
                        {
                            HasChanged = false
                        });
                    }

                    // Success
                    return(new FetchTogglesResult
                    {
                        HasChanged = true,
                        Etag = response.Headers.ETag?.Tag,
                        ToggleCollection = toggleCollection
                    });
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Expects a Etag string e.g(W/"3141") and returns an EntityTagHeaderValue instance
        /// </summary>
        /// <param name="ETag"></param>
        /// <returns>EntityTagHeaderValue</returns>
        public static EntityTagHeaderValue GetETagEntityTagHeaderValueFromETagString(string ETag)
        {
            EntityTagHeaderValue TempEtag;

            if (EntityTagHeaderValue.TryParse(ETag, out TempEtag))
            {
                return(TempEtag);
            }
            throw new FormatException("ETag is not formated correctly, string was: " + ETag);
        }
        private async Task <bool> ContinueExecution(
            string concatenatedEtags,
            string modifiedDate,
            string representationId,
            Func <DateTime, ConcurrentObject, bool> checkDateCallback,
            Func <ConcurrentObject, List <EntityTagHeaderValue>, bool> checkEtagCorrectCallback)
        {
            if (string.IsNullOrWhiteSpace(concatenatedEtags) &&
                string.IsNullOrWhiteSpace(modifiedDate))
            {
                return(true);
            }

            // Check a representation exists
            var lastRepresentation = await _concurrencyManager.TryGetRepresentationAsync(representationId);

            if (lastRepresentation == null)
            {
                throw new ArgumentNullException($"the representation {representationId} doesn't exist");
            }

            if (string.IsNullOrWhiteSpace(concatenatedEtags) || concatenatedEtags == "*")
            {
                // Process the date
                DateTime dateTime;
                if (!DateTime.TryParse(modifiedDate, out dateTime))
                {
                    return(true);
                }

                return(checkDateCallback(dateTime, lastRepresentation));
            }
            else
            {
                // Check etags are correct
                var etagsStr = concatenatedEtags.Split(',');
                var etags    = new List <EntityTagHeaderValue>();
                foreach (var etagStr in etagsStr)
                {
                    EntityTagHeaderValue et = null;
                    if (EntityTagHeaderValue.TryParse(etagStr, out et))
                    {
                        etags.Add(et);
                    }
                }

                if (checkEtagCorrectCallback(lastRepresentation, etags))
                {
                    return(true);
                }
            }

            return(false);
        }
        internal static bool ContentIsNotModified(ResponseCachingContext context)
        {
            var cachedResponseHeaders = context.CachedResponseHeaders;
            var ifNoneMatchHeader     = context.HttpContext.Request.Headers[HeaderNames.IfNoneMatch];

            if (!StringValues.IsNullOrEmpty(ifNoneMatchHeader))
            {
                if (ifNoneMatchHeader.Count == 1 && StringSegment.Equals(ifNoneMatchHeader[0], EntityTagHeaderValue.Any.Tag, StringComparison.OrdinalIgnoreCase))
                {
                    context.Logger.LogNotModifiedIfNoneMatchStar();
                    return(true);
                }

                EntityTagHeaderValue         eTag;
                IList <EntityTagHeaderValue> ifNoneMatchEtags;
                if (!StringValues.IsNullOrEmpty(cachedResponseHeaders[HeaderNames.ETag]) &&
                    EntityTagHeaderValue.TryParse(cachedResponseHeaders[HeaderNames.ETag].ToString(), out eTag) &&
                    EntityTagHeaderValue.TryParseList(ifNoneMatchHeader, out ifNoneMatchEtags))
                {
                    for (var i = 0; i < ifNoneMatchEtags.Count; i++)
                    {
                        var requestETag = ifNoneMatchEtags[i];
                        if (eTag.Compare(requestETag, useStrongComparison: false))
                        {
                            context.Logger.LogNotModifiedIfNoneMatchMatched(requestETag);
                            return(true);
                        }
                    }
                }
            }
            else
            {
                var ifModifiedSince = context.HttpContext.Request.Headers[HeaderNames.IfModifiedSince];
                if (!StringValues.IsNullOrEmpty(ifModifiedSince))
                {
                    DateTimeOffset modified;
                    if (!HeaderUtilities.TryParseDate(cachedResponseHeaders[HeaderNames.LastModified].ToString(), out modified) &&
                        !HeaderUtilities.TryParseDate(cachedResponseHeaders[HeaderNames.Date].ToString(), out modified))
                    {
                        return(false);
                    }

                    DateTimeOffset modifiedSince;
                    if (HeaderUtilities.TryParseDate(ifModifiedSince.ToString(), out modifiedSince) &&
                        modified <= modifiedSince)
                    {
                        context.Logger.LogNotModifiedIfModifiedSinceSatisfied(modified, modifiedSince);
                        return(true);
                    }
                }
            }

            return(false);
        }
예제 #12
0
        public static ActionResult IntoBinaryResult <TError>(this Result <BinaryContent, TError> result) where TError : Error
        {
            if (result == null)
            {
                return(new StatusCodeResult(StatusCodes.Status422UnprocessableEntity));
            }

            return(result.Match <ActionResult>(
                       ok =>
            {
                if (ok == null)
                {
                    return new StatusCodeResult(StatusCodes.Status422UnprocessableEntity);
                }

                if (ok.Data == null)
                {
                    return new StatusCodeResult(StatusCodes.Status304NotModified);
                }

                var mime = ok.MimeType ?? "application/octet-stream";
                var res = new FileContentResult(ok.Data, mime);
                if (!string.IsNullOrEmpty(ok.ContentHash))
                {
                    EntityTagHeaderValue entityTagHeaderValue;
                    bool isValid = EntityTagHeaderValue.TryParse($"\"{ok.ContentHash}\"", out entityTagHeaderValue);
                    if (!isValid)
                    {
                        isValid = EntityTagHeaderValue.TryParse(ok.ContentHash, out entityTagHeaderValue);
                    }

                    if (!isValid)
                    {
                        throw new ServerErrorException($"Unprocessable ETag: {ok.ContentHash}");
                    }

                    res.EntityTag = entityTagHeaderValue;
                }
                return res;
            },
                       err =>
            {
                var res = new ObjectResult(err);
                res.StatusCode = err.ErrorCode.IntoStatusCode();
                return res;
            }));
        }
예제 #13
0
        public async Task GetEntityWithIfNoneMatchShouldReturnNotModifiedETagsTest_ForDouble()
        {
            // Arrange
            HttpClient client = CreateClient();
            string     eTag;

            var getUri = "double/ETagsCustomers?$format=json";

            // Act
            using (var response = await client.GetAsync(getUri))
            {
                // Assert
                Assert.True(response.IsSuccessStatusCode);

                var json = await response.Content.ReadAsObject <JObject>();

                var result = json.GetValue("value") as JArray;
                Assert.NotNull(result);

                // check the first unchanged, the first unchanged could be "3"
                // because #0, #1, #2 will change potentially running in parallel by other tests.
                eTag = result[3]["@odata.etag"].ToString();
                Assert.False(String.IsNullOrEmpty(eTag));
                Assert.Equal("W/\"OC4w\"", eTag);

                EntityTagHeaderValue parsedValue;
                Assert.True(EntityTagHeaderValue.TryParse(eTag, out parsedValue));
                IDictionary <string, object>  tags = this.ParseETag(parsedValue);
                KeyValuePair <string, object> pair = Assert.Single(tags);
                Single value = Assert.IsType <Single>(pair.Value);
                Assert.Equal((Single)8.0, value);
            }

            // Arrange
            var getRequestWithEtag = new HttpRequestMessage(HttpMethod.Get, "double/ETagsCustomers(3)");

            getRequestWithEtag.Headers.IfNoneMatch.ParseAdd(eTag);

            // Act
            using (var response = await client.SendAsync(getRequestWithEtag))
            {
                // Assert
                Assert.Equal(HttpStatusCode.NotModified, response.StatusCode);
            }
        }
예제 #14
0
        private int? GetIfMatchFromHeader()
        {
            var header = HttpContext.Request.Headers.GetHeaderValue(HeaderConstants.IfMatch);

            if (header == null)
                return null;

            _ = EntityTagHeaderValue.TryParse(header, out var entityTagHeaderValue);

            if (entityTagHeaderValue == null)
                return null;

            var version = entityTagHeaderValue.Tag.Replace("\"", string.Empty);

            if (int.TryParse(version, out var numericValue))
                return numericValue;

            return null;
        }
예제 #15
0
        public async Task GetEntryWithIfNoneMatchShouldReturnNotModifiedETagsTest_ForDouble()
        {
            string eTag;

            var getUri = this.BaseAddress + "/double/ETagsCustomers?$format=json";

            using (var response = await Client.GetAsync(getUri))
            {
                Assert.True(response.IsSuccessStatusCode);

                var json = await response.Content.ReadAsAsync <JObject>();

                var result = json.GetValue("value") as JArray;
                Assert.NotNull(result);

                // check the first
                eTag = result[0]["@odata.etag"].ToString();
                Assert.False(String.IsNullOrEmpty(eTag));
                Assert.Equal("W/\"Mi4w\"", eTag);

                EntityTagHeaderValue parsedValue;
                Assert.True(EntityTagHeaderValue.TryParse(eTag, out parsedValue));
                HttpConfiguration             config  = new HttpConfiguration();
                IETagHandler                  handler = config.GetETagHandler();
                IDictionary <string, object>  tags    = handler.ParseETag(parsedValue);
                KeyValuePair <string, object> pair    = Assert.Single(tags);
                Single value = Assert.IsType <Single>(pair.Value);
                Assert.Equal((Single)2.0, value);
            }

            var getRequestWithEtag = new HttpRequestMessage(HttpMethod.Get, this.BaseAddress + "/double/ETagsCustomers(0)");

            getRequestWithEtag.Headers.IfNoneMatch.ParseAdd(eTag);
            using (var response = await Client.SendAsync(getRequestWithEtag))
            {
                Assert.Equal(HttpStatusCode.NotModified, response.StatusCode);
            }
        }
예제 #16
0
        public async Task GetEntryWithIfNoneMatchShouldReturnNotModifiedETagsTest_ForShort()
        {
            string eTag;

            var getUri = this.BaseAddress + "/short/ETagsCustomers?$format=json";

            using (var response = await Client.GetAsync(getUri))
            {
                Assert.True(response.IsSuccessStatusCode);

                var json = await response.Content.ReadAsObject <JObject>();

                var result = json.GetValue("value") as JArray;
                Assert.NotNull(result);

                // check the second
                eTag = result[1]["@odata.etag"].ToString();
                Assert.False(String.IsNullOrEmpty(eTag));
                Assert.Equal("W/\"MzI3NjY=\"", eTag);

                EntityTagHeaderValue parsedValue;
                Assert.True(EntityTagHeaderValue.TryParse(eTag, out parsedValue));
                IDictionary <string, object>  tags = this.ParseETag(parsedValue);
                KeyValuePair <string, object> pair = Assert.Single(tags);
                int value = Assert.IsType <int>(pair.Value);
                Assert.Equal((short)32766, value);
            }

            var getRequestWithEtag = new HttpRequestMessage(HttpMethod.Get, this.BaseAddress + "/short/ETagsCustomers(1)");

            getRequestWithEtag.Headers.IfNoneMatch.ParseAdd(eTag);
            using (var response = await Client.SendAsync(getRequestWithEtag))
            {
                Assert.Equal(HttpStatusCode.NotModified, response.StatusCode);
            }
        }
예제 #17
0
        public async Task <FetchTogglesResult> FetchToggles(string etag, CancellationToken cancellationToken)
        {
            const string resourceUri = "api/client/features";

            using (var request = new HttpRequestMessage(HttpMethod.Get, resourceUri))
            {
                SetRequestHeaders(request, clientRequestHeaders);

                if (EntityTagHeaderValue.TryParse(etag, out var etagHeaderValue))
                {
                    request.Headers.IfNoneMatch.Add(etagHeaderValue);
                }

                using (var response = await httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false))
                {
                    if (!response.IsSuccessStatusCode)
                    {
                        var error = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                        Logger.Trace($"UNLEASH: Error {response.StatusCode} from server in '{nameof(FetchToggles)}': " + error);

                        return(new FetchTogglesResult
                        {
                            HasChanged = false,
                            Etag = null,
                        });
                    }

                    var newEtag = response.Headers.ETag?.Tag;
                    if (newEtag == etag)
                    {
                        return(new FetchTogglesResult
                        {
                            HasChanged = false,
                            Etag = newEtag,
                            ToggleCollection = null,
                        });
                    }

                    var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);

                    var toggleCollection = jsonSerializer.Deserialize <ToggleCollection>(stream);

                    if (toggleCollection == null)
                    {
                        return(new FetchTogglesResult
                        {
                            HasChanged = false
                        });
                    }

                    // Success
                    return(new FetchTogglesResult
                    {
                        HasChanged = true,
                        Etag = newEtag,
                        ToggleCollection = toggleCollection
                    });
                }
            }
        }