<commit_before>﻿using Blogifier.Core.Common;
using Blogifier.Core.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Blogifier.Core.Middleware
{
    public class EmbeddedResources
	{
		readonly RequestDelegate _next;
        readonly ILogger _logger;
        Dictionary<string, CachedResource> _resources;

		public EmbeddedResources(RequestDelegate next, ILogger<EmbeddedResources> logger)
		{
			_next = next;
            _logger = logger;
            _resources = new Dictionary<string, CachedResource>();
			var assembly = typeof(EmbeddedResources).GetTypeInfo().Assembly;

			foreach (var name in assembly.GetManifestResourceNames())
			{
				if (name.Contains("Blogifier.Core.embedded") && Include(name))
				{
                    var path = name.ReplaceIgnoreCase("Blogifier.Core", "").ToLower();
                    var resource = GetResource(name, assembly);
					_resources.Add(path, resource);
                    _logger.LogInformation("EMBEDDED: " + path);
				}
			}
		}

        public async Task Invoke(HttpContext context)
        {
            var path = context.Request.Path.ToString().ToLower().Replace("/", ".");

            if (path.Contains(".embedded.", StringComparison.OrdinalIgnoreCase))
            {
                try
                {
                    // embedded resources never change, set eTag and cache for a year
                    var requestedETag = context.Request.Headers[HeaderNames.IfNoneMatch];
                    var responseETag = GetToken(Encoding.ASCII.GetBytes(path));

                    if (requestedETag == responseETag)
                        context.Response.StatusCode = (int)HttpStatusCode.NotModified;

                    var resource = _resources[path];
                    Stream stream = new MemoryStream(resource.Content);

                    SetContextHeaders(context, responseETag, resource.ContentType, stream.Length);

                    await stream.CopyToAsync(context.Response.Body);
                }
                catch (Exception ex)
                {
                    if(ex.Message == "Write to non-body 304 response." || ex.Message == "Writing to the response body is invalid for responses with status code 304.")
                    {
                        try
                        {
                            context.Response.StatusCode = 304;
                            return;
                        }
                        catch(Exception x)
                        {
                            var z = x.Message;
                        }
                    }
                    else
                    {
                        _logger.LogError(string.Format("Error processing embedded resource : ", ex.Message));
                    }
                }
            }
            else
            {
                await _next.Invoke(context);
            }
        }

        void SetContextHeaders(HttpContext context, string etag, string resType, long length)
        {
            // marker to identify embedded resource for troublshooting
            context.Response.Headers.Add("Embedded-Content", "true");

            context.Response.Headers.Add(HeaderNames.CacheControl, "max-age=" + TimeSpan.FromDays(365));
            context.Response.Headers.Add(HeaderNames.ETag, new[] { etag });

            if (ApplicationSettings.AddContentTypeHeaders)
                context.Response.ContentType = resType;

            if (ApplicationSettings.AddContentLengthHeaders)
                context.Response.ContentLength = length;
        }

        CachedResource GetResource(string path, Assembly assembly)
        {
            var stream = assembly.GetManifestResourceStream(path);

            var resource = new CachedResource();
            resource.ContentType = GetContentType(path);

            using (var memoryStream = new MemoryStream())
            {
                stream.CopyTo(memoryStream);
                resource.Content = memoryStream.ToArray();<commit_msg>Etag handling removef from embedded middlware - causes hanging issues in .net core 2.0<commit_after>﻿using Blogifier.Core.Common;
using Blogifier.Core.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Blogifier.Core.Middleware
{
    public class EmbeddedResources
	{
		readonly RequestDelegate _next;
        readonly ILogger _logger;
        Dictionary<string, CachedResource> _resources;

		public EmbeddedResources(RequestDelegate next, ILogger<EmbeddedResources> logger)
		{
			_next = next;
            _logger = logger;
            _resources = new Dictionary<string, CachedResource>();
			var assembly = typeof(EmbeddedResources).GetTypeInfo().Assembly;

			foreach (var name in assembly.GetManifestResourceNames())
			{
				if (name.Contains("Blogifier.Core.embedded") && Include(name))
				{
                    var path = name.ReplaceIgnoreCase("Blogifier.Core", "").ToLower();
                    var resource = GetResource(name, assembly);
					_resources.Add(path, resource);
                    _logger.LogInformation("EMBEDDED: " + path);
				}
			}
		}

        public async Task Invoke(HttpContext context)
        {
            var path = context.Request.Path.ToString().ToLower().Replace("/", ".");

            if (path.Contains(".embedded.", StringComparison.OrdinalIgnoreCase))
            {
                try
                {
                    var resource = _resources[path];
                    Stream stream = new MemoryStream(resource.Content);

                    SetContextHeaders(context, resource.ContentType, stream.Length);

                    await stream.CopyToAsync(context.Response.Body);
                }
                catch (Exception ex)
                {
                    _logger.LogError(string.Format("Error processing embedded resource : ", ex.Message));
                }
            }
            else
            {
                await _next.Invoke(context);
            }
        }

        void SetContextHeaders(HttpContext context, string resType, long length)
        {
            // marker to identify embedded resource for troublshooting
            context.Response.Headers.Add("Embedded-Content", "true");

            if (ApplicationSettings.AddContentTypeHeaders)
                context.Response.ContentType = resType;

            if (ApplicationSettings.AddContentLengthHeaders)
                context.Response.ContentLength = length;
        }

        CachedResource GetResource(string path, Assembly assembly)
        {
            var stream = assembly.GetManifestResourceStream(path);

            var resource = new CachedResource();
            resource.ContentType = GetContentType(path);

            using (var memoryStream = new MemoryStream())
            {
                stream.CopyTo(memoryStream);
                resource.Content = memoryStream.ToArray();
{'fraction_non_alphanumeric': 0.08884993932856951, 'fraction_numerical': 0.001887555615477956, 'mean_word_length': 1.918174665617624, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5389818', 'n_tokens_mistral': 1870, 'n_tokens_neox': 1726, 'n_words': 390}