Skip to content

Conversation

@MackinnonBuck
Copy link
Member

@MackinnonBuck MackinnonBuck commented Aug 7, 2020

Summary

  • Migrated InputFile from https://github.com/SteveSandersonMS/BlazorInputFile to M.A.C.Web.Extensions
  • Removed dependency on third-party base64 encoding JS code.
  • Added IJSUnmarshalledRuntime to allow RemoteFileListEntryStream to make unmarshalled JS invocations without reflection.
  • Reimplemented RemoteFileListEntryStream to use System.IO.Pipelines.
  • Added E2E tests

Addresses #12205

@Pilchie Pilchie added the area-blazor Includes: Blazor, Razor Components label Aug 7, 2020
@MackinnonBuck MackinnonBuck marked this pull request as ready for review August 8, 2020 00:27
@MackinnonBuck MackinnonBuck requested review from a team and SteveSandersonMS as code owners August 8, 2020 00:27
@SteveSandersonMS
Copy link
Member

This looks really great, @MackinnonBuck! Let us know when you want another round of review.

// - Or, failing that, at least use something like System.IO.Pipelines to manage
// the supply/consumption of byte data with less custom code.

internal class RemoteFileListEntryStream : FileListEntryStream
Copy link
Member

Choose a reason for hiding this comment

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

@javiercn You spoke before about doing a security review on the new file upload feature. I don't know if you had something else in mind, but one thing that occurs to me is reviewing this kind of logic to see if we can see any way it could be misused to make the server allocate arbitrary amounts of memory, or to leak memory, to get into an infinite loop, or anything like that.

Do you think that's something we should do directly within this PR review, or schedule something separate (maybe with Levi giving it a look over)?

@SteveSandersonMS
Copy link
Member

Again, this looks great 👍

I see there are still a couple of API changes due (e.g., your OpenFileStream suggestion) and E2E test cases remaining so I'll hold off on marking as approved, but as far as I'm concerned all the big questions are answered now and the rest are just small details. Nice work!

/// <summary>
/// Represents the data of a file selected from an <see cref="InputFile"/> component.
/// </summary>
public interface IFileListEntry
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we call this IBrowserFile? The browser API is called File: https://developer.mozilla.org/en-US/docs/Web/API/File

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason we have an interface and implementation? Do we expect users to implement this contract?

Copy link
Member Author

Choose a reason for hiding this comment

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

I believe properties that can be deserialized from JSON must have public setters - correct me if I'm wrong on this. If that's the case, we probably don't need users to be able to tinker with the various properties, hence the internal FileListEntry and the public IFileListEntry that describes those properties as read-only.

Copy link
Member

Choose a reason for hiding this comment

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

IBrowserFile sounds fine to me. In most cases people won't see the type name in their code anyway since they will receive the InputFileChangeEventArgs then just iterate over its Files collection.

I believe properties that can be deserialized from JSON must have public setters - correct me if I'm wrong on this. If that's the case, we probably don't need users to be able to tinker with the various properties, hence the internal FileListEntry and the public IFileListEntry that describes those properties as read-only.

Yes, I agree. However if we wanted we could swap the "public interface, internal class" pair with a "public abstract class, internal concrete subclass" pair. That has the benefit of letting us add more members in the future non-breakingly.

Not a big deal though. Do either of you feel strongly either way?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not partial to keeping the interface - I'll go ahead and swap it for an abstract class.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually, @SteveSandersonMS, I just want to clarify my understanding of what you had in mind. Is the change to enable us to add more properties to IBrowserFile without forcing our customers to modify their own types implementing IBrowserFile? If so, wouldn't default interface implementations solve this? The challenge with turning IBrowserFile into an abstract class is that we can't define properties in the abstract class as read-only but define them in the internal class as read-write. There are workarounds of course, but that seemed messier to me than using default interface implementation.

@javiercn
Copy link
Member

@javiercn I believe the maximum file size scenario is covered already with a bit of custom user code. The user receives an IBrowserFile object which contains a Size property that they can look at before calling OpenReadStream

Yes, but do we stop reading after we reach the Size of the file in the implementation? So if I told you I had 1MB of data and tried to send you 2MB, would we stop at Size when we are pulling data from the stream within CopyToAsync?

@MackinnonBuck
Copy link
Member Author

@javiercn Ah, I see what you mean now - I'll add a check for this!

@javiercn
Copy link
Member

@javiercn Ah, I see what you mean now - I'll add a check for this!

Nevermind, I think it's already covered https://github.com/dotnet/aspnetcore/pull/24640/files#diff-288a225ef1a4f388d11bacb6bbb83334R49

Copy link
Contributor

@pranavkm pranavkm left a comment

Choose a reason for hiding this comment

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

Feel free to respond to my comments in a follow up PR

/// security reasons, will never be supported for .NET code that runs on the server.
/// This is an advanced mechanism that should only be used in performance-critical scenarios.
/// </summary>
public interface IJSUnmarshalledRuntime
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we mark this as [SupportedOSPlatform('browser")]? Previously you were unable to get to this contract from a Blazor server app. We have a way to indicate this is never useful in it.

@pranavkm pranavkm added this to the 5.0.0-rc1 milestone Aug 20, 2020
@MackinnonBuck MackinnonBuck changed the base branch from master to release/5.0 August 20, 2020 21:53
@MackinnonBuck MackinnonBuck merged commit 0b1042c into release/5.0 Aug 21, 2020
@MackinnonBuck MackinnonBuck deleted the t-mabuc/input-file branch August 21, 2020 00:52
/// This only has an effect when using Blazor Server.
/// </para>
/// </summary>
public TimeSpan SegmentFetchTimeout { get; set; } = TimeSpan.FromSeconds(3);
Copy link
Member Author

Choose a reason for hiding this comment

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

Consider increasing the timeout.

@pranavkm pranavkm added the api-approved API was approved in API review, it can be implemented label Aug 25, 2020
@MackinnonBuck
Copy link
Member Author

API changes are being included as part of #25248.

@hannespreishuber
Copy link

looking for deep explanation, why imageFile.OpenReadStream(512000,cancellationToken) is limited?

@SteveSandersonMS
Copy link
Member

@hannespreishuber Sorry, I don't understand the question. If you think there's a problem or some unexplained behavior, could you please post a new issue detailing repro steps, what you expect to happen, and what happens instead? Thanks!

@hannespreishuber
Copy link

The upload limit of 512KB as parameter size. No bigger files? or do I miss something (as there is no doc on it)

@halter73
Copy link
Member

What's stopping you from changing the parameter? Is it being called internally somewhere where maxAllowedSize is not configurable? The doc comments look good to me, but I don't think docs.microsoft.com has been updated yet.

@hannespreishuber
Copy link

ah my fault. Read that Doc comment as internal limit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api-approved API was approved in API review, it can be implemented area-blazor Includes: Blazor, Razor Components

Projects

None yet

Development

Successfully merging this pull request may close these issues.