/// <summary> /// Initializes a new instance of the <see cref="EntityTagHeaderOptions"/> class. /// </summary> /// <remarks> /// The following table shows the initial property values for an instance of <see cref="EntityTagHeaderOptions"/>. /// <list type="table"> /// <listheader> /// <term>Property</term> /// <description>Initial Value</description> /// </listheader> /// <item> /// <term><see cref="EntityTagParser"/></term> /// <description>A delegate that computes a MD5 hash of the body and add or update the necessary HTTP response headers needed to provide entity tag header information.</description> /// </item> /// </list> /// </remarks> public EntityTagHeaderOptions() { EntityTagParser = (body, request, response) => { var builder = new ChecksumBuilder(body.ComputeHash(o => { o.AlgorithmType = HashAlgorithmType.MD5; o.LeaveStreamOpen = true; }).Value); response.SetEntityTagHeaderInformation(request, builder); }; }
public void Mutate_Stream_Test() { var thisAssemblyFilePath = Assembly.GetExecutingAssembly().Location; using (var fileStream = File.OpenRead(thisAssemblyFilePath)) { var checksum = new ChecksumBuilder() .Mutate(fileStream) .Calculate() .ToString(); Assert.That(checksum, Is.Not.Null.Or.Empty); } }
/// <summary> /// Initializes a new instance of the <see cref="HttpEntityTagHeaderOptions"/> class. /// </summary> /// <remarks> /// The following table shows the initial property values for an instance of <see cref="HttpEntityTagHeaderOptions"/>. /// <list type="table"> /// <listheader> /// <term>Property</term> /// <description>Initial Value</description> /// </listheader> /// <item> /// <term><see cref="EntityTagProvider"/></term> /// <description><code> /// (integrity, context) => /// { /// var builder = new ChecksumBuilder(integrity.Checksum.Value); /// context.Response.SetEntityTagHeaderInformation(context.Request, builder, integrity.ChecksumStrength == ChecksumStrength.Weak); /// }; /// </code></description> /// </item> /// <item> /// <term><see cref="EntityTagResponseParser"/></term> /// <description><code> /// (body, request, response) => /// { /// var builder = new ChecksumBuilder(body.ComputeHash(o => /// { /// o.AlgorithmType = HashAlgorithmType.MD5; /// o.LeaveStreamOpen = true; /// }).Value); /// response.SetEntityTagHeaderInformation(request, builder); /// }; /// </code></description> /// </item> /// <item> /// <term><see cref="UseEntityTagResponseParser"/></term> /// <description><c>false</c></description> /// </item> /// </list> /// </remarks> public HttpEntityTagHeaderOptions() { EntityTagProvider = (integrity, context) => { var builder = new ChecksumBuilder(integrity.Checksum.Value); context.Response.SetEntityTagHeaderInformation(context.Request, builder, integrity.Validation == ChecksumStrength.Weak); }; EntityTagResponseParser = (body, request, response) => { var builder = new ChecksumBuilder(body.ComputeHash(o => { o.AlgorithmType = HashAlgorithmType.MD5; o.LeaveStreamOpen = true; }).Value); response.SetEntityTagHeaderInformation(request, builder); }; UseEntityTagResponseParser = false; }
/// <summary> /// Determines whether a cached version of the requested resource is found client-side using the If-None-Match HTTP header. /// </summary> /// <param name="request">An instance of the <see cref="HttpRequest"/> object.</param> /// <param name="builder">A <see cref="ChecksumBuilder"/> that represents the integrity of the client.</param> /// <returns> /// <c>true</c> if a cached version of the requested content is found client-side; otherwise, <c>false</c>. /// </returns> public static bool IsClientSideResourceCached(this HttpRequest request, ChecksumBuilder builder) { Validator.ThrowIfNull(request, nameof(request)); var headers = new RequestHeaders(request.Headers); if (headers.IfNoneMatch != null) { var clientSideEntityTagHeader = headers.IfNoneMatch.FirstOrDefault(); var clientSideEntityTag = clientSideEntityTagHeader == null ? "" : clientSideEntityTagHeader.Tag.Value; int indexOfStartQuote = clientSideEntityTag.IndexOf('"'); int indexOfEndQuote = clientSideEntityTag.LastIndexOf('"'); if (indexOfStartQuote == 0 && (indexOfEndQuote > 2 && indexOfEndQuote == clientSideEntityTag.Length - 1)) { clientSideEntityTag = clientSideEntityTag.Remove(indexOfEndQuote, 1); clientSideEntityTag = clientSideEntityTag.Remove(indexOfStartQuote, 1); } return(builder.Checksum.ToHexadecimal().Equals(clientSideEntityTag)); } return(false); }
/// <summary> /// This method will either add or update the necessary HTTP response headers needed to provide entity tag header information. /// </summary> /// <param name="response">The <see cref="HttpResponse"/> to extend.</param> /// <param name="request">An instance of the <see cref="HttpRequest"/> object.</param> /// <param name="builder">A <see cref="ChecksumBuilder"/> that represents the integrity of the client.</param> /// <param name="isWeak">A value that indicates if this entity-tag header is a weak validator.</param> public static void SetEntityTagHeaderInformation(this HttpResponse response, HttpRequest request, ChecksumBuilder builder, bool isWeak = false) { Validator.ThrowIfNull(response, nameof(response)); Validator.ThrowIfNull(request, nameof(request)); Validator.ThrowIfNull(builder, nameof(builder)); builder = builder.CombineWith(request.Headers["Accept"]); DateTime utcNow = DateTime.UtcNow; if (request.IsClientSideResourceCached(builder)) { response.StatusCode = StatusCodes.Status304NotModified; } else { response.Headers.AddOrUpdate(HeaderNames.LastModified, new StringValues(utcNow.ToString("R", DateTimeFormatInfo.InvariantInfo))); } response.Headers.AddOrUpdate(HeaderNames.ETag, new StringValues(builder.ToEntityTag(isWeak).ToString())); }
/// <summary> /// Creates an <see cref="EntityTagHeaderValue"/> from the specified <paramref name="builder"/>. /// </summary> /// <param name="builder">The <see cref="ChecksumBuilder"/> to extend.</param> /// <param name="isWeak">A value that indicates if this entity-tag header is a weak validator.</param> /// <returns>An <see cref="EntityTagHeaderValue"/> that is initiated with a hexadecimal representation of <see cref="ChecksumBuilder.Checksum"/> and a value that indicates if the tag is weak.</returns> public static EntityTagHeaderValue ToEntityTag(this ChecksumBuilder builder, bool isWeak = false) { Validator.ThrowIfNull(builder, nameof(builder)); return(new EntityTagHeaderValue(string.Concat("\"", builder.Checksum.ToHexadecimal(), "\""), isWeak)); }
/// <summary> /// This method will either add or update the necessary HTTP response headers needed to provide entity tag header information. /// </summary> /// <param name="response">The <see cref="HttpResponse"/> to extend.</param> /// <param name="request">An instance of the <see cref="HttpRequest"/> object.</param> /// <param name="builder">A <see cref="ChecksumBuilder"/> that represents the integrity of the client.</param> /// <param name="isWeak">A value that indicates if this entity-tag header is a weak validator.</param> public static void SetEntityTagHeaderInformation(this HttpResponse response, HttpRequest request, ChecksumBuilder builder, bool isWeak = false) { Validator.ThrowIfNull(response, nameof(response)); Validator.ThrowIfNull(request, nameof(request)); Validator.ThrowIfNull(builder, nameof(builder)); builder = builder.CombineWith(request.Headers[HeaderNames.Accept]); if (response.IsSuccessStatusCode() && request.IsClientSideResourceCached(builder)) { response.StatusCode = StatusCodes.Status304NotModified; } response.Headers.AddOrUpdate(HeaderNames.ETag, new StringValues(builder.ToEntityTag(isWeak).ToString())); }