parent
dc6b066e79
commit
693a1df34f
@ -65,9 +65,21 @@ open System.Collections.Concurrent
|
|||||||
/// settings update page</remarks>
|
/// settings update page</remarks>
|
||||||
module WebLogCache =
|
module WebLogCache =
|
||||||
|
|
||||||
|
open System.Text.RegularExpressions
|
||||||
|
|
||||||
|
/// A redirect rule that caches compiled regular expression rules
|
||||||
|
type CachedRedirectRule =
|
||||||
|
/// A straight text match rule
|
||||||
|
| Text of string * string
|
||||||
|
/// A regular expression match rule
|
||||||
|
| RegEx of Regex * string
|
||||||
|
|
||||||
/// The cache of web log details
|
/// The cache of web log details
|
||||||
let mutable private _cache : WebLog list = []
|
let mutable private _cache : WebLog list = []
|
||||||
|
|
||||||
|
/// Redirect rules with compiled regular expressions
|
||||||
|
let mutable private _redirectCache = ConcurrentDictionary<WebLogId, CachedRedirectRule list> ()
|
||||||
|
|
||||||
/// Try to get the web log for the current request (longest matching URL base wins)
|
/// Try to get the web log for the current request (longest matching URL base wins)
|
||||||
let tryGet (path : string) =
|
let tryGet (path : string) =
|
||||||
_cache
|
_cache
|
||||||
@ -78,6 +90,16 @@ module WebLogCache =
|
|||||||
/// Cache the web log for a particular host
|
/// Cache the web log for a particular host
|
||||||
let set webLog =
|
let set webLog =
|
||||||
_cache <- webLog :: (_cache |> List.filter (fun wl -> wl.Id <> webLog.Id))
|
_cache <- webLog :: (_cache |> List.filter (fun wl -> wl.Id <> webLog.Id))
|
||||||
|
_redirectCache[webLog.Id] <-
|
||||||
|
webLog.RedirectRules
|
||||||
|
|> List.map (fun it ->
|
||||||
|
let relUrl = Permalink >> WebLog.relativeUrl webLog
|
||||||
|
let urlTo = if it.To.Contains "://" then it.To else relUrl it.To
|
||||||
|
if it.IsRegex then
|
||||||
|
let pattern = if it.From.StartsWith "^" then $"^{relUrl (it.From.Substring 1)}" else it.From
|
||||||
|
RegEx (new Regex (pattern, RegexOptions.Compiled ||| RegexOptions.IgnoreCase), urlTo)
|
||||||
|
else
|
||||||
|
Text (relUrl it.From, urlTo))
|
||||||
|
|
||||||
/// Get all cached web logs
|
/// Get all cached web logs
|
||||||
let all () =
|
let all () =
|
||||||
@ -86,9 +108,13 @@ module WebLogCache =
|
|||||||
/// Fill the web log cache from the database
|
/// Fill the web log cache from the database
|
||||||
let fill (data : IData) = backgroundTask {
|
let fill (data : IData) = backgroundTask {
|
||||||
let! webLogs = data.WebLog.All ()
|
let! webLogs = data.WebLog.All ()
|
||||||
_cache <- webLogs
|
webLogs |> List.iter set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the cached redirect rules for the given web log
|
||||||
|
let redirectRules webLogId =
|
||||||
|
_redirectCache[webLogId]
|
||||||
|
|
||||||
/// Is the given theme in use by any web logs?
|
/// Is the given theme in use by any web logs?
|
||||||
let isThemeInUse themeId =
|
let isThemeInUse themeId =
|
||||||
_cache |> List.exists (fun wl -> wl.ThemeId = themeId)
|
_cache |> List.exists (fun wl -> wl.ThemeId = themeId)
|
||||||
|
@ -26,6 +26,30 @@ type WebLogMiddleware (next : RequestDelegate, log : ILogger<WebLogMiddleware>)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Middleware to check redirects for the current web log
|
||||||
|
type RedirectRuleMiddleware (next : RequestDelegate, log : ILogger<RedirectRuleMiddleware>) =
|
||||||
|
|
||||||
|
/// Shorthand for case-insensitive string equality
|
||||||
|
let ciEquals str1 str2 =
|
||||||
|
System.String.Equals (str1, str2, System.StringComparison.InvariantCultureIgnoreCase)
|
||||||
|
|
||||||
|
member _.InvokeAsync (ctx : HttpContext) = task {
|
||||||
|
let path = ctx.Request.Path.Value.ToLower ()
|
||||||
|
let matched =
|
||||||
|
WebLogCache.redirectRules ctx.WebLog.Id
|
||||||
|
|> List.tryPick (fun rule ->
|
||||||
|
match rule with
|
||||||
|
| WebLogCache.CachedRedirectRule.Text (urlFrom, urlTo) ->
|
||||||
|
log.LogInformation $"Checking {path} against from={urlFrom} and to={urlTo}"
|
||||||
|
if ciEquals path urlFrom then Some urlTo else None
|
||||||
|
| WebLogCache.CachedRedirectRule.RegEx (regExFrom, patternTo) ->
|
||||||
|
if regExFrom.IsMatch path then Some (regExFrom.Replace (path, patternTo)) else None)
|
||||||
|
match matched with
|
||||||
|
| Some url -> ctx.Response.Redirect (url, permanent = true)
|
||||||
|
| None -> return! next.Invoke ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
open System
|
open System
|
||||||
open BitBadger.Npgsql.FSharp.Documents
|
open BitBadger.Npgsql.FSharp.Documents
|
||||||
open Microsoft.Extensions.DependencyInjection
|
open Microsoft.Extensions.DependencyInjection
|
||||||
@ -207,6 +231,7 @@ let main args =
|
|||||||
|
|
||||||
let _ = app.UseCookiePolicy (CookiePolicyOptions (MinimumSameSitePolicy = SameSiteMode.Strict))
|
let _ = app.UseCookiePolicy (CookiePolicyOptions (MinimumSameSitePolicy = SameSiteMode.Strict))
|
||||||
let _ = app.UseMiddleware<WebLogMiddleware> ()
|
let _ = app.UseMiddleware<WebLogMiddleware> ()
|
||||||
|
let _ = app.UseMiddleware<RedirectRuleMiddleware> ()
|
||||||
let _ = app.UseAuthentication ()
|
let _ = app.UseAuthentication ()
|
||||||
let _ = app.UseStaticFiles ()
|
let _ = app.UseStaticFiles ()
|
||||||
let _ = app.UseRouting ()
|
let _ = app.UseRouting ()
|
||||||
|
Loading…
Reference in New Issue
Block a user