From fe3dfe627b266e34b84f634abc293b42d79b65ee Mon Sep 17 00:00:00 2001 From: Andrew Stanton-Nurse Date: Mon, 29 Apr 2019 11:25:26 -0700 Subject: [PATCH] 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 --- .../StaticFiles/src/HtmlDirectoryFormatter.cs | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) 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(@"