Skip to content

Commit

Permalink
Merge pull request #177 from PhyxionNL/file
Browse files Browse the repository at this point in the history
Check for invalid characters
  • Loading branch information
Shazwazza committed Feb 17, 2023
2 parents 6f9891b + 456314b commit 9510e0f
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 53 deletions.
3 changes: 1 addition & 2 deletions src/Smidge.Core/Cache/PhysicalFileCacheFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ public IFileInfo GetRequiredFileInfo(string filePath)
return fileInfo;
}

private string GetCompositeFilePath(string cacheBusterValue, CompressionType type, string filesetKey)
=> $"{cacheBusterValue}/{type}/{filesetKey + ".s"}";
private string GetCompositeFilePath(string cacheBusterValue, CompressionType type, string filesetKey) => $"{cacheBusterValue}/{type}/{filesetKey}.s";

public Task ClearCachedCompositeFileAsync(string cacheBusterValue, CompressionType type, string filesetKey)
{
Expand Down
16 changes: 9 additions & 7 deletions src/Smidge.Core/CompositeFiles/Compressor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.IO.Compression;
using System.Text;
Expand All @@ -10,24 +10,26 @@ namespace Smidge.CompositeFiles
/// Performs byte compression
/// </summary>
public static class Compressor
{
public static async Task<Stream> CompressAsync(CompressionType type, Stream original)
{
public static async Task<Stream> CompressAsync(CompressionType type, Stream original) => await CompressAsync(type, CompressionLevel.Optimal, original);

public static async Task<Stream> CompressAsync(CompressionType type, CompressionLevel level, Stream original)
{
using (var ms = new MemoryStream())
{
Stream compressedStream = null;

if (type == CompressionType.Deflate)
{
compressedStream = new DeflateStream(ms, CompressionLevel.Optimal);
compressedStream = new DeflateStream(ms, level);
}
else if (type == CompressionType.GZip)
{
compressedStream = new GZipStream(ms, CompressionLevel.Optimal);
compressedStream = new GZipStream(ms, level);
}
else if (type == CompressionType.Brotli)
{
compressedStream = new BrotliStream(ms, CompressionLevel.Optimal);
compressedStream = new BrotliStream(ms, level);
}

if (type != CompressionType.None)
Expand All @@ -50,4 +52,4 @@ public static async Task<Stream> CompressAsync(CompressionType type, Stream orig
}
}
}
}
}
47 changes: 23 additions & 24 deletions src/Smidge.Core/CompositeFiles/DefaultUrlManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ namespace Smidge.CompositeFiles
public class DefaultUrlManager : IUrlManager
{
private readonly IHasher _hasher;
private readonly IRequestHelper _requestHelper;
private readonly bool _keepFileExtensions;
private readonly UrlManagerOptions _options;
private readonly ISmidgeConfig _config;
private readonly IRequestHelper _requestHelper;

public DefaultUrlManager(IOptions<SmidgeOptions> options, IHasher hasher, IRequestHelper requestHelper, ISmidgeConfig config)
{
_hasher = hasher;
_requestHelper = requestHelper;
_options = options.Value.UrlOptions;
_config = config;
_keepFileExtensions = config.KeepFileExtensions;
}

public string AppendCacheBuster(string url, bool debug, string cacheBusterValue)
Expand All @@ -42,16 +42,13 @@ public string GetUrl(string bundleName, string fileExtension, bool debug, string
throw new ArgumentException($"'{nameof(cacheBusterValue)}' cannot be null or whitespace.", nameof(cacheBusterValue));
}

string handler = _config.KeepFileExtensions ? "~/{0}/{1}.{3}{4}{2}" : "~/{0}/{1}{2}.{3}{4}";
return _requestHelper.Content(
string.Format(
handler,
_options.BundleFilePath,
Uri.EscapeUriString(bundleName),
fileExtension,
debug ? 'd' : 'v',
cacheBusterValue));

var handler = _keepFileExtensions ? "~/{0}/{1}.{3}{4}{2}" : "~/{0}/{1}{2}.{3}{4}";
return _requestHelper.Content(string.Format(handler,
_options.BundleFilePath,
Uri.EscapeUriString(bundleName),
fileExtension,
debug ? 'd' : 'v',
cacheBusterValue));
}

public IEnumerable<FileSetUrl> GetUrls(IEnumerable<IWebFile> dependencies, string fileExtension, string cacheBusterValue)
Expand All @@ -67,7 +64,7 @@ public IEnumerable<FileSetUrl> GetUrls(IEnumerable<IWebFile> dependencies, strin
var builderCount = 1;

var remaining = new Queue<IWebFile>(dependencies);
while (remaining.Any())
while (remaining.Count > 0)
{
var current = remaining.Peek();

Expand Down Expand Up @@ -137,23 +134,25 @@ public ParsedUrlPath ParsePath(string input)
}

//can start with 'v' or 'd' (d == debug)
var prefix = _config.KeepFileExtensions ? parts[parts.Length - 2][0] : parts[parts.Length - 1][0];
var prefix = _keepFileExtensions ? parts[parts.Length - 2][0] : parts[parts.Length - 1][0];
if (prefix != 'v' && prefix != 'd')
{
//invalid
return null;
}
result.Debug = prefix == 'd';

result.CacheBusterValue = _config.KeepFileExtensions ? parts[parts.Length - 2].Substring(1) : parts[parts.Length - 1].Substring(1);
var ext = _config.KeepFileExtensions ? parts[parts.Length - 1] : parts[parts.Length - 2];
if (!Enum.TryParse(ext, true, out WebFileType type))
{
//invalid
result.CacheBusterValue = _keepFileExtensions ? parts[parts.Length - 2].Substring(1) : parts[parts.Length - 1].Substring(1);
var ext = _keepFileExtensions ? parts[parts.Length - 1] : parts[parts.Length - 2];

WebFileType type;
if (ext.Equals("js", StringComparison.OrdinalIgnoreCase))
type = WebFileType.Js;
else if (ext.Equals("css", StringComparison.OrdinalIgnoreCase))
type = WebFileType.Css;
else
return null;
}
result.WebType = type;

result.WebType = type;
result.Names = parts.Take(parts.Length - 2);

return result;
Expand All @@ -163,7 +162,7 @@ private string GetCompositeUrl(string fileKey, string fileExtension, string cach
{
//Create a delimited URL query string

string handler = _config.KeepFileExtensions ? "~/{0}/{1}.v{3}{2}" : "~/{0}/{1}{2}.v{3}";
string handler = _keepFileExtensions ? "~/{0}/{1}.v{3}{2}" : "~/{0}/{1}{2}.v{3}";
return _requestHelper.Content(
string.Format(
handler,
Expand Down
12 changes: 7 additions & 5 deletions src/Smidge.Core/CompressionType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ public struct CompressionType : IEquatable<CompressionType>, IEquatable<string>

public static CompressionType Parse(string compressionType)
{
if (compressionType == Deflate) return Deflate;
if (compressionType == GZip) return GZip;
if (compressionType == "x-gzip") return GZip;
if (compressionType == Brotli) return Brotli;
return None;
if (compressionType == Brotli)
return Brotli;

if ((compressionType == GZip) || (compressionType == "x-gzip"))
return GZip;

return compressionType == Deflate ? Deflate : None;
}

public override string ToString() => _compressionType;
Expand Down
10 changes: 8 additions & 2 deletions src/Smidge.Core/FileProcessors/PreProcessManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class PreProcessManager : IPreProcessManager
private readonly IBundleManager _bundleManager;
private readonly ILogger<PreProcessManager> _logger;
private readonly SemaphoreSlim _processFileSemaphore = new SemaphoreSlim(1, 1);
private readonly char[] _invalidPathChars = Path.GetInvalidPathChars();

public PreProcessManager(ISmidgeFileSystem fileSystem, IBundleManager bundleManager, ILogger<PreProcessManager> logger)
{
Expand All @@ -43,7 +44,12 @@ private async Task ProcessFile(IWebFile file, BundleOptions bundleOptions, Bundl
if (file.FilePath.Contains(SmidgeConstants.SchemeDelimiter))
{
throw new InvalidOperationException("Cannot process an external file as part of a bundle");
};
}

if (file.FilePath.IndexOfAny(_invalidPathChars) != -1)
{
throw new InvalidOperationException("Cannot process paths with invalid chars");
}

await _processFileSemaphore.WaitAsync();

Expand All @@ -65,7 +71,7 @@ private async Task ProcessFileImpl(IWebFile file, BundleOptions bundleOptions, B

var extension = Path.GetExtension(file.FilePath);

var fileWatchEnabled = bundleOptions?.FileWatchOptions.Enabled ?? false;
var fileWatchEnabled = bundleOptions.FileWatchOptions.Enabled;

var cacheBusterValue = bundleContext.CacheBusterValue;

Expand Down
8 changes: 7 additions & 1 deletion src/Smidge.Core/Options/BundleOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.IO.Compression;
using Smidge.Cache;

namespace Smidge.Options
Expand All @@ -19,7 +20,7 @@ public BundleOptions()
CacheControlOptions = new CacheControlOptions();
ProcessAsCompositeFile = true;
CompressResult = true;

CompressionLevel = CompressionLevel.Optimal;
}

private Type _defaultCacheBuster;
Expand Down Expand Up @@ -80,6 +81,11 @@ public Type GetCacheBusterType()
/// </summary>
public bool CompressResult { get; set; }

/// <summary>
/// The compression level of the bundle
/// </summary>
public CompressionLevel CompressionLevel {get; set; }

/// <summary>
/// Used to control the caching of the bundle
/// </summary>
Expand Down
6 changes: 3 additions & 3 deletions src/Smidge/Controllers/CompositeFileCacheFilterAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Smidge.Models;
using System;
Expand Down Expand Up @@ -28,7 +28,6 @@ public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
internal static bool TryGetCachedCompositeFileResult(ISmidgeFileSystem fileSystem, string cacheBusterValue, string filesetKey, CompressionType type, string mime, out FileResult result, out DateTime lastWriteTime)
{
result = null;
lastWriteTime = DateTime.Now;

var cacheFile = fileSystem.CacheFileSystem.GetCachedCompositeFile(cacheBusterValue, type, filesetKey, out _);
if (cacheFile.Exists)
Expand All @@ -48,6 +47,7 @@ internal static bool TryGetCachedCompositeFileResult(ISmidgeFileSystem fileSyste
return true;
}

lastWriteTime = DateTime.Now;
return false;
}

Expand Down Expand Up @@ -84,4 +84,4 @@ public void OnActionExecuted(ActionExecutedContext context)
{ }
}
}
}
}
12 changes: 6 additions & 6 deletions src/Smidge/Controllers/SmidgeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.FileProviders;
Expand Down Expand Up @@ -133,10 +134,10 @@ public class SmidgeController : Controller
using (var resultStream = await GetCombinedStreamAsync(fileInfos, bundleContext))
{
//compress the response (if enabled)
var compressedStream = await Compressor.CompressAsync(
//do not compress anything if it's not enabled in the bundle options
bundleOptions.CompressResult ? bundleModel.Compression : CompressionType.None,
resultStream);
//do not compress anything if it's not enabled in the bundle options
var compressedStream = await Compressor.CompressAsync(bundleOptions.CompressResult ? bundleModel.Compression : CompressionType.None,
bundleOptions.CompressionLevel,
resultStream);

//save the resulting compressed file, if compression is not enabled it will just save the non compressed format
// this persisted file will be used in the CheckNotModifiedAttribute which will short circuit the request and return
Expand Down Expand Up @@ -164,7 +165,6 @@ public class SmidgeController : Controller
return NotFound();
}

var defaultBundleOptions = _bundleManager.GetDefaultBundleOptions(false);
var cacheBusterValue = file.ParsedPath.CacheBusterValue;

var cacheFile = _fileSystem.CacheFileSystem.GetCachedCompositeFile(cacheBusterValue, file.Compression, file.FileKey, out var cacheFilePath);
Expand Down Expand Up @@ -241,4 +241,4 @@ private async Task<Stream> GetCombinedStreamAsync(IEnumerable<IFileInfo> files,
}
}
}
}
}
2 changes: 1 addition & 1 deletion src/Smidge/Models/RequestModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ protected RequestModel(string valueName, IUrlManager urlManager, IActionContextA
if (requestHelper is null)throw new ArgumentNullException(nameof(requestHelper));

//default
LastFileWriteTime = DateTime.Now;
LastFileWriteTime = DateTime.MinValue;

Compression = requestHelper.GetClientCompression(accessor.ActionContext.HttpContext.Request.Headers);

Expand Down
4 changes: 2 additions & 2 deletions src/Smidge/RequestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public string Content(IWebFile file)
if (file.FilePath.StartsWith("//"))
{
var scheme = _siteInfo.GetBaseUrl().Scheme;
return Regex.Replace(file.FilePath, @"^\/\/", string.Format("{0}{1}", scheme, SmidgeConstants.SchemeDelimiter));
return Regex.Replace(file.FilePath, @"^\/\/", scheme + SmidgeConstants.SchemeDelimiter);
}

var filePath = Content(file.FilePath);
Expand Down Expand Up @@ -71,7 +71,7 @@ public string Content(string path)
if (path.StartsWith("//"))
{
var scheme = _siteInfo.GetBaseUrl().Scheme;
return Regex.Replace(path, @"^\/\/", string.Format("{0}{1}", scheme, SmidgeConstants.SchemeDelimiter));
return Regex.Replace(path, @"^\/\/", scheme + SmidgeConstants.SchemeDelimiter);
}

//This code is taken from the UrlHelper code ... which shouldn't need to be tucked away in there
Expand Down

0 comments on commit 9510e0f

Please sign in to comment.