Streaming Interop Followup Items#33916
Conversation
* CI Debugging * CiData message * CiData message * Update RemoteJSDataStream.cs * Remove Task.Delay * Update RemoteJSDataStream.cs * Update RemoteJSDataStream.cs
| long pauseIncomingBytesThreshold, | ||
| long resumeIncomingBytesThreshold, |
There was a problem hiding this comment.
Per David Fowler's suggestion #33491 (comment)
| *REMOVED*static Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, params object![]! args) -> System.Threading.Tasks.ValueTask | ||
| static Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(this Microsoft.JSInterop.IJSRuntime! jsRuntime, string! identifier, params object?[]? args) -> System.Threading.Tasks.ValueTask | ||
| virtual Microsoft.JSInterop.JSRuntime.ReadJSDataAsStreamAsync(Microsoft.JSInterop.IJSStreamReference! jsStreamReference, long totalLength, long maxBufferSize, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<System.IO.Stream!>! | ||
| virtual Microsoft.JSInterop.JSRuntime.ReadJSDataAsStreamAsync(Microsoft.JSInterop.IJSStreamReference! jsStreamReference, long totalLength, long pauseIncomingBytesThreshold, long resumeIncomingBytesThreshold, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<System.IO.Stream!>! |
There was a problem hiding this comment.
I'm not a big fan of this API.
It exposes a bunch of internal details and it does so in a way that is problematic and that can make it easy to introduce security issues if you are not careful. The defaults need to be safe (the default can't never be "unlimited" on a server app) and we should add a remark on the comments about the security implications of these parameters.
There was a problem hiding this comment.
@javiercn Would you consider it sufficient to:
- have some default like 100KB or so
- remove the behavior of "zero means unlimited" so that if someone really wants unlimited they have to pass
int.MaxValueor similar - include a mention in the XML docs for the parameter saying something like
Avoid specifying an excessively large value because this could allow clients to exhaust server memory.
?
There was a problem hiding this comment.
That sounds about right.
We would need to figure out a good default. It's a trade-off between speed and availability I think
There was a problem hiding this comment.
To clarify this here, we do have a safe default (indicated by -1, zero is not the default). Users should be working with the JSStreamReference and not the JSRuntime methods seen here. This follows the exact pattern seen in the PipeOptions, and we utilize these parameters directly with the Pipe during initialization.
What the safe defaults translate to:
https://github.com/dotnet/runtime/blob/9fb6e818cda2e4364e085fe0b8ecebed97db9596/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/PipeOptions.cs#L47-L69
(65k and 32.5k bytes). Originally we were using a 100kb but per #33491 (comment), it seemed like using the Pipe defaults was preferred.
Are we okay keeping with this general approach in this case? Action items:
- Update the comments to provide more clarity on -1 and security implications of using large sizes
- Reflect the safe defaults
-1in theJSRuntimeas well.
javiercn
left a comment
There was a problem hiding this comment.
I have a few questions that I've put on the comments.
In addition to those questions, I would like us to add an API that exposes the PipeReader directly. This essentially saves an intermediate copy from the Stream. Look for other APIs that expose the PipeReader and follow the same pattern.
|
/azp run |
|
Azure Pipelines successfully started running 2 pipeline(s). |
I don't really mind, and am fine with requiring people to supply a typed array. We can always add support for more cases in the future if we want. However for clarity, an arraybuffer is just a store of bytes that can be viewed as being one of several possible types (Uint8Array, Uint32Array, etc.). So if we receive an arraybuffer, it's always correct and valid to read the bytes directly from it using any element size we choose arbitrarily. For example we could freely |
| jsStreamReference, | ||
| totalLength: 15, | ||
| maximumIncomingBytes: 10_000, | ||
| jsInteropDefaultCallTimeout: TimeSpan.FromSeconds(30), // Note we're using a 30 second timeout for this test |
There was a problem hiding this comment.
Generally we try to make tests as quick as possible, we do this by
a) not using real timers (mock timers so we control when they tick and how much time they think has passed)
b) avoiding timers if possible (presumably this test is actually testing a timeout so b. doesn't apply)
c) using much lower values for timeouts if a. or b. can't be done
Additionally, relying on a real timeout creates potential flakiness because what if the machine is really slow and the test doesn't do the work you expected before the timeout occurs?
Couple examples:
aspnetcore/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs
Lines 2690 to 2708 in 65276b0
Last thing, when using await you should consider putting .DefaultTimeout() on the calls so that any hangs will fail the test (and tell you where they hung) and not timeout the test run instead.
Example:
aspnetcore/src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs
Lines 4453 to 4461 in 65276b0
Sorry if this ended up looking like a bit of a rant, but I really want our tests to be reliable.
There was a problem hiding this comment.
Thanks @BrennanConroy appreciate the feedback. I went the route of using a TaskCompletionSource to match the pattern used in other src/Components/tests tests to keep consistency. I also significantly reduced the timeout values to avoid long running tests, and the TaskCompletionSource approach should eliminate flakiness as we'll be able to await the timeout. I've also updated the tests to leverage DefaultTimeout().
Will expose a public Edit: Done in 94ea801 |
I'll update in #33900 as that area is already being reworked in #33900. Edit: Done here. |
|
/azp run |
|
Azure Pipelines successfully started running 2 pipeline(s). |
|
@javiercn @SteveSandersonMS could I please get a review, hoping to get it in for Preview 7. |
Resolves:
JStoDotNet#33491 (comment)JStoDotNet#33491 (comment)ArrayBuffers directly: Blazor Streaming Interop |JStoDotNet#33491 (comment)ArrayBuffer's aren't normally used directly and we don't have element access, so I don't think we need to directly support them. I've updated the error message in the original PR.JStoDotNet#33491 (comment)Separate PR:
JStoDotNet#33491 (comment)