Fix #343 - Avoid going to disk when reading the form

This change tries to avoid looking up the TEMP directory for most reads of
the form data. We'll now only hit the disk when necessary.
This commit is contained in:
Ryan Nowak 2015-08-27 21:48:13 -07:00
parent 516a435ea5
commit 15687ab80a
2 changed files with 39 additions and 10 deletions

View File

@ -12,21 +12,30 @@ namespace Microsoft.AspNet.Http.Internal
{
internal const int DefaultBufferThreshold = 1024 * 30;
private readonly static Func<string> _getTempDirectory = () => TempDirectory;
private static string _tempDirectory;
public static string TempDirectory
{
get
{
// Look for folders in the following order.
var temp = Environment.GetEnvironmentVariable("ASPNET_TEMP") ?? // ASPNET_TEMP - User set temporary location.
Path.GetTempPath(); // Fall back.
if (!Directory.Exists(temp))
if (_tempDirectory == null)
{
// TODO: ???
throw new DirectoryNotFoundException(temp);
// Look for folders in the following order.
var temp = Environment.GetEnvironmentVariable("ASPNET_TEMP") ?? // ASPNET_TEMP - User set temporary location.
Path.GetTempPath(); // Fall back.
if (!Directory.Exists(temp))
{
// TODO: ???
throw new DirectoryNotFoundException(temp);
}
_tempDirectory = temp;
}
return temp;
return _tempDirectory;
}
}
@ -37,7 +46,7 @@ namespace Microsoft.AspNet.Http.Internal
{
// TODO: Register this buffer for disposal at the end of the request to ensure the temp file is deleted.
// Otherwise it won't get deleted until GC closes the stream.
request.Body = new FileBufferingReadStream(body, bufferThreshold, TempDirectory);
request.Body = new FileBufferingReadStream(body, bufferThreshold, _getTempDirectory);
}
return request;
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@ -18,7 +19,8 @@ namespace Microsoft.AspNet.WebUtilities
{
private readonly Stream _inner;
private readonly int _memoryThreshold;
private readonly string _tempFileDirectory;
private string _tempFileDirectory;
private readonly Func<string> _tempFileDirectoryAccessor;
private Stream _buffer = new MemoryStream(); // TODO: We could have a more efficiently expanding buffer stream.
private bool _inMemory = true;
@ -26,6 +28,17 @@ namespace Microsoft.AspNet.WebUtilities
private bool _disposed;
// TODO: allow for an optional buffer size limit to prevent filling hard disks. 1gb?
public FileBufferingReadStream(
[NotNull] Stream inner,
int memoryThreshold,
[NotNull] Func<string> tempFileDirectoryAccessor)
{
_inner = inner;
_memoryThreshold = memoryThreshold;
_tempFileDirectoryAccessor = tempFileDirectoryAccessor;
}
// TODO: allow for an optional buffer size limit to prevent filling hard disks. 1gb?
public FileBufferingReadStream([NotNull] Stream inner, int memoryThreshold, [NotNull] string tempFileDirectory)
{
@ -88,6 +101,13 @@ namespace Microsoft.AspNet.WebUtilities
private Stream CreateTempFile()
{
if (_tempFileDirectory == null)
{
Debug.Assert(_tempFileDirectoryAccessor != null);
_tempFileDirectory = _tempFileDirectoryAccessor();
Debug.Assert(_tempFileDirectory != null);
}
var fileName = Path.Combine(_tempFileDirectory, "ASPNET_" + Guid.NewGuid().ToString() + ".tmp");
return new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Delete, 1024 * 16,
FileOptions.Asynchronous | FileOptions.DeleteOnClose | FileOptions.SequentialScan);