[wasm] Initial addition of Browser WebAssembly support#35573
[wasm] Initial addition of Browser WebAssembly support#35573kjpou1 merged 114 commits intodotnet:masterfrom kjpou1:wasm-http-interop
Conversation
- This still needs to have the code implement nullable
…http-interop # Conflicts: # src/libraries/System.Net.Http/src/System.Net.Http.csproj
|
Tagging subscribers to this area: @dotnet/ncl |
src/libraries/Common/src/Interop/Browser/Interop.HttpHandlerService.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.HttpHandlerService.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.HttpHandlerService.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.HttpHandlerService.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.HttpHandlerService.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.HttpHandlerService.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.HttpHandlerService.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.JavaScript.Array.cs
Outdated
Show resolved
Hide resolved
stephentoub
left a comment
There was a problem hiding this comment.
Thanks for starting to work on this. I skimmed it and left a few comments. I'll comment in more depth when it's further along and the initial round of feedback has been addressed. Thanks!
src/libraries/Common/src/Interop/Browser/Interop.HttpHandlerService.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.HttpHandlerService.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.HttpHandlerService.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.HttpHandlerService.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.HttpHandlerService.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.JavaScript.Array.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.HttpHandlerService.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.JavaScript.HostObject.cs
Outdated
Show resolved
Hide resolved
...ibraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/BrowserHttpMessageHandler.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/SocketsHttpHandler.cs
Outdated
Show resolved
Hide resolved
- Throws `PlatformNotSupportedException` for properties and methods of the HttpMessageHandler abstract implementation.
- Addresses commit comments.
jkotas
left a comment
There was a problem hiding this comment.
The CI failures seem to be related to the change. The CI needs to be green before this is merged.
All my concerns are addressed.
I would like to see somebody from the networking team to sign-off on this as well.
|
I'll take another pass through it today. |
…used to obtain the socket field
| } | ||
|
|
||
| FieldInfo socketsHttpHandlerField = typeof(HttpClientHandler).GetField("_socketsHttpHandler", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| FieldInfo socketsHttpHandlerField = typeof(HttpClientHandler).GetField("_underlyingHandler", BindingFlags.NonPublic | BindingFlags.Instance); |
There was a problem hiding this comment.
Now that _underlyingHandler could be something other than a SocketsHttpHandler, this set of checks will probably need to be updated to validate that the instance retrieved from the field actually is a SocketsHttpHandler and bailing if it's not. That could be left for later, but if we start running the System.Net.Http tests against the webassembly implementation, this will likely cause problems (then again, I expect a ton of tests wouldn't pass, anyway).
| { | ||
| using (var streamingSupported = new Function("return typeof Response !== 'undefined' && 'body' in Response.prototype && typeof ReadableStream === 'function'")) | ||
| StreamingSupported = (bool)streamingSupported.Call(); | ||
| } |
There was a problem hiding this comment.
Doesn't need to be in this PR, but it might be worth refactoring this subsequently to avoid the explicit static cctor, e.g.
private static bool StreamingSupported { get; } = GetIsStreamingSupported();
private static bool GetIsStreamingSupported()
{
using (var streamingSupported = new Function("return typeof Response !== 'undefined' && 'body' in Response.prototype && typeof ReadableStream === 'function'"))
return (bool)streamingSupported.Call();
}| set => throw new PlatformNotSupportedException(); | ||
| } | ||
|
|
||
| public IDictionary<string, object?> Properties => throw new PlatformNotSupportedException(); |
There was a problem hiding this comment.
May not matter, but this can be made to work, e.g.
private Dictionary<string, object?>? _properties;
public IDictionary<string, object?> Properties => _properties ??= new Dictionary<string, object?>();It's fine if you want to punt on that for now, given that most everything else throws PNSE and there's little reason right now for someone to be storing data into properties.
|
|
||
| protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => | ||
| SerializeToStreamAsync(stream, context, CancellationToken.None); | ||
| protected sealed override async Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) |
There was a problem hiding this comment.
Nit: the sealed here isn't necessary, as the whole class is sealed
| get => throw new NotSupportedException(); | ||
| set => throw new NotSupportedException(); | ||
| } | ||
|
|
There was a problem hiding this comment.
Nit: you might want to override BeginRead/EndRead as well; if you don't and someone uses them, they'll end up getting an exception about synchronous reads not being supported, as by default the base implementations just queue a work item that wraps the sync method. You can implement these pretty easily with an internal helper that should already be available in this library, e.g. something like:
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsynCallback? callback, object? state) =>
TaskToApm.Begin(ReadAsync(buffer, offset, count), callback, state);
public override int EndRead(IAsyncResult asyncResult) => TaskToApm.End<int>(asyncResult);Search for BeginRead/EndRead and you should find other examples in this project.
| } | ||
| } | ||
|
|
||
| if (_bufferedBytes != null && _position < _bufferedBytes.Length) |
There was a problem hiding this comment.
Am I reading this correctly that if someone reads to the end but then calls read again (such that _position >= _bufferedBytes.Length), they'll end up starting to read again at the beginning because they'll fail this if check and proceed to the below try? If so, that seems wrong.
| public bool UseCookies | ||
| { | ||
| get => throw new PlatformNotSupportedException("Property UseCookies is not supported."); | ||
| set => throw new PlatformNotSupportedException("Property UseCookies is not supported."); |
There was a problem hiding this comment.
I still see all of these custom messages being passed to PNSE.
| _clientCertificateOptions = value; | ||
| _socketsHttpHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate()!; | ||
| _underlyingHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate()!; | ||
| #endif |
There was a problem hiding this comment.
These ifdefs are ok for now. It'd be good to see if we can find a cleaner solution subsequently.
| <StrongNameKeyId>Microsoft</StrongNameKeyId> | ||
| <IsNETCoreApp>true</IsNETCoreApp> | ||
| </PropertyGroup> | ||
| </Project> No newline at end of file |
There was a problem hiding this comment.
Nit: missing a newline at the end of the file
|
|
||
| namespace System.Runtime.InteropServices.JavaScript | ||
| { | ||
|
|
| /// <param name="js_handle">Js handle.</param> | ||
| internal DataView(IntPtr js_handle) : base(js_handle) | ||
| { } | ||
| /// <summary> |
There was a problem hiding this comment.
Nit: some of these members have blank lines between them, some don't
| public Float32Array() { } | ||
|
|
||
| public Float32Array(int length) : base(length) { } | ||
|
|
| public Float64Array() { } | ||
|
|
||
| public Float64Array(int length) : base(length) { } | ||
|
|
|
|
||
| public Int8Array(int length) : base(length) | ||
| { } | ||
|
|
There was a problem hiding this comment.
Nit:
Another extra blank line. I'll stop commenting on these, but there look to be a few more.
| public DictionaryEntry Entry => (DictionaryEntry)Current; | ||
|
|
||
| // Return the key of the current item. | ||
| public object Key { get; private set; } = new object(); |
There was a problem hiding this comment.
Seems a little strange to be assigning a new object to Key here. Is that intentional?
| } | ||
|
|
||
| // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. | ||
| // TODO: set large fields to null. |
There was a problem hiding this comment.
What's the plan for all these TODOs? Is there an issue tracking whatever needs to be done here?
|
Will follow up with PR to address the other points. |
Initial file support for Interop and Http handlers.