Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,11 @@ private async Task GetFormFilesAsync(
continue;
}

if (file.Name.Equals(modelName, StringComparison.OrdinalIgnoreCase))
if (file.Name.Equals(modelName, StringComparison.OrdinalIgnoreCase) ||
(file.Name.Length >= modelName.Length + 2 &&

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(file.Name.Length >= modelName.Length + 2 &&
(file.Name.Length - 2 >= modelName.Length &&

to prevent potential overflow.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion.
I'm not currently seeing the problem the requested change solves.
Could you please share an example scenario where an overflow would occur?

file.Name.StartsWith(modelName, StringComparison.OrdinalIgnoreCase) &&
file.Name[modelName.Length] == '[' &&
file.Name[file.Name.Length - 1] == ']'))
{
postedFiles.Add(file);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,96 @@ public async Task FormFileModelBinder_ReturnsFailedResult_ForCollectionsItCannot
Assert.Null(bindingContext.Result.Model);
}

[Fact]
public async Task FormFileModelBinder_ExpectMultipleFiles_WithIndexBinding_BindSuccessful()
{
// Arrange
var formFiles = new FormFileCollection
{
GetMockFormFile("file[0]", "file1.txt"),
GetMockFormFile("file[1]", "file2.txt"),
};
var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles));
var bindingContext = GetBindingContext(typeof(IEnumerable<IFormFile>), httpContext);
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);

// Act
await binder.BindModelAsync(bindingContext);

// Assert
Assert.True(bindingContext.Result.IsModelSet);

var entry = bindingContext.ValidationState[bindingContext.Result.Model];
Assert.False(entry.SuppressValidation);
Assert.Equal("file", entry.Key);
Assert.Null(entry.Metadata);

var files = Assert.IsAssignableFrom<IList<IFormFile>>(bindingContext.Result.Model);
Assert.Equal(2, files.Count);
Assert.Equal("file1.txt", files[0].FileName);
Assert.Equal("file2.txt", files[1].FileName);
}

[Fact]
public async Task FormFileModelBinder_ExpectMultipleFiles_WithNamedIndexBinding_BindSuccessful()
{
// Arrange
var formFiles = new FormFileCollection
{
GetMockFormFile("file[foo]", "file1.txt"),
GetMockFormFile("file[bar]", "file2.txt"),
};
var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles));
var bindingContext = GetBindingContext(typeof(IEnumerable<IFormFile>), httpContext);
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);

// Act
await binder.BindModelAsync(bindingContext);

// Assert
Assert.True(bindingContext.Result.IsModelSet);

var entry = bindingContext.ValidationState[bindingContext.Result.Model];
Assert.False(entry.SuppressValidation);
Assert.Equal("file", entry.Key);
Assert.Null(entry.Metadata);

var files = Assert.IsAssignableFrom<IList<IFormFile>>(bindingContext.Result.Model);
Assert.Equal(2, files.Count);
Assert.Equal("file1.txt", files[0].FileName);
Assert.Equal("file2.txt", files[1].FileName);
}

[Fact]
public async Task FormFileModelBinder_ExpectMultipleFiles_WithEmptyBracketBinding_BindSuccessful()
{
// Arrange
var formFiles = new FormFileCollection
{
GetMockFormFile("file[]", "file1.txt"),
GetMockFormFile("file[]", "file2.txt"),
};
var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles));
var bindingContext = GetBindingContext(typeof(IEnumerable<IFormFile>), httpContext);
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);

// Act
await binder.BindModelAsync(bindingContext);

// Assert
Assert.True(bindingContext.Result.IsModelSet);

var entry = bindingContext.ValidationState[bindingContext.Result.Model];
Assert.False(entry.SuppressValidation);
Assert.Equal("file", entry.Key);
Assert.Null(entry.Metadata);

var files = Assert.IsAssignableFrom<IList<IFormFile>>(bindingContext.Result.Model);
Assert.Equal(2, files.Count);
Assert.Equal("file1.txt", files[0].FileName);
Assert.Equal("file2.txt", files[1].FileName);
}

private static DefaultModelBindingContext GetBindingContextForReadOnlyArray(HttpContext httpContext)
{
var metadataProvider = new TestModelMetadataProvider();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,26 @@ public async Task BindModelAsync_MultiDimensionalFormFile_WithArrayNotation()
Assert.True(modelBindingResult.IsModelSet);
var container = Assert.IsType<MultiDimensionalFormFileContainer>(modelBindingResult.Model);
Assert.NotNull(container.FormFiles);
Assert.Empty(container.FormFiles);
Assert.Equal(2, container.FormFiles.Length);

Assert.Single(container.FormFiles[0]);
Assert.Equal(2, container.FormFiles[1].Length);

Assert.Collection(
container.FormFiles,
item =>
{
Assert.Collection(
item,
file => Assert.Equal(data + 1, ReadFormFile(file)));
},
item =>
{
Assert.Collection(
item,
file => Assert.Equal(data + 2, ReadFormFile(file)),
file => Assert.Equal(data + 3, ReadFormFile(file)));
});
}

public class MultiDimensionalFormFileContainerLevel2
Expand Down
Loading