Be more defensive in HtmlDirectoryFormatter (#9755)

Fixes aspnet/AspNetCore-Internal#2245

Our tests were flaking out due to this possible race where the directory browser middleware enumerates the directory but a file is deleted while we're formatting the response. This change just catches the FNF/DNF exceptions and suppresses the file from the directory listing
This commit is contained in:
Andrew Stanton-Nurse 2019-04-29 11:25:26 -07:00 committed by GitHub
parent 49ae712294
commit fe3dfe627b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 50 additions and 10 deletions

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
@ -132,27 +133,66 @@ namespace Microsoft.AspNetCore.StaticFiles
foreach (var subdir in contents.Where(info => info.IsDirectory)) 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(@"
<tr class=""directory""> <tr class=""directory"">
<td class=""name""><a href=""./{0}/"">{0}/</a></td> <td class=""name""><a href=""./{0}/"">{0}/</a></td>
<td></td> <td></td>
<td class=""modified"">{1}</td> <td class=""modified"">{1}</td>
</tr>", </tr>",
HtmlEncode(subdir.Name), HtmlEncode(subdir.Name),
HtmlEncode(subdir.LastModified.ToString(CultureInfo.CurrentCulture))); 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)) 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(@"
<tr class=""file""> <tr class=""file"">
<td class=""name""><a href=""./{0}"">{0}</a></td> <td class=""name""><a href=""./{0}"">{0}</a></td>
<td class=""length"">{1}</td> <td class=""length"">{1}</td>
<td class=""modified"">{2}</td> <td class=""modified"">{2}</td>
</tr>", </tr>",
HtmlEncode(file.Name), HtmlEncode(file.Name),
HtmlEncode(file.Length.ToString("n0", CultureInfo.CurrentCulture)), HtmlEncode(file.Length.ToString("n0", CultureInfo.CurrentCulture)),
HtmlEncode(file.LastModified.ToString(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(@" builder.Append(@"