Skip to content

Commit 3626616

Browse files
Merge pull request #246 from SixLabors/js/file-system-fixes
PhysicalFileSystem optimizations
2 parents b922f29 + dd3af49 commit 3626616

10 files changed

Lines changed: 59 additions & 124 deletions

src/Directory.Build.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,6 @@
3131
<PackageReference Update="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" />
3232
<PackageReference Update="Microsoft.Extensions.Caching.Abstractions" Version="2.2.0" />
3333
<PackageReference Update="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.2.0" />
34+
<PackageReference Update="Microsoft.Extensions.FileProviders.Physical" Version="2.2.0"/>
3435
</ItemGroup>
3536
</Project>

src/ImageSharp.Web/Caching/PhysicalFileSystemCache.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ internal static string GetCacheRoot(PhysicalFileSystemCacheOptions cacheOptions,
6767
string cacheRootPath = cacheOptions.CacheRootPath ?? webRootPath;
6868
if (string.IsNullOrEmpty(cacheRootPath))
6969
{
70-
throw new InvalidOperationException("The cache root path can't be determined, make sure it's explicitly configured or the webroot is set.");
70+
throw new InvalidOperationException("The cache root path cannot be determined, make sure it's explicitly configured or the webroot is set.");
7171
}
7272

7373
if (!Path.IsPathFullyQualified(cacheRootPath))

src/ImageSharp.Web/ImageCacheMetadata.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,11 @@ public static async Task<ImageCacheMetadata> ReadAsync(Stream stream)
156156
/// <inheritdoc/>
157157
[MethodImpl(MethodImplOptions.AggressiveInlining)]
158158
public bool Equals(ImageCacheMetadata other)
159-
{
160-
return this.SourceLastWriteTimeUtc == other.SourceLastWriteTimeUtc
161-
&& this.CacheLastWriteTimeUtc == other.CacheLastWriteTimeUtc
162-
&& this.ContentType == other.ContentType
163-
&& this.CacheControlMaxAge == other.CacheControlMaxAge
164-
&& this.ContentLength == other.ContentLength;
165-
}
159+
=> this.SourceLastWriteTimeUtc == other.SourceLastWriteTimeUtc
160+
&& this.CacheLastWriteTimeUtc == other.CacheLastWriteTimeUtc
161+
&& this.ContentType == other.ContentType
162+
&& this.CacheControlMaxAge == other.CacheControlMaxAge
163+
&& this.ContentLength == other.ContentLength;
166164

167165
/// <inheritdoc/>
168166
public override bool Equals(object obj)
@@ -181,16 +179,14 @@ public override int GetHashCode() => HashCode.Combine(
181179
/// </summary>
182180
/// <returns>The <see cref="Dictionary{String, String}"/>.</returns>
183181
public Dictionary<string, string> ToDictionary()
184-
{
185-
return new Dictionary<string, string>
182+
=> new()
186183
{
187184
{ SourceLastModifiedKey, this.SourceLastWriteTimeUtc.ToString("o") },
188185
{ CacheLastModifiedKey, this.CacheLastWriteTimeUtc.ToString("o") },
189186
{ ContentTypeKey, this.ContentType },
190187
{ CacheControlKey, this.CacheControlMaxAge.TotalSeconds.ToString(NumberFormatInfo.InvariantInfo) },
191188
{ ContentLengthKey, this.ContentLength.ToString(NumberFormatInfo.InvariantInfo) }
192189
};
193-
}
194190

195191
/// <inheritdoc/>
196192
public override string ToString()

src/ImageSharp.Web/ImageSharp.Web.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<AssemblyTitle>SixLabors.ImageSharp.Web</AssemblyTitle>
@@ -41,6 +41,7 @@
4141
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" />
4242
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" />
4343
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
44+
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" />
4445
</ItemGroup>
4546

4647
<ItemGroup>

src/ImageSharp.Web/Providers/FileProviderImageProvider.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Web.Providers
1313
/// <summary>
1414
/// Returns images from an <see cref="IFileProvider"/> abstraction.
1515
/// </summary>
16-
public class FileProviderImageProvider : IImageProvider
16+
public abstract class FileProviderImageProvider : IImageProvider
1717
{
1818
/// <summary>
1919
/// The file provider abstraction.
@@ -29,21 +29,26 @@ public class FileProviderImageProvider : IImageProvider
2929
/// Initializes a new instance of the <see cref="FileProviderImageProvider"/> class.
3030
/// </summary>
3131
/// <param name="fileProvider">The file provider.</param>
32+
/// <param name="processingBehavior">The processing behavior.</param>
3233
/// <param name="formatUtilities">Contains various format helper methods based on the current configuration.</param>
33-
public FileProviderImageProvider(IFileProvider fileProvider, FormatUtilities formatUtilities)
34+
protected FileProviderImageProvider(IFileProvider fileProvider, ProcessingBehavior processingBehavior, FormatUtilities formatUtilities)
3435
{
35-
this.fileProvider = fileProvider ?? throw new ArgumentNullException(nameof(fileProvider));
36-
this.formatUtilities = formatUtilities ?? throw new ArgumentNullException(nameof(formatUtilities));
36+
Guard.NotNull(fileProvider, nameof(fileProvider));
37+
Guard.NotNull(formatUtilities, nameof(formatUtilities));
38+
39+
this.fileProvider = fileProvider;
40+
this.formatUtilities = formatUtilities;
41+
this.ProcessingBehavior = processingBehavior;
3742
}
3843

3944
/// <inheritdoc/>
40-
public ProcessingBehavior ProcessingBehavior { get; protected set; } = ProcessingBehavior.CommandOnly;
45+
public ProcessingBehavior ProcessingBehavior { get; }
4146

4247
/// <inheritdoc/>
43-
public Func<HttpContext, bool> Match { get; set; } = _ => true;
48+
public virtual Func<HttpContext, bool> Match { get; set; } = _ => true;
4449

4550
/// <inheritdoc/>
46-
public bool IsValidRequest(HttpContext context)
51+
public virtual bool IsValidRequest(HttpContext context)
4752
=> this.formatUtilities.TryGetExtensionFromUri(context.Request.GetDisplayUrl(), out _);
4853

4954
/// <inheritdoc/>

src/ImageSharp.Web/Providers/PhysicalFileSystemProvider.cs

Lines changed: 20 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,17 @@
33

44
using System;
55
using System.IO;
6-
using System.Threading.Tasks;
76
using Microsoft.AspNetCore.Hosting;
8-
using Microsoft.AspNetCore.Http;
9-
using Microsoft.AspNetCore.Http.Extensions;
7+
using Microsoft.Extensions.FileProviders;
108
using Microsoft.Extensions.Options;
11-
using SixLabors.ImageSharp.Web.Resolvers;
129

1310
namespace SixLabors.ImageSharp.Web.Providers
1411
{
1512
/// <summary>
1613
/// Returns images stored in the local physical file system.
1714
/// </summary>
18-
public class PhysicalFileSystemProvider : IImageProvider
15+
public sealed class PhysicalFileSystemProvider : FileProviderImageProvider
1916
{
20-
/// <summary>
21-
/// The root path for the provider.
22-
/// </summary>
23-
private readonly string providerRootPath;
24-
25-
/// <summary>
26-
/// Contains various format helper methods based on the current configuration.
27-
/// </summary>
28-
private readonly FormatUtilities formatUtilities;
29-
3017
/// <summary>
3118
/// Initializes a new instance of the <see cref="PhysicalFileSystemProvider"/> class.
3219
/// </summary>
@@ -41,56 +28,23 @@ public PhysicalFileSystemProvider(
4128
IWebHostEnvironment environment,
4229
#endif
4330
FormatUtilities formatUtilities)
31+
: base(GetProvider(options, environment), options.Value.ProcessingBehavior, formatUtilities)
4432
{
45-
Guard.NotNull(options, nameof(options));
46-
Guard.NotNull(environment, nameof(environment));
47-
48-
this.providerRootPath = GetProviderRoot(options.Value, environment.WebRootPath, environment.ContentRootPath);
49-
this.formatUtilities = formatUtilities;
50-
}
51-
52-
/// <inheritdoc/>
53-
public ProcessingBehavior ProcessingBehavior { get; } = ProcessingBehavior.CommandOnly;
54-
55-
/// <inheritdoc/>
56-
public Func<HttpContext, bool> Match { get; set; } = _ => true;
57-
58-
/// <inheritdoc/>
59-
public bool IsValidRequest(HttpContext context)
60-
=> this.formatUtilities.TryGetExtensionFromUri(context.Request.GetDisplayUrl(), out _);
61-
62-
/// <inheritdoc/>
63-
public Task<IImageResolver> GetAsync(HttpContext context)
64-
{
65-
// Use Join because request path starts with a slash
66-
string fullPath = Path.GetFullPath(Path.Join(this.providerRootPath, context.Request.Path.Value));
67-
if (PathUtilities.IsUnderneathRoot(fullPath, this.providerRootPath))
68-
{
69-
// Check to see if the file exists
70-
var fileInfo = new FileInfo(fullPath);
71-
if (fileInfo.Exists)
72-
{
73-
var metadata = new ImageMetadata(fileInfo.LastWriteTimeUtc, fileInfo.Length);
74-
return Task.FromResult<IImageResolver>(new PhysicalFileSystemResolver(fileInfo, metadata));
75-
}
76-
}
77-
78-
return Task.FromResult<IImageResolver>(null);
7933
}
8034

8135
/// <summary>
8236
/// Determine the provider root path
8337
/// </summary>
84-
/// <param name="providerOptions">The provider options.</param>
38+
/// <param name="options">The provider options.</param>
8539
/// <param name="webRootPath">The web root path.</param>
8640
/// <param name="contentRootPath">The content root path.</param>
8741
/// <returns><see cref="string"/> representing the fully qualified provider root path.</returns>
88-
internal static string GetProviderRoot(PhysicalFileSystemProviderOptions providerOptions, string webRootPath, string contentRootPath)
42+
internal static string GetProviderRoot(PhysicalFileSystemProviderOptions options, string webRootPath, string contentRootPath)
8943
{
90-
string providerRootPath = providerOptions.ProviderRootPath ?? webRootPath;
44+
string providerRootPath = options.ProviderRootPath ?? webRootPath;
9145
if (string.IsNullOrEmpty(providerRootPath))
9246
{
93-
throw new InvalidOperationException("The provider root path can't be determined, make sure it's explicitly configured or the webroot is set.");
47+
throw new InvalidOperationException("The provider root path cannot be determined, make sure it's explicitly configured or the webroot is set.");
9448
}
9549

9650
if (!Path.IsPathFullyQualified(providerRootPath))
@@ -101,5 +55,18 @@ internal static string GetProviderRoot(PhysicalFileSystemProviderOptions provide
10155

10256
return PathUtilities.EnsureTrailingSlash(providerRootPath);
10357
}
58+
59+
private static PhysicalFileProvider GetProvider(
60+
IOptions<PhysicalFileSystemProviderOptions> options,
61+
#if NETCOREAPP2_1
62+
IHostingEnvironment environment)
63+
#else
64+
IWebHostEnvironment environment)
65+
#endif
66+
{
67+
Guard.NotNull(options, nameof(options));
68+
Guard.NotNull(environment, nameof(environment));
69+
return new(GetProviderRoot(options.Value, environment.WebRootPath, environment.ContentRootPath));
70+
}
10471
}
10572
}

src/ImageSharp.Web/Providers/PhysicalFileSystemProviderOptions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,10 @@ public class PhysicalFileSystemProviderOptions
2121
/// </para>
2222
/// </summary>
2323
public string ProviderRootPath { get; set; }
24+
25+
/// <summary>
26+
/// Gets or sets the processing behavior. Defaults to <see cref="ProcessingBehavior.CommandOnly"/>.
27+
/// </summary>
28+
public ProcessingBehavior ProcessingBehavior { get; set; } = ProcessingBehavior.CommandOnly;
2429
}
2530
}

src/ImageSharp.Web/Providers/WebRootImageProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public WebRootImageProvider(
2222
IWebHostEnvironment environment,
2323
#endif
2424
FormatUtilities formatUtilities)
25-
: base(environment.WebRootFileProvider, formatUtilities)
25+
: base(environment.WebRootFileProvider, ProcessingBehavior.CommandOnly, formatUtilities)
2626
{
2727
}
2828
}

src/ImageSharp.Web/Resolvers/PhysicalFileSystemCacheResolver.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0.
33

44
using System.IO;
5+
using System.Runtime.CompilerServices;
56
using System.Threading.Tasks;
67
using SixLabors.ImageSharp.Web.Caching;
78

@@ -32,8 +33,12 @@ public PhysicalFileSystemCacheResolver(FileInfo metaFileInfo, FormatUtilities fo
3233
/// <inheritdoc/>
3334
public async Task<ImageCacheMetadata> GetMetaDataAsync()
3435
{
35-
using Stream stream = OpenFileStream(this.metaFileInfo.FullName);
36-
this.metadata = await ImageCacheMetadata.ReadAsync(stream);
36+
if (this.metadata == default)
37+
{
38+
using FileStream stream = OpenFileStream(this.metaFileInfo.FullName);
39+
this.metadata = await ImageCacheMetadata.ReadAsync(stream);
40+
}
41+
3742
return this.metadata;
3843
}
3944

@@ -44,14 +49,15 @@ public Task<Stream> OpenReadAsync()
4449
this.metaFileInfo.FullName,
4550
this.formatUtilities.GetExtensionFromContentType(this.metadata.ContentType));
4651

47-
return Task.FromResult(OpenFileStream(path));
52+
return Task.FromResult<Stream>(OpenFileStream(path));
4853
}
4954

50-
private static Stream OpenFileStream(string path)
55+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
56+
private static FileStream OpenFileStream(string path)
5157
{
5258
// We are setting buffer size to 1 to prevent FileStream from allocating it's internal buffer
5359
// 0 causes constructor to throw
54-
int bufferSize = 1;
60+
const int bufferSize = 1;
5561
return new FileStream(
5662
path,
5763
FileMode.Open,

src/ImageSharp.Web/Resolvers/PhysicalFileSystemResolver.cs

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)