Skip to content

Commit

Permalink
Fix build errors; still working on tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lilith committed Feb 3, 2024
1 parent cadf929 commit 437deb5
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 46 deletions.
20 changes: 9 additions & 11 deletions src/Imageflow.Server/ImageflowMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ public class ImageflowMiddleware
private readonly ImageflowMiddlewareOptions options;
private readonly GlobalInfoProvider globalInfoProvider;
private readonly IImageServer<RequestStreamAdapter,ResponseStreamAdapter, HttpContext> imageServer;
private readonly Licensing licensing;
public ImageflowMiddleware(
RequestDelegate next,
IWebHostEnvironment env,
Expand All @@ -43,6 +42,7 @@ public ImageflowMiddleware(
IEnumerable<IBlobCacheProvider> blobCacheProviders,
ImageflowMiddlewareOptions options)
{

var retainedLogStore = retainedLogStores.FirstOrDefault() ?? new ReLogStore(new ReLogStoreOptions());
var loggerFactory = loggerFactories.FirstOrDefault() ?? new ReLoggerFactory(legacyLoggerFactory, retainedLogStore);
var logger = loggerFactory.CreateReLogger("ImageflowMiddleware");
Expand All @@ -52,15 +52,17 @@ public ImageflowMiddleware(

var container = new ImageServerContainer(serviceProvider);

licensing ?? new Licensing(LicenseManagerSingleton.GetOrCreateSingleton(
"imageflow_", new[] { env.ContentRootPath, Path.GetTempPath() }));
container.Register(licensing);
globalInfoProvider = new GlobalInfoProvider(container);
container.Register(globalInfoProvider);

var licensingOptions = new LicenseOptions()
{ CandidateCacheFolders = new[] { env.ContentRootPath, Path.GetTempPath() } };

container.Register(licensingOptions);
container.Register(env);
container.Register(logger);
container.Register(licensing);

globalInfoProvider = new GlobalInfoProvider(container);
container.Register(globalInfoProvider);


new MiddlewareOptionsServerBuilder(container, logger, retainedLogStore, options, env).PopulateServices();

Expand All @@ -70,9 +72,6 @@ public ImageflowMiddleware(
startDiag.Validate(logger);

imageServer = container.GetRequiredService<IImageServer<RequestStreamAdapter,ResponseStreamAdapter, HttpContext>>();
licensing.Initialize(this.options);
licensing.FireHeartbeat();
GlobalPerf.Singleton.SetInfoProviders(new List<IInfoProvider>(){globalInfoProvider});
}

private bool hasPopulatedHttpContextExample = false;
Expand All @@ -98,7 +97,6 @@ public async Task Invoke(HttpContext context)

if (await imageServer.TryHandleRequestAsync(requestAdapter, responseAdapter, context, context.RequestAborted))
{
licensing?.FireHeartbeat();
return; // We handled it
}
await next.Invoke(context);
Expand Down
10 changes: 9 additions & 1 deletion src/Imageflow.Server/Internal/GlobalInfoProvider.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Reflection;
using Imazen.Abstractions.DependencyInjection;
using Imazen.Common.Helpers;
using Imazen.Common.Instrumentation.Support;
using Imazen.Common.Instrumentation.Support.InfoAccumulators;
using Imazen.Routing.Helpers;
using Imazen.Routing.HttpAbstractions;
using Imazen.Routing.Serving;
using Microsoft.AspNetCore.Hosting;
Expand Down Expand Up @@ -67,7 +69,7 @@ public void Add(IInfoAccumulator query)
if (env?.ContentRootPath != null)
{
// ReSharper disable once StringLiteralTypo
q.Add("apppath_hash", Utilities.Sha256TruncatedBase64(env.ContentRootPath, 6));
q.Add("apppath_hash", Sha256TruncatedBase64(env.ContentRootPath, 6));
}

query.Add("imageflow",1);
Expand All @@ -86,5 +88,11 @@ public void Add(IInfoAccumulator query)
}

}

private static string Sha256TruncatedBase64(string input, int bytes)
{
var hash = System.Security.Cryptography.SHA256.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(input));
return EncodingUtils.ToBase64U(hash.Take(bytes).ToArray());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.ComponentModel;
using System.Globalization;
using System.Text;
using Imageflow.Bindings;
Expand Down Expand Up @@ -226,7 +227,6 @@ private RoutingBuilder CreateRoutes(RoutingBuilder builder, IReadOnlyCollection<
builder.AddGlobalEndpoint(Conditions.HasPathSuffix("/imageflow.ready"),
(_) =>
{
options.Licensing?.FireHeartbeat();
using (new JobContext())
{
return SmallHttpResponse.NoStore(200, "Imageflow.Server is ready to accept requests.");
Expand All @@ -236,18 +236,17 @@ private RoutingBuilder CreateRoutes(RoutingBuilder builder, IReadOnlyCollection<
builder.AddGlobalEndpoint(Conditions.HasPathSuffix("/imageflow.health"),
(_) =>
{
options.Licensing?.FireHeartbeat();
return SmallHttpResponse.NoStore(200, "Imageflow.Server is healthy.");
});

builder.AddGlobalEndpoint(Conditions.HasPathSuffix("/imageflow.license"),
(req) =>
{
options.Licensing?.FireHeartbeat();
var s = new StringBuilder(8096);
var now = DateTime.UtcNow.ToString(NumberFormatInfo.InvariantInfo);
s.AppendLine($"License page for Imageflow at {req.OriginatingRequest?.GetHost().Value} generated {now} UTC");
s.Append(options.Licensing?.GetLicensePageContents());
var licenser = serverContainer.GetRequiredService<ILicenseChecker>();
s.Append(licenser.GetLicensePageContents());
return SmallHttpResponse.NoStoreNoRobots((200, s.ToString()));
});

Expand Down
27 changes: 16 additions & 11 deletions src/Imazen.Routing/Layers/Licensing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@

namespace Imageflow.Server
{
internal class LicenseOptions{
public class LicenseOptions{
internal string LicenseKey { get; set; } = "";
internal string MyOpenSourceProjectUrl { get; set; } = "";

internal string KeyPrifx { get; set; } = "imageflow_";
public required string[] CandidateCacheFolders { get; set; }
internal EnforceLicenseWith EnforcementMethod { get; set; } = EnforceLicenseWith.RedDotWatermark;

}
Expand All @@ -26,7 +28,7 @@ internal Licensing(LicenseManagerSingleton mgr, Func<Uri>? getCurrentRequestUrl
this.getCurrentRequestUrl = getCurrentRequestUrl;
}
private LicenseOptions? options;
internal void Initialize(LicenseOptions licenseOptions)
public void Initialize(LicenseOptions licenseOptions)
{
options = licenseOptions;
mgr.MonitorLicenses(this);
Expand All @@ -44,8 +46,8 @@ internal void Initialize(LicenseOptions licenseOptions)

private bool EnforcementEnabled()
{
return !string.IsNullOrEmpty(options.LicenseKey)
|| string.IsNullOrEmpty(options.MyOpenSourceProjectUrl);
return options != null && (!string.IsNullOrEmpty(options.LicenseKey)
|| string.IsNullOrEmpty(options.MyOpenSourceProjectUrl));
}
public IEnumerable<KeyValuePair<string, string>> GetDomainMappings()
{
Expand All @@ -59,7 +61,7 @@ public IReadOnlyCollection<IReadOnlyCollection<string>> GetFeaturesUsed()

public IEnumerable<string> GetLicenses()
{
return !string.IsNullOrEmpty(options?.LicenseKey) ? Enumerable.Repeat(options.LicenseKey, 1) : Enumerable.Empty<string>();
return !string.IsNullOrEmpty(options?.LicenseKey) ? Enumerable.Repeat(options!.LicenseKey, 1) : Enumerable.Empty<string>();
}

public LicenseAccess LicenseScope => LicenseAccess.Local;
Expand All @@ -68,6 +70,9 @@ public LicenseErrorAction LicenseEnforcement
{
get
{
if (options == null) {
return LicenseErrorAction.Http422;
}
return options.EnforcementMethod switch
{
EnforceLicenseWith.RedDotWatermark => LicenseErrorAction.Watermark,
Expand All @@ -82,13 +87,13 @@ public string EnforcementMethodMessage
{
get
{
return options.EnforcementMethod switch
return LicenseEnforcement switch
{
EnforceLicenseWith.RedDotWatermark =>
LicenseErrorAction.Watermark =>
"You are using EnforceLicenseWith.RedDotWatermark. If there is a licensing error, an red dot will be drawn on the bottom-right corner of each image. This can be set to EnforceLicenseWith.Http402Error instead (valuable if you are externally caching or storing result images.)",
EnforceLicenseWith.Http422Error =>
LicenseErrorAction.Http422 =>
"You are using EnforceLicenseWith.Http422Error. If there is a licensing error, HTTP status code 422 will be returned instead of serving the image. This can also be set to EnforceLicenseWith.RedDotWatermark.",
EnforceLicenseWith.Http402Error =>
LicenseErrorAction.Http402 =>
"You are using EnforceLicenseWith.Http402Error. If there is a licensing error, HTTP status code 402 will be returned instead of serving the image. This can also be set to EnforceLicenseWith.RedDotWatermark.",
_ => throw new ArgumentOutOfRangeException()
};
Expand All @@ -108,10 +113,10 @@ public string AgplCompliantMessage
{
get
{
if (!string.IsNullOrWhiteSpace(options.MyOpenSourceProjectUrl))
if (!string.IsNullOrWhiteSpace(options?.MyOpenSourceProjectUrl))
{
return "You have certified that you are complying with the AGPLv3 and have open-sourced your project at the following url:\r\n"
+ options.MyOpenSourceProjectUrl;
+ options!.MyOpenSourceProjectUrl;
}
else
{
Expand Down
10 changes: 6 additions & 4 deletions src/Imazen.Routing/Matching/MatchExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -672,18 +672,20 @@ public bool TryMatch(ReadOnlySpan<char> text, out int start, out int end)
}
return false;
case When.AtString or When.EqualsOrdinal:
if (text.StartsWith(Chars.AsSpan(), StringComparison.Ordinal))
var charSpan = Chars.AsSpan();
if (text.StartsWith(charSpan, StringComparison.Ordinal))
{
start = 0;
end = Chars.Length;
end = charSpan.Length;
return true;
}
return true;
case When.AtStringIgnoreCase or When.EqualsOrdinalIgnoreCase:
if (text.StartsWith(Chars.AsSpan(), StringComparison.OrdinalIgnoreCase))
var charSpan2 = Chars.AsSpan();
if (text.StartsWith(charSpan2, StringComparison.OrdinalIgnoreCase))
{
start = 0;
end = Chars.Length;
end = charSpan2.Length;
return true;
}
return true;
Expand Down
4 changes: 4 additions & 0 deletions src/Imazen.Routing/Serving/ILicenseChecker.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Imageflow.Server;
using Imazen.Routing.HttpAbstractions;

namespace Imazen.Routing.Serving;
Expand All @@ -7,4 +8,7 @@ public interface ILicenseChecker
bool RequestNeedsEnforcementAction(IHttpRequestStreamAdapter request);

string InvalidLicenseMessage { get; }
string GetLicensePageContents();
void FireHeartbeat();
void Initialize(LicenseOptions licenseOptions);
}
20 changes: 18 additions & 2 deletions src/Imazen.Routing/Serving/ImageServer.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
using System.Text;
using Imageflow.Server;
using Imazen.Abstractions.BlobCache;
using Imazen.Abstractions.Blobs;
using Imazen.Abstractions.Blobs.LegacyProviders;
using Imazen.Abstractions.DependencyInjection;
using Imazen.Abstractions.Logging;
using Imazen.Abstractions.Resulting;
using Imazen.Common.Concurrency.BoundedTaskCollection;
using Imazen.Common.Instrumentation;
using Imazen.Common.Instrumentation.Support.InfoAccumulators;
using Imazen.Common.Licensing;
using Imazen.Routing.Caching;
using Imazen.Routing.Engine;
using Imazen.Routing.Helpers;
Expand Down Expand Up @@ -33,7 +37,7 @@ internal class ImageServer<TRequest, TResponse, TContext> : IImageServer<TReques
private readonly bool shutdownRegisteredServices;
private readonly IImageServerContainer container;
public ImageServer(IImageServerContainer container,
ILicenseChecker licenseChecker,
LicenseOptions licenseOptions,
RoutingEngine routingEngine,
IPerformanceTracker perfTracker,
IReLogger logger,
Expand All @@ -42,9 +46,20 @@ public ImageServer(IImageServerContainer container,
this.shutdownRegisteredServices = shutdownRegisteredServices;
perf = perfTracker;
this.container = container;
this.licenseChecker = licenseChecker;
this.logger = logger.WithSubcategory("ImageServer");
this.routingEngine = routingEngine;

licenseChecker = container.GetService<ILicenseChecker>() ??
new Licensing(LicenseManagerSingleton.GetOrCreateSingleton(
licenseOptions.KeyPrifx, licenseOptions.CandidateCacheFolders), null);
licenseChecker.Initialize(licenseOptions);

licenseChecker.FireHeartbeat();
var infoProviders = container.GetService<IEnumerable<IInfoProvider>>()?.ToList();
if (infoProviders != null)
GlobalPerf.Singleton.SetInfoProviders(infoProviders);


var blobFactory = new SimpleReusableBlobFactory();

// ensure routingengine is registered
Expand Down Expand Up @@ -131,6 +146,7 @@ private string CreateEtag(ICacheableBlobPromise promise)
}
public async ValueTask<bool> TryHandleRequestAsync(TRequest request, TResponse response, TContext context, CancellationToken cancellationToken = default)
{
licenseChecker?.FireHeartbeat(); // Perhaps limit this to imageflow-handled requests?
try
{

Expand Down
22 changes: 11 additions & 11 deletions tests/Imageflow.Server.Tests/TestLicensing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Imazen.Common.Tests.Licensing;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Xunit;
using Xunit.Abstractions;
Expand Down Expand Up @@ -43,9 +44,13 @@ string GetInfo(ILicenseConfig c, LicenseManagerSingleton mgr)
return sb.ToString();
}

internal Task<IHost> StartAsyncWithOptions(ImageflowMiddlewareOptions options)
internal Task<IHost> StartAsyncWithOptions(Licensing l, ImageflowMiddlewareOptions options)
{
var hostBuilder = new HostBuilder()
.ConfigureServices(services =>
{
services.AddSingleton(l);
})
.ConfigureWebHost(webHost =>
{
// Add TestServer
Expand All @@ -72,9 +77,8 @@ public async void TestNoLicense()
var licensing = new Licensing(mgr);


using var host = await StartAsyncWithOptions(new ImageflowMiddlewareOptions()
using var host = await StartAsyncWithOptions(licensing,new ImageflowMiddlewareOptions()
{
Licensing = licensing,
MyOpenSourceProjectUrl = null,
EnforcementMethod = EnforceLicenseWith.Http402Error
}
Expand Down Expand Up @@ -121,9 +125,8 @@ public async void TestAGPL()
var licensing = new Licensing(mgr);


using var host = await StartAsyncWithOptions(new ImageflowMiddlewareOptions()
using var host = await StartAsyncWithOptions(licensing,new ImageflowMiddlewareOptions()
{
Licensing = licensing,
MyOpenSourceProjectUrl = "https://github.com/username/project",
EnforcementMethod = EnforceLicenseWith.RedDotWatermark
}.MapPath("/", Path.Combine(contentRoot.PhysicalPath, "images")));
Expand Down Expand Up @@ -163,9 +166,8 @@ public async void TestDomainsLicense()
var url = new RequestUrlProvider();
var licensing = new Licensing(mgr, url.Get);

using var host = await StartAsyncWithOptions(new ImageflowMiddlewareOptions()
using var host = await StartAsyncWithOptions(licensing,new ImageflowMiddlewareOptions()
{
Licensing = licensing,
MyOpenSourceProjectUrl = null
}
.SetLicenseKey(EnforceLicenseWith.Http402Error,
Expand Down Expand Up @@ -233,9 +235,8 @@ public async void TestSiteLicense()
var url = new RequestUrlProvider();
var licensing = new Licensing(mgr, url.Get);

using var host = await StartAsyncWithOptions(new ImageflowMiddlewareOptions()
using var host = await StartAsyncWithOptions(licensing,new ImageflowMiddlewareOptions()
{
Licensing = licensing,
MyOpenSourceProjectUrl = null
}
.SetLicenseKey(EnforceLicenseWith.Http402Error,
Expand Down Expand Up @@ -309,9 +310,8 @@ public async void TestRevocations(string licenseSetName)
var licensing = new Licensing(mgr, url.Get);


using var host = await StartAsyncWithOptions(new ImageflowMiddlewareOptions()
using var host = await StartAsyncWithOptions(licensing, new ImageflowMiddlewareOptions()
{
Licensing = licensing,
MyOpenSourceProjectUrl = null
}
.SetLicenseKey(EnforceLicenseWith.Http402Error,
Expand Down
3 changes: 2 additions & 1 deletion tests/ImazenShared.Tests/Routing/Serving/ImageServerTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Imageflow.Server;
using Imazen.Abstractions.DependencyInjection;
using Imazen.Abstractions.Logging;
using Imazen.Routing.Promises.Pipelines.Watermarking;
Expand Down Expand Up @@ -42,7 +43,7 @@ ImageServerOptions imageServerOptions
{
return new ImageServer<MockRequestAdapter, MockResponseAdapter, TContext>(
container,
container.GetService<ILicenseChecker>(),
container.GetRequiredService<LicenseOptions>(),
routingEngine,
container.GetService<IPerformanceTracker>() ?? new NullPerformanceTracker(),
logger
Expand Down
Loading

0 comments on commit 437deb5

Please sign in to comment.