diff --git a/src/Middleware/StaticFiles/src/HtmlDirectoryFormatter.cs b/src/Middleware/StaticFiles/src/HtmlDirectoryFormatter.cs
index a5ac8e7ea1..e27624ec1c 100644
--- a/src/Middleware/StaticFiles/src/HtmlDirectoryFormatter.cs
+++ b/src/Middleware/StaticFiles/src/HtmlDirectoryFormatter.cs
@@ -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.IO;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.StaticFiles
throw new ArgumentNullException(nameof(encoder));
}
_htmlEncoder = encoder;
- }
+ }
///
/// Generates an HTML view for a directory.
@@ -81,8 +82,8 @@ namespace Microsoft.AspNetCore.StaticFiles
margin-top: 5px;
margin-bottom: 0px;}
#index {
- border-collapse: separate;
- border-spacing: 0;
+ border-collapse: separate;
+ border-spacing: 0;
margin: 0 0 20px; }
#index th {
vertical-align: bottom;
@@ -132,27 +133,66 @@ namespace Microsoft.AspNetCore.StaticFiles
foreach (var subdir in contents.Where(info => info.IsDirectory))
{
- builder.AppendFormat(@"
+ // Collect directory metadata in a try...catch in case the file is deleted while we're getting the data.
+ // The metadata is retrieved prior to calling AppendFormat so if it throws, we won't have written a row
+ // to the table.
+ try
+ {
+ builder.AppendFormat(@"
| {0}/ |
|
{1} |
",
- HtmlEncode(subdir.Name),
- HtmlEncode(subdir.LastModified.ToString(CultureInfo.CurrentCulture)));
+ HtmlEncode(subdir.Name),
+ HtmlEncode(subdir.LastModified.ToString(CultureInfo.CurrentCulture)));
+ }
+ catch (DirectoryNotFoundException)
+ {
+ // The physical DirectoryInfo class doesn't appear to throw for either
+ // of Name or LastWriteTimeUtc (which backs LastModified in the physical provider)
+ // if the directory doesn't exist. However, we don't know what other providers might do.
+
+ // Just skip this directory. It was deleted while we were enumerating.
+ }
+ catch (FileNotFoundException)
+ {
+ // The physical DirectoryInfo class doesn't appear to throw for either
+ // of Name or LastWriteTimeUtc (which backs LastModified in the physical provider)
+ // if the directory doesn't exist. However, we don't know what other providers might do.
+
+ // Just skip this directory. It was deleted while we were enumerating.
+ }
}
foreach (var file in contents.Where(info => !info.IsDirectory))
{
- builder.AppendFormat(@"
+ // Collect file metadata in a try...catch in case the file is deleted while we're getting the data.
+ // The metadata is retrieved prior to calling AppendFormat so if it throws, we won't have written a row
+ // to the table.
+ try
+ {
+ builder.AppendFormat(@"
| {0} |
{1} |
{2} |
",
- HtmlEncode(file.Name),
- HtmlEncode(file.Length.ToString("n0", CultureInfo.CurrentCulture)),
- HtmlEncode(file.LastModified.ToString(CultureInfo.CurrentCulture)));
+ HtmlEncode(file.Name),
+ HtmlEncode(file.Length.ToString("n0", CultureInfo.CurrentCulture)),
+ HtmlEncode(file.LastModified.ToString(CultureInfo.CurrentCulture)));
+ }
+ catch (DirectoryNotFoundException)
+ {
+ // There doesn't appear to be a case where DirectoryNotFound is thrown in the physical provider,
+ // but we don't know what other providers might do.
+
+ // Just skip this file. It was deleted while we were enumerating.
+ }
+ catch (FileNotFoundException)
+ {
+ // Just skip this file. It was deleted while we were enumerating.
+ }
}
builder.Append(@"