/// <summary> /// Handles HTTP Caching Headers and checks if the client has the /// latest version in cache. /// </summary> /// <param name="context">The HTTP Cache</param> /// <param name="site">The current site</param> /// <param name="content">The current content</param> /// <param name="expires">How many minutes the cache should be valid</param> /// <returns>If the client has the latest version</returns> public bool HandleCache(HttpContext context, Site site, RoutedContentBase content, int expires) { var headers = context.Response.GetTypedHeaders(); if (expires > 0 && content.Published.HasValue) { _logger?.LogDebug($"Setting HTTP Cache for [{ content.Slug }]"); var lastModified = !site.ContentLastModified.HasValue || content.LastModified > site.ContentLastModified ? content.LastModified : site.ContentLastModified.Value; var etag = Utils.GenerateETag(content.Id.ToString(), lastModified); headers.CacheControl = new CacheControlHeaderValue { Public = true, MaxAge = TimeSpan.FromMinutes(expires), }; headers.ETag = new EntityTagHeaderValue(etag); headers.LastModified = lastModified; if (HttpCaching.IsCached(context, etag, lastModified)) { _logger?.LogInformation("Client has current version. Setting NotModified"); context.Response.StatusCode = 304; return(true); } } else { _logger?.LogDebug($"Setting HTTP NoCache for [{ content.Slug }]"); headers.CacheControl = new CacheControlHeaderValue { NoCache = true }; } return(false); }
/// <summary> /// Invokes the middleware. /// </summary> /// <param name="context">The current http context</param> /// <returns>An async task</returns> public override async Task Invoke(HttpContext context) { if (!IsHandled(context) && !context.Request.Path.Value.StartsWith("/manager/assets/")) { var url = context.Request.Path.HasValue ? context.Request.Path.Value : ""; var response = PageRouter.Invoke(api, url); if (response != null) { if (logger != null) { logger.LogInformation($"Found page\n Route: {response.Route}\n Params: {response.QueryString}"); } if (string.IsNullOrWhiteSpace(response.RedirectUrl)) { using (var config = new Config(api)) { var headers = context.Response.GetTypedHeaders(); if (config.CacheExpiresPages > 0) { if (logger != null) { logger.LogInformation("Caching enabled. Setting MaxAge, LastModified & ETag"); } headers.CacheControl = new CacheControlHeaderValue() { Public = true, MaxAge = TimeSpan.FromMinutes(config.CacheExpiresPages), }; headers.Headers["ETag"] = response.CacheInfo.EntityTag; headers.LastModified = response.CacheInfo.LastModified; } else { headers.CacheControl = new CacheControlHeaderValue() { NoCache = true }; } } if (HttpCaching.IsCached(context, response.CacheInfo)) { if (logger != null) { logger.LogInformation("Client has current version. Returning NotModified"); } context.Response.StatusCode = 304; return; } else { context.Request.Path = new PathString(response.Route); if (context.Request.QueryString.HasValue) { context.Request.QueryString = new QueryString(context.Request.QueryString.Value + "&" + response.QueryString); } else { context.Request.QueryString = new QueryString("?" + response.QueryString); } } } else { if (logger != null) { logger.LogInformation($"Redirecting to url: {response.RedirectUrl}"); } context.Response.Redirect(response.RedirectUrl, response.RedirectType == Data.RedirectType.Permanent); return; } } } await next.Invoke(context); }
/// <summary> /// Invokes the middleware. /// </summary> /// <param name="context">The current http context</param> /// <param name="api">The current api</param> /// <returns>An async task</returns> public override async Task Invoke(HttpContext context, IApi api, IApplicationService service) { if (!IsHandled(context) && !context.Request.Path.Value.StartsWith("/manager/assets/")) { var url = context.Request.Path.HasValue ? context.Request.Path.Value : ""; var siteId = service.Site.Id; var response = await PostRouter.InvokeAsync(api, url, siteId); if (response != null) { _logger?.LogInformation($"Found post\n Route: {response.Route}\n Params: {response.QueryString}"); service.PageId = response.PageId; using (var config = new Config(api)) { var headers = context.Response.GetTypedHeaders(); var expires = config.CacheExpiresPosts; // Only use caching for published posts if (response.IsPublished && expires > 0) { _logger?.LogInformation("Caching enabled. Setting MaxAge, LastModified & ETag"); headers.CacheControl = new CacheControlHeaderValue { Public = true, MaxAge = TimeSpan.FromMinutes(expires), }; headers.ETag = new EntityTagHeaderValue(response.CacheInfo.EntityTag); headers.LastModified = response.CacheInfo.LastModified; } else { headers.CacheControl = new CacheControlHeaderValue { NoCache = true }; } } if (HttpCaching.IsCached(context, response.CacheInfo)) { _logger?.LogInformation("Client has current version. Returning NotModified"); context.Response.StatusCode = 304; return; } else { context.Request.Path = new PathString(response.Route); if (context.Request.QueryString.HasValue) { context.Request.QueryString = new QueryString(context.Request.QueryString.Value + "&" + response.QueryString); } else { context.Request.QueryString = new QueryString("?" + response.QueryString); } } } } await _next.Invoke(context); }
/// <summary> /// Invokes the middleware. /// </summary> /// <param name="context">The current http context</param> /// <returns>An async task</returns> public override async Task Invoke(HttpContext context) { if (!IsHandled(context) && !context.Request.Path.Value.StartsWith("/manager/assets/")) { var url = context.Request.Path.HasValue ? context.Request.Path.Value : ""; var authorized = true; var response = PostRouter.Invoke(api, url, context.Request.Host.Host); if (response != null) { if (logger != null) { logger.LogInformation($"Found post\n Route: {response.Route}\n Params: {response.QueryString}"); } if (!response.IsPublished) { if (!context.User.HasClaim(Security.Permission.PostPreview, Security.Permission.PostPreview)) { if (logger != null) { logger.LogInformation($"User not authorized to preview unpublished posts"); } authorized = false; } } if (authorized) { using (var config = new Config(api)) { var headers = context.Response.GetTypedHeaders(); // Only use caching for published posts if (response.IsPublished && config.CacheExpiresPosts > 0) { if (logger != null) { logger.LogInformation("Caching enabled. Setting MaxAge, LastModified & ETag"); } headers.CacheControl = new CacheControlHeaderValue() { Public = true, MaxAge = TimeSpan.FromMinutes(config.CacheExpiresPosts), }; headers.Headers["ETag"] = response.CacheInfo.EntityTag; headers.LastModified = response.CacheInfo.LastModified; } else { headers.CacheControl = new CacheControlHeaderValue() { NoCache = true }; } } if (HttpCaching.IsCached(context, response.CacheInfo)) { if (logger != null) { logger.LogInformation("Client has current version. Returning NotModified"); } context.Response.StatusCode = 304; return; } else { context.Request.Path = new PathString(response.Route); if (context.Request.QueryString.HasValue) { context.Request.QueryString = new QueryString(context.Request.QueryString.Value + "&" + response.QueryString); } else { context.Request.QueryString = new QueryString("?" + response.QueryString); } } } } } await next.Invoke(context); }
/// <summary> /// Invokes the middleware. /// </summary> /// <param name="context">The current http context</param> /// <param name="api">The current api</param> /// <returns>An async task</returns> public override async Task Invoke(HttpContext context, IApi api, IApplicationService service) { if (!IsHandled(context) && !context.Request.Path.Value.StartsWith("/manager/assets/")) { var url = context.Request.Path.HasValue ? context.Request.Path.Value : ""; var siteId = service.Site.Id; var authorized = true; var draft = IsDraft(context); var response = await PageRouter.InvokeAsync(api, url, siteId); if (response != null) { _logger?.LogInformation($"Found page\n Route: {response.Route}\n Params: {response.QueryString}"); if (!response.IsPublished) { if (!context.User.HasClaim(Security.Permission.PagePreview, Security.Permission.PagePreview)) { _logger?.LogInformation($"User not authorized to preview unpublished page"); authorized = false; } } if (authorized) { if (string.IsNullOrWhiteSpace(response.RedirectUrl)) { service.PageId = response.PageId; using (var config = new Config(api)) { var headers = context.Response.GetTypedHeaders(); var expires = config.CacheExpiresPages; // Only use caching for published pages if (response.IsPublished && expires > 0 && !draft) { _logger?.LogInformation("Caching enabled. Setting MaxAge, LastModified & ETag"); headers.CacheControl = new CacheControlHeaderValue { Public = true, MaxAge = TimeSpan.FromMinutes(expires), }; headers.ETag = new EntityTagHeaderValue(response.CacheInfo.EntityTag); headers.LastModified = response.CacheInfo.LastModified; } else { headers.CacheControl = new CacheControlHeaderValue { NoCache = true }; } } if (HttpCaching.IsCached(context, response.CacheInfo)) { _logger?.LogInformation("Client has current version. Returning NotModified"); context.Response.StatusCode = 304; return; } else { context.Request.Path = new PathString(response.Route); if (context.Request.QueryString.HasValue) { context.Request.QueryString = new QueryString(context.Request.QueryString.Value + "&" + response.QueryString); } else { context.Request.QueryString = new QueryString("?" + response.QueryString); } } } else { _logger?.LogInformation($"Redirecting to url: {response.RedirectUrl}"); context.Response.Redirect(response.RedirectUrl, response.RedirectType == RedirectType.Permanent); return; } } } } await _next.Invoke(context); }