[backend/federation] Add short-lived cache for non-specific federation requests
This commit is contained in:
parent
762278426f
commit
ff59b07035
4 changed files with 27 additions and 0 deletions
|
@ -12,6 +12,7 @@ using Iceshrimp.Backend.Core.Middleware;
|
||||||
using Iceshrimp.Backend.Core.Queues;
|
using Iceshrimp.Backend.Core.Queues;
|
||||||
using Iceshrimp.Backend.Core.Services;
|
using Iceshrimp.Backend.Core.Services;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.OutputCaching;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
@ -108,6 +109,7 @@ public class ActivityPubController(
|
||||||
|
|
||||||
[HttpGet("/users/{id}")]
|
[HttpGet("/users/{id}")]
|
||||||
[AuthorizedFetch]
|
[AuthorizedFetch]
|
||||||
|
[OutputCache(PolicyName = "federation")]
|
||||||
[MediaTypeRouteFilter("application/activity+json", "application/ld+json")]
|
[MediaTypeRouteFilter("application/activity+json", "application/ld+json")]
|
||||||
[OverrideResultType<ASActor>]
|
[OverrideResultType<ASActor>]
|
||||||
[ProducesResults(HttpStatusCode.OK, HttpStatusCode.MovedPermanently)]
|
[ProducesResults(HttpStatusCode.OK, HttpStatusCode.MovedPermanently)]
|
||||||
|
@ -129,6 +131,7 @@ public class ActivityPubController(
|
||||||
|
|
||||||
[HttpGet("/users/{id}/collections/featured")]
|
[HttpGet("/users/{id}/collections/featured")]
|
||||||
[AuthorizedFetch]
|
[AuthorizedFetch]
|
||||||
|
[OutputCache(PolicyName = "federation")]
|
||||||
[OverrideResultType<ASOrderedCollection>]
|
[OverrideResultType<ASOrderedCollection>]
|
||||||
[ProducesResults(HttpStatusCode.OK)]
|
[ProducesResults(HttpStatusCode.OK)]
|
||||||
[ProducesErrors(HttpStatusCode.NotFound)]
|
[ProducesErrors(HttpStatusCode.NotFound)]
|
||||||
|
@ -159,6 +162,7 @@ public class ActivityPubController(
|
||||||
|
|
||||||
[HttpGet("/@{acct}")]
|
[HttpGet("/@{acct}")]
|
||||||
[AuthorizedFetch]
|
[AuthorizedFetch]
|
||||||
|
[OutputCache(PolicyName = "federation")]
|
||||||
[MediaTypeRouteFilter("application/activity+json", "application/ld+json")]
|
[MediaTypeRouteFilter("application/activity+json", "application/ld+json")]
|
||||||
[OverrideResultType<ASActor>]
|
[OverrideResultType<ASActor>]
|
||||||
[ProducesResults(HttpStatusCode.OK, HttpStatusCode.MovedPermanently)]
|
[ProducesResults(HttpStatusCode.OK, HttpStatusCode.MovedPermanently)]
|
||||||
|
@ -212,6 +216,7 @@ public class ActivityPubController(
|
||||||
|
|
||||||
[HttpGet("/emoji/{name}")]
|
[HttpGet("/emoji/{name}")]
|
||||||
[AuthorizedFetch]
|
[AuthorizedFetch]
|
||||||
|
[OutputCache(PolicyName = "federation")]
|
||||||
[MediaTypeRouteFilter("application/activity+json", "application/ld+json")]
|
[MediaTypeRouteFilter("application/activity+json", "application/ld+json")]
|
||||||
[OverrideResultType<ASEmoji>]
|
[OverrideResultType<ASEmoji>]
|
||||||
[ProducesResults(HttpStatusCode.OK)]
|
[ProducesResults(HttpStatusCode.OK)]
|
||||||
|
|
|
@ -9,6 +9,7 @@ using Iceshrimp.Backend.Core.Federation.WebFinger;
|
||||||
using Iceshrimp.Backend.Core.Middleware;
|
using Iceshrimp.Backend.Core.Middleware;
|
||||||
using Microsoft.AspNetCore.Cors;
|
using Microsoft.AspNetCore.Cors;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.OutputCaching;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@ namespace Iceshrimp.Backend.Controllers.Federation;
|
||||||
[FederationApiController]
|
[FederationApiController]
|
||||||
[Route("/.well-known")]
|
[Route("/.well-known")]
|
||||||
[EnableCors("well-known")]
|
[EnableCors("well-known")]
|
||||||
|
[OutputCache(PolicyName = "federation")]
|
||||||
public class WellKnownController(IOptions<Config.InstanceSection> config, DatabaseContext db) : ControllerBase
|
public class WellKnownController(IOptions<Config.InstanceSection> config, DatabaseContext db) : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet("webfinger")]
|
[HttpGet("webfinger")]
|
||||||
|
|
|
@ -374,10 +374,22 @@ public static class ServiceExtensions
|
||||||
options.AddScheme<IAuthenticationHandler>("StubAuthenticationHandler", null);
|
options.AddScheme<IAuthenticationHandler>("StubAuthenticationHandler", null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void AddOutputCacheWithOptions(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddOutputCache(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("conditional", o => o.With(ctx => ctx.HttpContext.ShouldCacheOutput()));
|
||||||
|
options.AddPolicy("federation", o => o.SetVaryByHeader("Accept").Expire(TimeSpan.FromSeconds(60)));
|
||||||
|
options.DefaultExpirationTimeSpan = TimeSpan.FromDays(365);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class HttpContextExtensions
|
public static partial class HttpContextExtensions
|
||||||
{
|
{
|
||||||
|
private const string CacheKey = "shouldCache";
|
||||||
|
|
||||||
public static string GetRateLimitPartition(this HttpContext ctx, bool includeRoute) =>
|
public static string GetRateLimitPartition(this HttpContext ctx, bool includeRoute) =>
|
||||||
(includeRoute ? ctx.Request.Path.ToString() + "#" : "") + (GetRateLimitPartitionInternal(ctx) ?? "");
|
(includeRoute ? ctx.Request.Path.ToString() + "#" : "") + (GetRateLimitPartitionInternal(ctx) ?? "");
|
||||||
|
|
||||||
|
@ -385,6 +397,11 @@ public static partial class HttpContextExtensions
|
||||||
ctx.GetUser()?.Id ??
|
ctx.GetUser()?.Id ??
|
||||||
ctx.Request.Headers["X-Forwarded-For"].FirstOrDefault() ??
|
ctx.Request.Headers["X-Forwarded-For"].FirstOrDefault() ??
|
||||||
ctx.Connection.RemoteIpAddress?.ToString();
|
ctx.Connection.RemoteIpAddress?.ToString();
|
||||||
|
|
||||||
|
public static void CacheOutput(this HttpContext ctx) => ctx.Items[CacheKey] = true;
|
||||||
|
|
||||||
|
public static bool ShouldCacheOutput(this HttpContext ctx) =>
|
||||||
|
ctx.Items.TryGetValue(CacheKey, out var s) && s is true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region AsyncDataProtection handlers
|
#region AsyncDataProtection handlers
|
||||||
|
|
|
@ -24,6 +24,7 @@ builder.Services
|
||||||
.AddPlugins(PluginLoader.Assemblies);
|
.AddPlugins(PluginLoader.Assemblies);
|
||||||
|
|
||||||
builder.Services.AddSwaggerGenWithOptions();
|
builder.Services.AddSwaggerGenWithOptions();
|
||||||
|
builder.Services.AddOutputCacheWithOptions();
|
||||||
builder.Services.AddLogging(logging => logging.AddCustomConsoleFormatter());
|
builder.Services.AddLogging(logging => logging.AddCustomConsoleFormatter());
|
||||||
builder.Services.AddDatabaseContext(builder.Configuration);
|
builder.Services.AddDatabaseContext(builder.Configuration);
|
||||||
builder.Services.AddSlidingWindowRateLimiter();
|
builder.Services.AddSlidingWindowRateLimiter();
|
||||||
|
@ -38,6 +39,7 @@ builder.Services.AddAntiforgery(o => o.Cookie.Name = "CSRF-Token");
|
||||||
|
|
||||||
builder.Services.AddServices(builder.Configuration);
|
builder.Services.AddServices(builder.Configuration);
|
||||||
builder.Services.ConfigureServices(builder.Configuration);
|
builder.Services.ConfigureServices(builder.Configuration);
|
||||||
|
|
||||||
builder.WebHost.ConfigureKestrel(builder.Configuration);
|
builder.WebHost.ConfigureKestrel(builder.Configuration);
|
||||||
builder.WebHost.UseStaticWebAssets();
|
builder.WebHost.UseStaticWebAssets();
|
||||||
|
|
||||||
|
@ -64,6 +66,7 @@ app.UseAuthorization();
|
||||||
app.UseWebSockets(new WebSocketOptions { KeepAliveInterval = TimeSpan.FromSeconds(30) });
|
app.UseWebSockets(new WebSocketOptions { KeepAliveInterval = TimeSpan.FromSeconds(30) });
|
||||||
app.UseCustomMiddleware();
|
app.UseCustomMiddleware();
|
||||||
app.UseAntiforgery();
|
app.UseAntiforgery();
|
||||||
|
app.UseOutputCache();
|
||||||
|
|
||||||
app.MapStaticAssetsWithTransparentDecompression();
|
app.MapStaticAssetsWithTransparentDecompression();
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|
Loading…
Add table
Reference in a new issue