Backed out 14 changesets (bug 1815997, bug 1811624, bug 1814122, bug 1818074, bug 1815993, bug 1811958, bug 1814113, bug 1790678, bug 1817130, bug 1817129, bug 1814750, bug 1817521) for causing bp-hybrid build bustages related to WebTransport. CLOSED TREE

Backed out changeset 8cfdfa663856 (bug 1790678)
Backed out changeset 44f5c3b41dac (bug 1818074)
Backed out changeset debbb57f5328 (bug 1817130)
Backed out changeset 85dac52e3e4c (bug 1817521)
Backed out changeset ddb0ea4cdda2 (bug 1817129)
Backed out changeset 799ad4a11f33 (bug 1815993)
Backed out changeset fc263dcd3c5e (bug 1790678)
Backed out changeset 331d1209db0d (bug 1814113)
Backed out changeset 738d3cb6d163 (bug 1814122)
Backed out changeset 4c743c9e706a (bug 1814750)
Backed out changeset e7e0a6849e43 (bug 1811624)
Backed out changeset c8a708ab94c5 (bug 1811958)
Backed out changeset 62a3991715fb (bug 1814113)
Backed out changeset 85d446d9d20c (bug 1815997)
This commit is contained in:
Iulian Moraru 2023-02-23 06:07:49 +02:00
Родитель 794756e970
Коммит e79cbd009c
29 изменённых файлов: 268 добавлений и 1645 удалений

Просмотреть файл

@ -6,7 +6,6 @@
#include "mozilla/dom/UnderlyingSinkCallbackHelpers.h"
#include "StreamUtils.h"
#include "mozilla/dom/UnionTypes.h"
using namespace mozilla::dom;
@ -129,137 +128,3 @@ already_AddRefed<Promise> UnderlyingSinkAlgorithmsWrapper::AbortCallback(
[&](ErrorResult& aRv) { return AbortCallbackImpl(aCx, aReason, aRv); },
aRv);
}
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(WritableStreamToOutput,
UnderlyingSinkAlgorithmsBase,
nsIOutputStreamCallback)
NS_IMPL_CYCLE_COLLECTION_INHERITED(WritableStreamToOutput,
UnderlyingSinkAlgorithmsBase, mParent,
mOutput, mPromise)
NS_IMETHODIMP
WritableStreamToOutput::OnOutputStreamReady(nsIAsyncOutputStream* aStream) {
if (!mData) {
return NS_OK;
}
MOZ_ASSERT(mPromise);
uint32_t written = 0;
nsresult rv = mOutput->Write(
reinterpret_cast<const char*>(mData->Elements() + mWritten),
mData->Length() - mWritten, &written);
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
mPromise->MaybeRejectWithAbortError("Error writing to stream"_ns);
ClearData();
// XXX should we add mErrored and fail future calls immediately?
// I presume new calls to Write() will fail though, too
return rv;
}
if (NS_SUCCEEDED(rv)) {
mWritten += written;
MOZ_ASSERT(mWritten <= mData->Length());
if (mWritten >= mData->Length()) {
mPromise->MaybeResolveWithUndefined();
ClearData();
return NS_OK;
}
// more to write
}
// wrote partial or nothing
// Wait for space
nsCOMPtr<nsIEventTarget> target = mozilla::GetCurrentSerialEventTarget();
rv = mOutput->AsyncWait(this, 0, 0, target);
if (NS_FAILED(rv)) {
mPromise->MaybeRejectWithUnknownError("error waiting to write data");
ClearData();
// XXX should we add mErrored and fail future calls immediately?
// New calls to Write() will fail, note
// See step 5.2 of
// https://streams.spec.whatwg.org/#writable-stream-default-controller-process-write.
return rv;
}
return NS_OK;
}
already_AddRefed<Promise> WritableStreamToOutput::WriteCallback(
JSContext* aCx, JS::Handle<JS::Value> aChunk,
WritableStreamDefaultController& aController, ErrorResult& aError) {
ArrayBufferViewOrArrayBuffer data;
if (!data.Init(aCx, aChunk)) {
aError.StealExceptionFromJSContext(aCx);
return nullptr;
}
// buffer/bufferView
MOZ_ASSERT(data.IsArrayBuffer() || data.IsArrayBufferView());
RefPtr<Promise> promise = Promise::Create(mParent, aError);
if (NS_WARN_IF(aError.Failed())) {
return nullptr;
}
// This is a duplicate of dom/encoding/TextDecoderStream.cpp#51-69
// PeterV will deal with that when he lands his patch for TypedArrays
auto dataSpan = [&data]() {
if (data.IsArrayBuffer()) {
const ArrayBuffer& buffer = data.GetAsArrayBuffer();
buffer.ComputeState();
return Span{buffer.Data(), buffer.Length()};
}
MOZ_ASSERT(data.IsArrayBufferView());
const ArrayBufferView& buffer = data.GetAsArrayBufferView();
buffer.ComputeState();
return Span{buffer.Data(), buffer.Length()};
}();
// Try to write first, and only enqueue data if we were already blocked
// or the write didn't write it all. This avoids allocations and copies
// in common cases.
MOZ_ASSERT(!mPromise);
MOZ_ASSERT(mWritten == 0);
uint32_t written = 0;
nsresult rv = mOutput->Write(mozilla::AsChars(dataSpan).Elements(),
dataSpan.Length(), &written);
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
promise->MaybeRejectWithAbortError("error writing data");
return promise.forget();
}
if (NS_SUCCEEDED(rv)) {
if (written == dataSpan.Length()) {
promise->MaybeResolveWithUndefined();
return promise.forget();
}
dataSpan = dataSpan.From(written);
}
auto buffer = Buffer<uint8_t>::CopyFrom(dataSpan);
if (buffer.isNothing()) {
promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
return promise.forget();
}
mData = std::move(buffer);
mPromise = promise;
nsCOMPtr<nsIEventTarget> target = mozilla::GetCurrentSerialEventTarget();
rv = mOutput->AsyncWait(this, 0, 0, target);
if (NS_FAILED(rv)) {
ClearData();
promise->MaybeRejectWithUnknownError("error waiting to write data");
}
return promise.forget();
}
already_AddRefed<Promise> WritableStreamToOutput::AbortCallbackImpl(
JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
ErrorResult& aRv) {
// https://streams.spec.whatwg.org/#writablestream-set-up
// Step 3. Let abortAlgorithmWrapper be an algorithm that runs these steps:
// XXX The close or rather a dedicated abort should be async. For now we have
// to always fall back to the Step 3.3 below.
mOutput->CloseWithStatus(NS_ERROR_ABORT);
// Step 3.3. Return a promise resolved with undefined.
// Wrapper handles this
return nullptr;
}
void WritableStreamToOutput::ReleaseObjects() { mOutput->Close(); }

Просмотреть файл

@ -7,15 +7,12 @@
#ifndef mozilla_dom_UnderlyingSinkCallbackHelpers_h
#define mozilla_dom_UnderlyingSinkCallbackHelpers_h
#include "mozilla/Maybe.h"
#include "mozilla/Buffer.h"
#include "mozilla/HoldDropJSObjects.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/UnderlyingSinkBinding.h"
#include "nsCycleCollectionParticipant.h"
#include "nsISupports.h"
#include "nsISupportsImpl.h"
#include "nsIAsyncOutputStream.h"
/*
* See the comment in UnderlyingSourceCallbackHelpers.h!
@ -156,47 +153,6 @@ class UnderlyingSinkAlgorithmsWrapper : public UnderlyingSinkAlgorithmsBase {
}
};
class WritableStreamToOutput final : public UnderlyingSinkAlgorithmsWrapper,
public nsIOutputStreamCallback {
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIOUTPUTSTREAMCALLBACK
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WritableStreamToOutput,
UnderlyingSinkAlgorithmsBase)
WritableStreamToOutput(nsIGlobalObject* aParent,
nsIAsyncOutputStream* aOutput)
: mWritten(0), mParent(aParent), mOutput(aOutput) {}
// Streams algorithms
already_AddRefed<Promise> WriteCallback(
JSContext* aCx, JS::Handle<JS::Value> aChunk,
WritableStreamDefaultController& aController, ErrorResult& aRv) override;
// No CloseCallbackImpl() since ReleaseObjects() will call Close()
already_AddRefed<Promise> AbortCallbackImpl(
JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
ErrorResult& aRv) override;
void ReleaseObjects() override;
private:
~WritableStreamToOutput() override = default;
void ClearData() {
mData = Nothing();
mPromise = nullptr;
mWritten = 0;
}
uint32_t mWritten;
nsCOMPtr<nsIGlobalObject> mParent;
nsCOMPtr<nsIAsyncOutputStream> mOutput;
RefPtr<Promise> mPromise; // Resolved when entirely written
Maybe<Buffer<uint8_t>> mData;
};
} // namespace mozilla::dom
#endif

Просмотреть файл

@ -5,11 +5,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "StreamUtils.h"
#include "mozilla/dom/ReadableStream.h"
#include "mozilla/dom/ReadableStreamDefaultController.h"
#include "mozilla/dom/UnderlyingSourceCallbackHelpers.h"
#include "mozilla/dom/UnderlyingSourceBinding.h"
#include "js/experimental/TypedData.h"
namespace mozilla::dom {
@ -146,254 +144,4 @@ already_AddRefed<Promise> UnderlyingSourceAlgorithmsWrapper::CancelCallback(
aRv);
}
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(
InputToReadableStreamAlgorithms, UnderlyingSourceAlgorithmsWrapper)
NS_IMPL_CYCLE_COLLECTION_INHERITED(InputToReadableStreamAlgorithms,
UnderlyingSourceAlgorithmsWrapper, mStream)
already_AddRefed<Promise> InputToReadableStreamAlgorithms::PullCallbackImpl(
JSContext* aCx, ReadableStreamController& aController, ErrorResult& aRv) {
MOZ_ASSERT(aController.IsByte());
ReadableStream* stream = aController.Stream();
MOZ_ASSERT(stream);
MOZ_DIAGNOSTIC_ASSERT(stream->Disturbed());
MOZ_DIAGNOSTIC_ASSERT(mState == eInitializing || mState == eWaiting ||
mState == eChecking || mState == eReading);
RefPtr<Promise> resolvedWithUndefinedPromise =
Promise::CreateResolvedWithUndefined(aController.GetParentObject(), aRv);
if (aRv.Failed()) {
return nullptr;
}
if (mState == eReading) {
// We are already reading data.
return resolvedWithUndefinedPromise.forget();
}
if (mState == eChecking) {
// If we are looking for more data, there is nothing else we should do:
// let's move this checking operation in a reading.
MOZ_ASSERT(mInput);
mState = eReading;
return resolvedWithUndefinedPromise.forget();
}
mState = eReading;
MOZ_DIAGNOSTIC_ASSERT(mInput);
nsresult rv = mInput->AsyncWait(this, 0, 0, mOwningEventTarget);
if (NS_WARN_IF(NS_FAILED(rv))) {
ErrorPropagation(aCx, stream, rv);
return nullptr;
}
// All good.
return resolvedWithUndefinedPromise.forget();
}
NS_IMETHODIMP
InputToReadableStreamAlgorithms::OnInputStreamReady(
nsIAsyncInputStream* aStream) {
MOZ_DIAGNOSTIC_ASSERT(aStream);
// Already closed. We have nothing else to do here.
if (mState == eClosed) {
return NS_OK;
}
AutoEntryScript aes(mStream->GetParentObject(),
"InputToReadableStream data available");
MOZ_DIAGNOSTIC_ASSERT(mInput);
MOZ_DIAGNOSTIC_ASSERT(mState == eReading || mState == eChecking);
JSContext* cx = aes.cx();
uint64_t size = 0;
nsresult rv = mInput->Available(&size);
if (NS_SUCCEEDED(rv) && size == 0) {
// In theory this should not happen. If size is 0, the stream should be
// considered closed.
rv = NS_BASE_STREAM_CLOSED;
}
// No warning for stream closed.
if (rv == NS_BASE_STREAM_CLOSED || NS_WARN_IF(NS_FAILED(rv))) {
ErrorPropagation(cx, mStream, rv);
return NS_OK;
}
// This extra checking is completed. Let's wait for the next read request.
if (mState == eChecking) {
mState = eWaiting;
return NS_OK;
}
mState = eWriting;
ErrorResult errorResult;
EnqueueChunkWithSizeIntoStream(cx, mStream, size, errorResult);
errorResult.WouldReportJSException();
if (errorResult.Failed()) {
ErrorPropagation(cx, mStream, errorResult.StealNSResult());
return NS_OK;
}
// The previous call can execute JS (even up to running a nested event
// loop), so |mState| can't be asserted to have any particular value, even
// if the previous call succeeds.
return NS_OK;
}
void InputToReadableStreamAlgorithms::WriteIntoReadRequestBuffer(
JSContext* aCx, ReadableStream* aStream, JS::Handle<JSObject*> aBuffer,
uint32_t aLength, uint32_t* aByteWritten) {
MOZ_DIAGNOSTIC_ASSERT(aBuffer);
MOZ_DIAGNOSTIC_ASSERT(aByteWritten);
MOZ_DIAGNOSTIC_ASSERT(mInput);
MOZ_DIAGNOSTIC_ASSERT(mState == eWriting);
mState = eChecking;
uint32_t written;
nsresult rv;
void* buffer;
{
// Bug 1754513: Hazard suppression.
//
// Because mInput->Read is detected as possibly GCing by the
// current state of our static hazard analysis, we need to do the
// suppression here. This can be removed with future improvements
// to the static analysis.
JS::AutoSuppressGCAnalysis suppress;
JS::AutoCheckCannotGC noGC;
bool isSharedMemory;
buffer = JS_GetArrayBufferViewData(aBuffer, &isSharedMemory, noGC);
MOZ_ASSERT(!isSharedMemory);
rv = mInput->Read(static_cast<char*>(buffer), aLength, &written);
if (NS_WARN_IF(NS_FAILED(rv))) {
ErrorPropagation(aCx, aStream, rv);
return;
}
}
*aByteWritten = written;
if (written == 0) {
CloseAndReleaseObjects(aCx, aStream);
return;
}
rv = mInput->AsyncWait(this, 0, 0, mOwningEventTarget);
if (NS_WARN_IF(NS_FAILED(rv))) {
ErrorPropagation(aCx, aStream, rv);
return;
}
// All good.
}
// Whenever one or more bytes are available and stream is not
// errored, enqueue a Uint8Array wrapping an ArrayBuffer containing the
// available bytes into stream.
void InputToReadableStreamAlgorithms::EnqueueChunkWithSizeIntoStream(
JSContext* aCx, ReadableStream* aStream, uint64_t aAvailableData,
ErrorResult& aRv) {
// To avoid OOMing up on huge amounts of available data on a 32 bit system,
// as well as potentially overflowing nsIInputStream's Read method's
// parameter, let's limit our maximum chunk size to 256MB.
uint32_t ableToRead =
std::min(static_cast<uint64_t>(256 * 1024 * 1024), aAvailableData);
// Create Chunk
aRv.MightThrowJSException();
JS::Rooted<JSObject*> chunk(aCx, JS_NewUint8Array(aCx, ableToRead));
if (!chunk) {
aRv.StealExceptionFromJSContext(aCx);
return;
}
{
uint32_t bytesWritten = 0;
WriteIntoReadRequestBuffer(aCx, aStream, chunk, ableToRead, &bytesWritten);
// If bytesWritten is zero, then the stream has been closed; return
// rather than enqueueing a chunk filled with zeros.
if (bytesWritten == 0) {
return;
}
// If we don't read every byte we've allocated in the Uint8Array
// we risk enqueuing a chunk that is padded with trailing zeros,
// corrupting future processing of the chunks:
MOZ_DIAGNOSTIC_ASSERT((ableToRead - bytesWritten) == 0);
}
MOZ_ASSERT(aStream->Controller()->IsByte());
JS::Rooted<JS::Value> chunkValue(aCx);
chunkValue.setObject(*chunk);
aStream->EnqueueNative(aCx, chunkValue, aRv);
}
void InputToReadableStreamAlgorithms::CloseAndReleaseObjects(
JSContext* aCx, ReadableStream* aStream) {
MOZ_DIAGNOSTIC_ASSERT(mState != eClosed);
mState = eClosed;
ReleaseObjects();
if (aStream->State() == ReadableStream::ReaderState::Readable) {
IgnoredErrorResult rv;
aStream->CloseNative(aCx, rv);
NS_WARNING_ASSERTION(!rv.Failed(), "Failed to Close Stream");
}
}
void InputToReadableStreamAlgorithms::ReleaseObjects() {
mInput->CloseWithStatus(NS_BASE_STREAM_CLOSED);
}
void InputToReadableStreamAlgorithms::ErrorPropagation(JSContext* aCx,
ReadableStream* aStream,
nsresult aError) {
// Nothing to do.
if (mState == eClosed) {
return;
}
// Let's close the stream.
if (aError == NS_BASE_STREAM_CLOSED) {
CloseAndReleaseObjects(aCx, aStream);
return;
}
// Let's use a generic error.
ErrorResult rv;
// XXXbz can we come up with a better error message here to tell the
// consumer what went wrong?
rv.ThrowTypeError("Error in input stream");
JS::Rooted<JS::Value> errorValue(aCx);
bool ok = ToJSValue(aCx, std::move(rv), &errorValue);
MOZ_RELEASE_ASSERT(ok, "ToJSValue never fails for ErrorResult");
{
// This will be ignored if it's already errored.
IgnoredErrorResult rv;
aStream->ErrorNative(aCx, errorValue, rv);
NS_WARNING_ASSERTION(!rv.Failed(), "Failed to error InputToReadableStream");
}
MOZ_ASSERT(mInput);
CloseAndReleaseObjects(aCx, aStream);
}
} // namespace mozilla::dom

Просмотреть файл

@ -10,7 +10,6 @@
#include "mozilla/HoldDropJSObjects.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/UnderlyingSourceBinding.h"
#include "nsIAsyncInputStream.h"
#include "nsISupports.h"
#include "nsISupportsImpl.h"
@ -23,13 +22,10 @@
* WebIDL as if they were methods. So we have to preserve the underlying object
* to use as the This value on invocation.
*/
enum class nsresult : uint32_t;
namespace mozilla::dom {
class BodyStreamHolder;
class ReadableStreamController;
class ReadableStream;
class UnderlyingSourceAlgorithmsBase : public nsISupports {
public:
@ -159,78 +155,6 @@ class UnderlyingSourceAlgorithmsWrapper
}
};
class InputToReadableStreamAlgorithms final
: public UnderlyingSourceAlgorithmsWrapper,
public nsIInputStreamCallback {
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIINPUTSTREAMCALLBACK
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(InputToReadableStreamAlgorithms,
UnderlyingSourceAlgorithmsWrapper)
InputToReadableStreamAlgorithms(nsIAsyncInputStream* aInput,
ReadableStream* aStream)
: mState(eInitializing),
mOwningEventTarget(GetCurrentSerialEventTarget()),
mInput(aInput),
mStream(aStream) {}
// Streams algorithms
already_AddRefed<Promise> PullCallbackImpl(
JSContext* aCx, ReadableStreamController& aController,
ErrorResult& aRv) override;
void ReleaseObjects() override;
private:
~InputToReadableStreamAlgorithms() override = default;
MOZ_CAN_RUN_SCRIPT_BOUNDARY void CloseAndReleaseObjects(
JSContext* aCx, ReadableStream* aStream);
void WriteIntoReadRequestBuffer(JSContext* aCx, ReadableStream* aStream,
JS::Handle<JSObject*> aBuffer,
uint32_t aLength, uint32_t* aByteWritten);
MOZ_CAN_RUN_SCRIPT_BOUNDARY void EnqueueChunkWithSizeIntoStream(
JSContext* aCx, ReadableStream* aStream, uint64_t aAvailableData,
ErrorResult& aRv);
void ErrorPropagation(JSContext* aCx, ReadableStream* aStream,
nsresult aError);
// Common methods
enum State {
// This is the beginning state before any reading operation.
eInitializing,
// RequestDataCallback has not been called yet. We haven't started to read
// data from the stream yet.
eWaiting,
// We are reading data in a separate I/O thread.
eReading,
// We are ready to write something in the JS Buffer.
eWriting,
// After a writing, we want to check if the stream is closed. After the
// check, we go back to eWaiting. If a reading request happens in the
// meantime, we move to eReading state.
eChecking,
// Operation completed.
eClosed,
};
State mState;
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
nsCOMPtr<nsIAsyncInputStream> mInput;
RefPtr<ReadableStream> mStream;
};
} // namespace mozilla::dom
#endif

Просмотреть файл

@ -218,9 +218,6 @@ class WritableStream : public nsISupports, public nsWrapperCache {
already_AddRefed<WritableStreamDefaultWriter> GetWriter(ErrorResult& aRv);
protected:
nsCOMPtr<nsIGlobalObject> mGlobal;
// Internal Slots:
private:
bool mBackpressure = false;
@ -241,6 +238,7 @@ class WritableStream : public nsISupports, public nsWrapperCache {
RefPtr<WritableStreamDefaultWriter> mWriter;
nsTArray<RefPtr<Promise>> mWriteRequests;
nsCOMPtr<nsIGlobalObject> mGlobal;
HoldDropJSObjectsCaller mHoldDropCaller;
};

Просмотреть файл

@ -32,11 +32,6 @@ dictionary WebTransportCloseInfo {
UTF8String reason = "";
};
/* https://w3c.github.io/webtransport/#uni-stream-options */
dictionary WebTransportSendStreamOptions {
long long? sendOrder = null;
};
/* https://w3c.github.io/webtransport/#web-transport-stats */
dictionary WebTransportStats {
@ -78,19 +73,17 @@ interface WebTransport {
readonly attribute Promise<WebTransportCloseInfo> closed;
[Throws] undefined close(optional WebTransportCloseInfo closeInfo = {});
[Throws] readonly attribute WebTransportDatagramDuplexStream datagrams;
readonly attribute WebTransportDatagramDuplexStream datagrams;
[NewObject]
Promise<WebTransportBidirectionalStream> createBidirectionalStream(
optional WebTransportSendStreamOptions options = {});
Promise<WebTransportBidirectionalStream> createBidirectionalStream();
/* a ReadableStream of WebTransportBidirectionalStream objects */
readonly attribute ReadableStream incomingBidirectionalStreams;
/* XXX spec says this should be WebTransportSendStream */
[NewObject]
Promise<WritableStream> createUnidirectionalStream(
optional WebTransportSendStreamOptions options = {});
Promise<WritableStream> createUnidirectionalStream();
/* a ReadableStream of WebTransportReceiveStream objects */
readonly attribute ReadableStream incomingUnidirectionalStreams;
};

Просмотреть файл

@ -3,14 +3,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* https://w3c.github.io/webtransport/#send-stream */
[Exposed=(Window,Worker), SecureContext, Pref="network.webtransport.enabled"]
interface WebTransportSendStream : WritableStream {
Promise<WebTransportSendStreamStats> getStats();
};
/* https://w3c.github.io/webtransport/#send-stream-stats */
dictionary WebTransportSendStreamStats {
@ -20,13 +12,6 @@ dictionary WebTransportSendStreamStats {
unsigned long long bytesAcknowledged;
};
/* https://w3c.github.io/webtransport/#receive-stream */
[Exposed=(Window,Worker), SecureContext, Pref="network.webtransport.enabled"]
interface WebTransportReceiveStream : ReadableStream {
Promise<WebTransportReceiveStreamStats> getStats();
};
/* https://w3c.github.io/webtransport/#receive-stream-stats */
dictionary WebTransportReceiveStreamStats {
@ -35,10 +20,26 @@ dictionary WebTransportReceiveStreamStats {
unsigned long long bytesRead;
};
/* https://w3c.github.io/webtransport/#receive-stream */
/* https://w3c.github.io/webtransport/#send-stream */
/*
[Exposed=(Window,Worker), SecureContext, Pref="network.webtransport.enabled"]
interface WebTransportSendStream : WritableStream {
Promise<WebTransportSendStreamStats> getStats();
};
[Exposed=(Window,Worker), SecureContext, Pref="network.webtransport.enabled"]
interface WebTransportReceiveStream : ReadableStream {
Promise<WebTransportReceiveStreamStats> getStats();
};
*/
/* https://w3c.github.io/webtransport/#bidirectional-stream */
[Exposed=(Window,Worker), SecureContext, Pref="network.webtransport.enabled"]
interface WebTransportBidirectionalStream {
readonly attribute WebTransportReceiveStream readable;
readonly attribute WebTransportSendStream writable;
// XXX spec says these should be WebTransportReceiveStream and WebTransportSendStream
readonly attribute ReadableStream readable;
readonly attribute WritableStream writable;
};

Просмотреть файл

@ -6,11 +6,9 @@
#include "WebTransport.h"
#include "WebTransportBidirectionalStream.h"
#include "mozilla/RefPtr.h"
#include "nsUTF8Utils.h"
#include "nsIURL.h"
#include "nsIWebTransportStream.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/DOMExceptionBinding.h"
#include "mozilla/dom/Promise.h"
@ -19,46 +17,20 @@
#include "mozilla/dom/ReadableStreamDefaultController.h"
#include "mozilla/dom/WebTransportDatagramDuplexStream.h"
#include "mozilla/dom/WebTransportError.h"
#include "mozilla/dom/WebTransportStreams.h"
#include "mozilla/dom/WebTransportLog.h"
#include "mozilla/dom/WritableStream.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/ipc/PBackgroundChild.h"
using namespace mozilla::ipc;
namespace mozilla::dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(WebTransport)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WebTransport)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncomingUnidirectionalStreams)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncomingBidirectionalStreams)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncomingUnidirectionalAlgorithm)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncomingBidirectionalAlgorithm)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSendStreams)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReceiveStreams)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDatagrams)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReady)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClosed)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WebTransport)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncomingUnidirectionalStreams)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncomingBidirectionalStreams)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncomingUnidirectionalAlgorithm)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncomingBidirectionalAlgorithm)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSendStreams)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReceiveStreams)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDatagrams)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReady)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mClosed)
if (tmp->mChild) {
tmp->mChild->Shutdown(false);
tmp->mChild = nullptr;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebTransport, mGlobal,
mIncomingUnidirectionalStreams,
mIncomingBidirectionalStreams,
mSendStreams, mReceiveStreams, mDatagrams,
mReady, mClosed)
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebTransport)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebTransport)
@ -77,7 +49,6 @@ WebTransport::WebTransport(nsIGlobalObject* aGlobal)
WebTransport::~WebTransport() {
// Should be empty by this point, because we should always have run cleanup:
// https://w3c.github.io/webtransport/#webtransport-procedures
LOG(("~WebTransport() for %p", this));
MOZ_ASSERT(mSendStreams.IsEmpty());
MOZ_ASSERT(mReceiveStreams.IsEmpty());
// If this WebTransport was destroyed without being closed properly, make
@ -85,52 +56,24 @@ WebTransport::~WebTransport() {
// Since child has a raw ptr to us, we MUST call Shutdown() before we're
// destroyed
if (mChild) {
mChild->Shutdown(true);
mChild->Shutdown();
}
}
// From parent
void WebTransport::NewBidirectionalStream(
const RefPtr<DataPipeReceiver>& aIncoming,
const RefPtr<DataPipeSender>& aOutgoing) {
LOG_VERBOSE(("NewBidirectionalStream()"));
// Create a Bidirectional stream and push it into the
// IncomingBidirectionalStreams stream. Must be added to the ReceiveStreams
// and SendStreams arrays
UniquePtr<BidirectionalPair> streams(
new BidirectionalPair(aIncoming, aOutgoing));
mBidirectionalStreams.AppendElement(std::move(streams));
// We need to delete them all!
// Notify something to wake up readers of IncomingReceiveStreams
// The callback is always set/used from the same thread (MainThread or a
// Worker thread).
if (mIncomingBidirectionalAlgorithm) {
RefPtr<WebTransportIncomingStreamsAlgorithms> callback =
mIncomingBidirectionalAlgorithm;
LOG(("NotifyIncomingStream"));
callback->NotifyIncomingStream();
}
const RefPtr<mozilla::ipc::DataPipeReceiver>& aIncoming,
const RefPtr<mozilla::ipc::DataPipeSender>& aOutgoing) {
// XXX
}
void WebTransport::NewUnidirectionalStream(
const RefPtr<mozilla::ipc::DataPipeReceiver>& aStream) {
LOG_VERBOSE(("NewUnidirectionalStream()"));
// Create a Unidirectional stream and push it into the
// IncomingUnidirectionalStreams stream. Must be added to the ReceiveStreams
// array
mUnidirectionalStreams.AppendElement(aStream);
// Notify something to wake up readers of IncomingReceiveStreams
// The callback is always set/used from the same thread (MainThread or a
// Worker thread).
if (mIncomingUnidirectionalAlgorithm) {
RefPtr<WebTransportIncomingStreamsAlgorithms> callback =
mIncomingUnidirectionalAlgorithm;
LOG(("NotifyIncomingStream"));
callback->NotifyIncomingStream();
}
// RefPtr<ReadableStream> stream = CreateReadableByteStream(cx, global,
// algorithm, aRV);
}
// WebIDL Boilerplate
@ -149,7 +92,6 @@ already_AddRefed<WebTransport> WebTransport::Constructor(
const GlobalObject& aGlobal, const nsAString& aURL,
const WebTransportOptions& aOptions, ErrorResult& aError) {
LOG(("Creating WebTransport for %s", NS_ConvertUTF16toUTF8(aURL).get()));
// https://w3c.github.io/webtransport/#webtransport-constructor
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
RefPtr<WebTransport> result = new WebTransport(global);
@ -158,7 +100,6 @@ already_AddRefed<WebTransport> WebTransport::Constructor(
return nullptr;
}
// Step 25 Return transport
return result.forget();
}
@ -220,10 +161,16 @@ void WebTransport::Init(const GlobalObject& aGlobal, const nsAString& aURL,
// SendStreams: empty ordered set
// ReceiveStreams: empty ordered set
// Ready: new promise
mReady = Promise::CreateInfallible(mGlobal);
mReady = Promise::Create(mGlobal, aError);
if (NS_WARN_IF(aError.Failed())) {
return;
}
// Closed: new promise
mClosed = Promise::CreateInfallible(mGlobal);
mClosed = Promise::Create(mGlobal, aError);
if (NS_WARN_IF(aError.Failed())) {
return;
}
PBackgroundChild* backgroundChild =
BackgroundChild::GetOrCreateForCurrentThread();
@ -268,14 +215,18 @@ void WebTransport::Init(const GlobalObject& aGlobal, const nsAString& aURL,
// We set the global from the aGlobalObject parameter of the constructor, so
// it must still be set here.
const nsCOMPtr<nsIGlobalObject> global(mGlobal);
mIncomingBidirectionalAlgorithm = new WebTransportIncomingStreamsAlgorithms(
WebTransportIncomingStreamsAlgorithms::StreamType::Bidirectional, this);
// Used to implement the "wait until" aspects of the pull algorithm
mIncomingBidirectionalPromise = Promise::Create(mGlobal, aError);
if (NS_WARN_IF(aError.Failed())) {
return;
}
RefPtr<WebTransportIncomingStreamsAlgorithms> algorithm =
mIncomingBidirectionalAlgorithm;
new WebTransportIncomingStreamsAlgorithms(mIncomingBidirectionalPromise,
false, this);
mIncomingBidirectionalStreams = ReadableStream::CreateNative(
cx, global, *algorithm, Some(0.0), nullptr, aError);
cx, global, *algorithm, Some(0.0), nullptr, aError); // XXX
if (aError.Failed()) {
return;
}
@ -285,10 +236,15 @@ void WebTransport::Init(const GlobalObject& aGlobal, const nsAString& aURL,
// pullAlgorithm set to pullUnidirectionalStreamAlgorithm, and highWaterMark
// set to 0.
mIncomingUnidirectionalAlgorithm = new WebTransportIncomingStreamsAlgorithms(
WebTransportIncomingStreamsAlgorithms::StreamType::Unidirectional, this);
// Used to implement the "wait until" aspects of the pull algorithm
mIncomingUnidirectionalPromise = Promise::Create(mGlobal, aError);
if (NS_WARN_IF(aError.Failed())) {
return;
}
algorithm = new WebTransportIncomingStreamsAlgorithms(
mIncomingUnidirectionalPromise, true, this);
algorithm = mIncomingUnidirectionalAlgorithm;
mIncomingUnidirectionalStreams = ReadableStream::CreateNative(
cx, global, *algorithm, Some(0.0), nullptr, aError);
if (aError.Failed()) {
@ -318,14 +274,13 @@ void WebTransport::Init(const GlobalObject& aGlobal, const nsAString& aURL,
nsresult rv = aResult.IsReject()
? NS_ERROR_FAILURE
: Get<0>(aResult.ResolveValue());
LOG(("isreject: %d nsresult 0x%x", aResult.IsReject(),
(uint32_t)rv));
if (NS_FAILED(rv)) {
self->RejectWaitingConnection(rv, child);
self->RejectWaitingConnection(rv);
} else {
// This will process anything waiting for the connection to
// complete;
// Step 25 Return transport
self->ResolveWaitingConnection(
static_cast<WebTransportReliabilityMode>(
Get<1>(aResult.ResolveValue())),
@ -338,58 +293,31 @@ void WebTransport::ResolveWaitingConnection(
WebTransportReliabilityMode aReliability, WebTransportChild* aChild) {
LOG(("Resolved Connection %p, reliability = %u", this,
(unsigned)aReliability));
// https://w3c.github.io/webtransport/#webtransport-constructor
// Step 17 of initialize WebTransport over HTTP
// Step 17.1 If transport.[[State]] is not "connecting":
if (mState != WebTransportState::CONNECTING) {
// Step 17.1.1: In parallel, terminate session.
// Step 17.1.2: abort these steps
// Cleanup should have been called, which means Ready has been rejected
return;
}
MOZ_ASSERT(mState == WebTransportState::CONNECTING);
mChild = aChild;
// Step 17.2: Set transport.[[State]] to "connected".
mState = WebTransportState::CONNECTED;
// Step 17.3: Set transport.[[Session]] to session.
// Step 17.4: Set transports [[Reliability]] to "supports-unreliable".
mReliability = aReliability;
// Step 17.5: Resolve transport.[[Ready]] with undefined.
mReady->MaybeResolveWithUndefined();
mReady->MaybeResolve(true);
}
void WebTransport::RejectWaitingConnection(nsresult aRv,
WebTransportChild* aChild) {
LOG(("Rejected connection %p %x", this, (uint32_t)aRv));
// https://w3c.github.io/webtransport/#initialize-webtransport-over-http
void WebTransport::RejectWaitingConnection(nsresult aRv) {
LOG(("Reject Connection %p", this));
MOZ_ASSERT(mState == WebTransportState::CONNECTING);
mState = WebTransportState::FAILED;
LOG(("Rejected connection %x", (uint32_t)aRv));
// Step 10: If connection is failure, then abort the remaining steps and
// queue a network task with transport to run these steps:
// Step 10.1: If transport.[[State]] is "closed" or "failed", then abort
// these steps.
// https://w3c.github.io/webtransport/#webtransport-internal-slots
// "Reliability returns "pending" until a connection is established" so
// we leave it pending
mReady->MaybeReject(aRv);
// This will abort any pulls for IncomingBidirectional/UnidirectionalStreams
mIncomingBidirectionalPromise->MaybeResolveWithUndefined();
mIncomingUnidirectionalPromise->MaybeResolveWithUndefined();
// Step 14: If the previous step fails, abort the remaining steps and
// queue a network task with transport to run these steps:
// Step 14.1: If transport.[[State]] is "closed" or "failed", then abort
// these steps.
if (mState == WebTransportState::CLOSED ||
mState == WebTransportState::FAILED) {
aChild->Shutdown(true);
// Cleanup should have been called, which means Ready has been
// rejected and pulls resolved
return;
}
// Step 14.2: Let error be the result of creating a WebTransportError with
// "session".
RefPtr<WebTransportError> error = new WebTransportError(
"WebTransport connection rejected"_ns, WebTransportErrorSource::Session);
// Step 14.3: Cleanup transport with error.
Cleanup(error, nullptr, IgnoreErrors());
// We never set mChild, but we need to prepare it to die
aChild->Shutdown(true);
// We never set mChild, so we aren't holding a reference that blocks GC
// (spec 5.8)
}
bool WebTransport::ParseURL(const nsAString& aURL) const {
@ -426,39 +354,14 @@ WebTransportCongestionControl WebTransport::CongestionControl() {
return WebTransportCongestionControl::Default;
}
void WebTransport::RemoteClosed(bool aCleanly, const uint32_t& aCode,
const nsACString& aReason) {
LOG(("Server closed: cleanly: %d, code %u, reason %s", aCleanly, aCode,
PromiseFlatCString(aReason).get()));
// Step 2 of https://w3c.github.io/webtransport/#web-transport-termination
// We calculate cleanly on the parent
// Step 2.1: If transport.[[State]] is "closed" or "failed", abort these
// steps.
if (mState == WebTransportState::CLOSED ||
mState == WebTransportState::FAILED) {
return;
already_AddRefed<Promise> WebTransport::Closed() {
ErrorResult error;
RefPtr<Promise> promise = Promise::Create(GetParentObject(), error);
if (error.Failed()) {
return nullptr;
}
// Step 2.2: Let error be the result of creating a WebTransportError with
// "session".
RefPtr<WebTransportError> error = new WebTransportError(
"remote WebTransport close"_ns, WebTransportErrorSource::Session);
// Step 2.3: If cleanly is false, then cleanup transport with error, and
// abort these steps.
ErrorResult errorresult;
if (!aCleanly) {
Cleanup(error, nullptr, errorresult);
return;
}
// Step 2.4: Let closeInfo be a new WebTransportCloseInfo.
// Step 2.5: If code is given, set closeInfos closeCode to code.
// Step 2.6: If reasonBytes is given, set closeInfos reason to reasonBytes,
// UTF-8 decoded.
WebTransportCloseInfo closeinfo;
closeinfo.mCloseCode = aCode;
closeinfo.mReason = aReason;
// Step 2.7: Cleanup transport with error and closeInfo.
Cleanup(error, &closeinfo, errorresult);
promise->MaybeResolve(mState == WebTransportState::CLOSED);
return promise.forget();
}
void WebTransport::Close(const WebTransportCloseInfo& aOptions,
@ -471,6 +374,7 @@ void WebTransport::Close(const WebTransportCloseInfo& aOptions,
mState == WebTransportState::FAILED) {
return;
}
MOZ_ASSERT(mChild);
// Step 3: If transport.[[State]] is "connecting":
if (mState == WebTransportState::CONNECTING) {
// Step 3.1: Let error be the result of creating a WebTransportError with
@ -481,11 +385,9 @@ void WebTransport::Close(const WebTransportCloseInfo& aOptions,
// Step 3.2: Cleanup transport with error.
Cleanup(error, nullptr, aRv);
// Step 3.3: Abort these steps.
MOZ_ASSERT(!mChild);
return;
}
LOG(("Sending Close"));
MOZ_ASSERT(mChild);
// Step 4: Let session be transport.[[Session]].
// Step 5: Let code be closeInfo.closeCode.
// Step 6: "Let reasonString be the maximal code unit prefix of
@ -507,7 +409,6 @@ void WebTransport::Close(const WebTransportCloseInfo& aOptions,
RewindToPriorUTF8Codepoint(aOptions.mReason.get(), 1024u)));
} else {
mChild->SendClose(aOptions.mCloseCode, aOptions.mReason);
LOG(("Close sent"));
}
// Step 9: Cleanup transport with AbortError and closeInfo. (sets mState to
@ -516,78 +417,26 @@ void WebTransport::Close(const WebTransportCloseInfo& aOptions,
new WebTransportError("close()"_ns, WebTransportErrorSource::Session,
DOMException_Binding::ABORT_ERR);
Cleanup(error, &aOptions, aRv);
LOG(("Cleanup done"));
// The other side will call `Close()` for us now, make sure we don't call it
// in our destructor.
mChild->Shutdown(false);
// This also causes IPC to drop the reference to us, allowing us to be
// GC'd (spec 5.8)
mChild->Shutdown();
mChild = nullptr;
LOG(("Close done"));
}
already_AddRefed<WebTransportDatagramDuplexStream> WebTransport::GetDatagrams(
ErrorResult& aError) {
already_AddRefed<WebTransportDatagramDuplexStream> WebTransport::Datagrams() {
LOG(("Datagrams() called"));
aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
// XXX not implemented
return nullptr;
}
already_AddRefed<Promise> WebTransport::CreateBidirectionalStream(
const WebTransportSendStreamOptions& aOptions, ErrorResult& aRv) {
ErrorResult& aError) {
LOG(("CreateBidirectionalStream() called"));
// https://w3c.github.io/webtransport/#dom-webtransport-createbidirectionalstream
RefPtr<Promise> promise = Promise::CreateInfallible(GetParentObject());
// Step 2: If transport.[[State]] is "closed" or "failed", return a new
// rejected promise with an InvalidStateError.
if (mState == WebTransportState::CLOSED ||
mState == WebTransportState::FAILED) {
aRv.ThrowInvalidStateError("WebTransport close or failed");
return nullptr;
}
// Step 3: Let sendOrder be options's sendOrder.
Maybe<int64_t> sendOrder;
if (!aOptions.mSendOrder.IsNull()) {
sendOrder = Some(aOptions.mSendOrder.Value());
}
// Step 4: Let p be a new promise.
// Step 5: Run the following steps in parallel, but abort them whenever
// transports [[State]] becomes "closed" or "failed", and instead queue
// a network task with transport to reject p with an InvalidStateError.
// Ask the parent to create the stream and send us the DataPipeSender/Receiver
// pair
mChild->SendCreateBidirectionalStream(
sendOrder,
[self = RefPtr{this}, promise](
BidirectionalStreamResponse&& aPipes) MOZ_CAN_RUN_SCRIPT_BOUNDARY {
LOG(("CreateBidirectionalStream response"));
// Step 5.2.1: If transport.[[State]] is "closed" or "failed",
// reject p with an InvalidStateError and abort these steps.
if (self->mState == WebTransportState::CLOSED ||
self->mState == WebTransportState::FAILED) {
promise->MaybeRejectWithInvalidStateError(
"Transport close/errored before CreateBidirectional finished");
return;
}
ErrorResult error;
RefPtr<WebTransportBidirectionalStream> newStream =
WebTransportBidirectionalStream::Create(
self, self->mGlobal,
aPipes.get_BidirectionalStream().inStream(),
aPipes.get_BidirectionalStream().outStream(), error);
LOG(("Returning a bidirectionalStream"));
promise->MaybeResolve(newStream);
},
[self = RefPtr{this}, promise](mozilla::ipc::ResponseRejectReason) {
LOG(("CreateBidirectionalStream reject"));
promise->MaybeRejectWithInvalidStateError(
"Transport close/errored before CreateBidirectional started");
});
// Step 6: return p
return promise.forget();
aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
return nullptr;
}
already_AddRefed<ReadableStream> WebTransport::IncomingBidirectionalStreams() {
@ -595,74 +444,10 @@ already_AddRefed<ReadableStream> WebTransport::IncomingBidirectionalStreams() {
}
already_AddRefed<Promise> WebTransport::CreateUnidirectionalStream(
const WebTransportSendStreamOptions& aOptions, ErrorResult& aRv) {
ErrorResult& aError) {
LOG(("CreateUnidirectionalStream() called"));
// https://w3c.github.io/webtransport/#dom-webtransport-createunidirectionalstream
// Step 2: If transport.[[State]] is "closed" or "failed", return a new
// rejected promise with an InvalidStateError.
if (mState == WebTransportState::CLOSED ||
mState == WebTransportState::FAILED) {
aRv.ThrowInvalidStateError("WebTransport close or failed");
return nullptr;
}
// Step 3: Let sendOrder be options's sendOrder.
Maybe<int64_t> sendOrder;
if (!aOptions.mSendOrder.IsNull()) {
sendOrder = Some(aOptions.mSendOrder.Value());
}
// Step 4: Let p be a new promise.
RefPtr<Promise> promise = Promise::CreateInfallible(GetParentObject());
// Step 5: Run the following steps in parallel, but abort them whenever
// transports [[State]] becomes "closed" or "failed", and instead queue
// a network task with transport to reject p with an InvalidStateError.
// Ask the parent to create the stream and send us the DataPipeSender
mChild->SendCreateUnidirectionalStream(
sendOrder,
[self = RefPtr{this},
promise](RefPtr<::mozilla::ipc::DataPipeSender>&& aPipe)
MOZ_CAN_RUN_SCRIPT_BOUNDARY {
LOG(("CreateUnidirectionalStream response"));
// Step 5.1: Let internalStream be the result of creating an
// outgoing unidirectional stream with transport.[[Session]].
// Step 5.2: Queue a network task with transport to run the
// following steps:
// Step 5.2.1 If transport.[[State]] is "closed" or "failed",
// reject p with an InvalidStateError and abort these steps.
if (self->mState == WebTransportState::CLOSED ||
self->mState == WebTransportState::FAILED) {
promise->MaybeRejectWithInvalidStateError(
"Transport close/errored during CreateUnidirectional");
return;
}
// Step 5.2.2.: Let stream be the result of creating a
// WebTransportSendStream with internalStream, transport, and
// sendOrder.
ErrorResult error;
RefPtr<WebTransportSendStream> writableStream =
WebTransportSendStream::Create(self, self->mGlobal, aPipe,
error);
if (!writableStream) {
promise->MaybeReject(std::move(error));
return;
}
LOG(("Returning a writableStream"));
// https://w3c.github.io/webtransport/#send-stream-procedures step 7
self->mSendStreams.AppendElement(writableStream);
// Step 5.2.3: Resolve p with stream.
promise->MaybeResolve(writableStream);
},
[self = RefPtr{this}, promise](mozilla::ipc::ResponseRejectReason) {
LOG(("CreateUnidirectionalStream reject"));
promise->MaybeRejectWithInvalidStateError(
"Transport close/errored during CreateUnidirectional");
});
// Step 6: return p
return promise.forget();
aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
return nullptr;
}
already_AddRefed<ReadableStream> WebTransport::IncomingUnidirectionalStreams() {
@ -685,10 +470,9 @@ void WebTransport::Cleanup(WebTransportError* aError,
// transport.[[IncomingUnidirectionalStreams]].
// Step 7: Set transport.[[SendStreams]] to an empty set.
// Step 8: Set transport.[[ReceiveStreams]] to an empty set.
LOG(("Cleanup started"));
nsTArray<RefPtr<WebTransportSendStream>> sendStreams;
nsTArray<RefPtr<WritableStream>> sendStreams;
sendStreams.SwapElements(mSendStreams);
nsTArray<RefPtr<WebTransportReceiveStream>> receiveStreams;
nsTArray<RefPtr<ReadableStream>> receiveStreams;
receiveStreams.SwapElements(mReceiveStreams);
// Step 9: If closeInfo is given, then set transport.[[State]] to "closed".
@ -721,8 +505,7 @@ void WebTransport::Cleanup(WebTransportError* aError,
// Step 12:
if (aCloseInfo) {
// 12.1: Resolve closed with closeInfo.
LOG(("Resolving mClosed with closeinfo"));
mClosed->MaybeResolve(*aCloseInfo);
mClosed->MaybeResolve(aCloseInfo);
// 12.2: Assert: ready is settled.
MOZ_ASSERT(mReady->State() != Promise::PromiseState::Pending);
// 12.3: Close incomingBidirectionalStreams
@ -735,7 +518,6 @@ void WebTransport::Cleanup(WebTransportError* aError,
} else {
// Step 13
// 13.1: Reject closed with error
LOG(("Rejecting mClosed"));
mClosed->MaybeReject(errorValue);
// 13.2: Reject ready with error
mReady->MaybeReject(errorValue);
@ -744,9 +526,9 @@ void WebTransport::Cleanup(WebTransportError* aError,
// 13.4: Error incomingUnidirectionalStreams with error
mIncomingUnidirectionalStreams->ErrorNative(cx, errorValue, IgnoreErrors());
}
// Let go of the algorithms
mIncomingBidirectionalAlgorithm = nullptr;
mIncomingUnidirectionalAlgorithm = nullptr;
// abort any pending pulls from Incoming*Streams (not in spec)
mIncomingUnidirectionalPromise->MaybeResolveWithUndefined();
mIncomingBidirectionalPromise->MaybeResolveWithUndefined();
}
} // namespace mozilla::dom

Просмотреть файл

@ -8,15 +8,11 @@
#define DOM_WEBTRANSPORT_API_WEBTRANSPORT__H_
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "nsISupports.h"
#include "nsWrapperCache.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/WebTransportBinding.h"
#include "mozilla/dom/WebTransportChild.h"
#include "mozilla/dom/WebTransportSendStream.h"
#include "mozilla/dom/WebTransportReceiveStream.h"
#include "mozilla/dom/WebTransportStreams.h"
#include "mozilla/ipc/DataPipe.h"
namespace mozilla::dom {
@ -27,14 +23,8 @@ class WebTransportIncomingStreamsAlgorithms;
class ReadableStream;
class WritableStream;
using BidirectionalPair = std::pair<RefPtr<mozilla::ipc::DataPipeReceiver>,
RefPtr<mozilla::ipc::DataPipeSender>>;
class WebTransport final : public nsISupports, public nsWrapperCache {
friend class WebTransportIncomingStreamsAlgorithms;
// For mSendStreams/mReceiveStreams
friend class WebTransportSendStream;
friend class WebTransportReceiveStream;
public:
explicit WebTransport(nsIGlobalObject* aGlobal);
@ -52,7 +42,7 @@ class WebTransport final : public nsISupports, public nsWrapperCache {
ErrorResult& aError);
void ResolveWaitingConnection(WebTransportReliabilityMode aReliability,
WebTransportChild* aChild);
void RejectWaitingConnection(nsresult aRv, WebTransportChild* aChild);
void RejectWaitingConnection(nsresult aRv);
bool ParseURL(const nsAString& aURL) const;
// this calls CloseNative(), which doesn't actually run script. See bug
// 1810942
@ -68,8 +58,6 @@ class WebTransport final : public nsISupports, public nsWrapperCache {
void NewUnidirectionalStream(
const RefPtr<mozilla::ipc::DataPipeReceiver>& aStream);
void RemoteClosed(bool aCleanly, const uint32_t& aCode,
const nsACString& aReason);
// WebIDL Boilerplate
nsIGlobalObject* GetParentObject() const;
@ -86,17 +74,14 @@ class WebTransport final : public nsISupports, public nsWrapperCache {
already_AddRefed<Promise> Ready() { return do_AddRef(mReady); }
WebTransportReliabilityMode Reliability();
WebTransportCongestionControl CongestionControl();
already_AddRefed<Promise> Closed() { return do_AddRef(mClosed); }
already_AddRefed<Promise> Closed();
MOZ_CAN_RUN_SCRIPT void Close(const WebTransportCloseInfo& aOptions,
ErrorResult& aRv);
already_AddRefed<WebTransportDatagramDuplexStream> GetDatagrams(
ErrorResult& aRv);
already_AddRefed<Promise> CreateBidirectionalStream(
const WebTransportSendStreamOptions& aOptions, ErrorResult& aRv);
already_AddRefed<Promise> CreateUnidirectionalStream(
const WebTransportSendStreamOptions& aOptions, ErrorResult& aRv);
already_AddRefed<WebTransportDatagramDuplexStream> Datagrams();
already_AddRefed<Promise> CreateBidirectionalStream(ErrorResult& aError);
MOZ_CAN_RUN_SCRIPT_BOUNDARY already_AddRefed<ReadableStream>
IncomingBidirectionalStreams();
already_AddRefed<Promise> CreateUnidirectionalStream(ErrorResult& aError);
MOZ_CAN_RUN_SCRIPT_BOUNDARY already_AddRefed<ReadableStream>
IncomingUnidirectionalStreams();
@ -122,22 +107,14 @@ class WebTransport final : public nsISupports, public nsWrapperCache {
// each sendStream in sendStreams, error sendStream with error."
// XXX Use nsTArray.h for now, but switch to OrderHashSet/Table for release to
// improve remove performance (if needed)
nsTArray<RefPtr<WebTransportSendStream>> mSendStreams;
nsTArray<RefPtr<WebTransportReceiveStream>> mReceiveStreams;
nsTArray<RefPtr<WritableStream>> mSendStreams;
nsTArray<RefPtr<ReadableStream>> mReceiveStreams;
WebTransportState mState;
RefPtr<Promise> mReady;
// XXX may not need to be a RefPtr, since we own it through the Streams
RefPtr<WebTransportIncomingStreamsAlgorithms> mIncomingBidirectionalAlgorithm;
RefPtr<WebTransportIncomingStreamsAlgorithms>
mIncomingUnidirectionalAlgorithm;
RefPtr<Promise> mIncomingUnidirectionalPromise;
RefPtr<Promise> mIncomingBidirectionalPromise;
WebTransportReliabilityMode mReliability;
// Incoming streams get queued here. Use a TArray though it's working as
// a FIFO - rarely will there be more than one entry in these arrays, so
// the overhead of mozilla::Queue is unneeded
nsTArray<RefPtr<mozilla::ipc::DataPipeReceiver>> mUnidirectionalStreams;
nsTArray<UniquePtr<BidirectionalPair>> mBidirectionalStreams;
// These are created in the constructor
RefPtr<ReadableStream> mIncomingUnidirectionalStreams;
RefPtr<ReadableStream> mIncomingBidirectionalStreams;

Просмотреть файл

@ -9,10 +9,7 @@
namespace mozilla::dom {
using namespace mozilla::ipc;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebTransportBidirectionalStream, mGlobal,
mReadable, mWritable)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebTransportBidirectionalStream, mGlobal)
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebTransportBidirectionalStream)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebTransportBidirectionalStream)
@ -32,35 +29,6 @@ JSObject* WebTransportBidirectionalStream::WrapObject(
return WebTransportBidirectionalStream_Binding::Wrap(aCx, this, aGivenProto);
}
// static
already_AddRefed<WebTransportBidirectionalStream>
WebTransportBidirectionalStream::Create(WebTransport* aWebTransport,
nsIGlobalObject* aGlobal,
DataPipeReceiver* receiver,
DataPipeSender* sender,
ErrorResult& aRv) {
// https://w3c.github.io/webtransport/#pullbidirectionalstream (and
// createBidirectionalStream)
// Step 7.1: Let stream be the result of creating a
// WebTransportBidirectionalStream with internalStream and transport
RefPtr<WebTransportReceiveStream> readableStream =
WebTransportReceiveStream::Create(aWebTransport, aGlobal, receiver, aRv);
if (!readableStream) {
return nullptr;
}
RefPtr<WebTransportSendStream> writableStream =
WebTransportSendStream::Create(aWebTransport, aGlobal, sender, aRv);
if (!writableStream) {
return nullptr;
;
}
auto stream = MakeRefPtr<WebTransportBidirectionalStream>(
aGlobal, readableStream, writableStream);
return stream.forget();
}
// WebIDL Interface
} // namespace mozilla::dom

Просмотреть файл

@ -22,19 +22,12 @@ namespace mozilla::dom {
class WebTransportBidirectionalStream final : public nsISupports,
public nsWrapperCache {
public:
explicit WebTransportBidirectionalStream(nsIGlobalObject* aGlobal,
WebTransportReceiveStream* aReadable,
WebTransportSendStream* aWritable)
: mGlobal(aGlobal), mReadable(aReadable), mWritable(aWritable) {}
explicit WebTransportBidirectionalStream(nsIGlobalObject* aGlobal)
: mGlobal(aGlobal) {}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(WebTransportBidirectionalStream)
static already_AddRefed<WebTransportBidirectionalStream> Create(
WebTransport* aWebTransport, nsIGlobalObject* aGlobal,
::mozilla::ipc::DataPipeReceiver* receiver,
::mozilla::ipc::DataPipeSender* sender, ErrorResult& aRv);
// WebIDL Boilerplate
nsIGlobalObject* GetParentObject() const;
@ -42,19 +35,16 @@ class WebTransportBidirectionalStream final : public nsISupports,
JS::Handle<JSObject*> aGivenProto) override;
// WebIDL Interface
already_AddRefed<WebTransportReceiveStream> Readable() const {
return do_AddRef(mReadable);
}
already_AddRefed<WebTransportSendStream> Writable() const {
return do_AddRef(mWritable);
}
// XXX spec says these should be WebTransportReceiveStream and
// WebTransportSendStream
// XXX Not implemented
already_AddRefed<ReadableStream> Readable() { return nullptr; }
already_AddRefed<WritableStream> Writable() { return nullptr; }
private:
~WebTransportBidirectionalStream() = default;
nsCOMPtr<nsIGlobalObject> mGlobal;
RefPtr<WebTransportReceiveStream> mReadable;
RefPtr<WebTransportSendStream> mWritable;
};
} // namespace mozilla::dom

Просмотреть файл

@ -8,29 +8,16 @@
namespace mozilla::dom {
JSObject* WebTransportError::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return WebTransportError_Binding::Wrap(aCx, this, aGivenProto);
}
/* static */
already_AddRefed<WebTransportError> WebTransportError::Constructor(
const GlobalObject& aGlobal, const WebTransportErrorInit& aInit) {
// https://w3c.github.io/webtransport/#web-transport-error-constructor1
// Step 2: Let message be init.message if it exists, and "" otherwise.
nsCString message(""_ns);
if (aInit.mMessage.WasPassed()) {
CopyUTF16toUTF8(aInit.mMessage.Value(), message);
}
// Step 1: Let error be this.
// Step 3: Set up error with message and "stream".
RefPtr<WebTransportError> error(new WebTransportError(message));
// Step 4: Set error.[[StreamErrorCode]] to init.streamErrorCode if it exists.
if (aInit.mStreamErrorCode.WasPassed()) {
error->mStreamErrorCode = Nullable(aInit.mStreamErrorCode.Value());
error->mStreamErrorCode = aInit.mStreamErrorCode.Value();
}
return error.forget();
}

Просмотреть файл

@ -16,22 +16,21 @@ class WebTransportError final : public DOMException {
explicit WebTransportError(
const nsACString& aMessage,
WebTransportErrorSource aSource = WebTransportErrorSource::Stream,
Nullable<uint8_t> aCode = Nullable<uint8_t>())
uint8_t aCode = 0)
: DOMException(NS_OK, aMessage, "WebTransportError"_ns, 0),
mStreamErrorCode(aCode),
mSource(aSource) {}
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<WebTransportError> Constructor(
const GlobalObject& aGlobal, const WebTransportErrorInit& aInit);
WebTransportErrorSource Source() { return mSource; }
Nullable<uint8_t> GetStreamErrorCode() const { return mStreamErrorCode; }
Nullable<uint8_t> GetStreamErrorCode() const {
return Nullable<uint8_t>(mStreamErrorCode);
}
private:
Nullable<uint8_t> mStreamErrorCode;
uint8_t mStreamErrorCode;
const WebTransportErrorSource mSource;
};

Просмотреть файл

@ -1,58 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/WebTransportReceiveStream.h"
#include "mozilla/dom/ReadableByteStreamController.h"
#include "mozilla/dom/UnderlyingSourceCallbackHelpers.h"
#include "mozilla/dom/ReadableStream.h"
using namespace mozilla::ipc;
namespace mozilla::dom {
WebTransportReceiveStream::WebTransportReceiveStream(nsIGlobalObject* aGlobal)
: ReadableStream(aGlobal) {}
// WebIDL Boilerplate
JSObject* WebTransportReceiveStream::WrapObject(
JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
return WebTransportReceiveStream_Binding::Wrap(aCx, this, aGivenProto);
}
already_AddRefed<WebTransportReceiveStream> WebTransportReceiveStream::Create(
WebTransport* aWebTransport, nsIGlobalObject* aGlobal,
DataPipeReceiver* receiver, ErrorResult& aRv) {
// https://w3c.github.io/webtransport/#webtransportreceivestream-create
AutoJSAPI jsapi;
if (!jsapi.Init(aGlobal)) {
return nullptr;
}
JSContext* cx = jsapi.cx();
auto stream = MakeRefPtr<WebTransportReceiveStream>(aGlobal);
nsCOMPtr<nsIAsyncInputStream> inputStream = receiver;
auto algorithms = MakeRefPtr<InputToReadableStreamAlgorithms>(
inputStream, (ReadableStream*)stream);
stream->SetUpByteNative(cx, *algorithms, Some(0.0), aRv);
if (aRv.Failed()) {
return nullptr;
}
// Add to ReceiveStreams
aWebTransport->mReceiveStreams.AppendElement(stream);
return stream.forget();
}
already_AddRefed<Promise> WebTransportReceiveStream::GetStats() {
RefPtr<Promise> promise = Promise::CreateInfallible(ReadableStream::mGlobal);
promise->MaybeRejectWithNotSupportedError("GetStats isn't supported yet");
return promise.forget();
}
} // namespace mozilla::dom

Просмотреть файл

@ -4,34 +4,36 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOM_WEBTRANSPORT_API_WEBTRANSPORTRECEIVESTREAM__H_
#define DOM_WEBTRANSPORT_API_WEBTRANSPORTRECEIVESTREAM__H_
#ifndef DOM_WEBTRANSPORT_API_WEBTRANSPORTSENDSTREAM__H_
#define DOM_WEBTRANSPORT_API_WEBTRANSPORTSENDSTREAM__H_
#include "mozilla/dom/ReadableStream.h"
#if WEBTRANSPORT_STREAM_IMPLEMENTED
namespace mozilla::dom {
class WebTransportReceiveStream final : public ReadableStream {
protected:
WebTransportReceiveStream();
public:
NS_INLINE_DECL_REFCOUNTING_INHERITED(WebTransportReceiveStream,
ReadableStream)
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WebTransportReceiveStream,
ReadableStream)
explicit WebTransportReceiveStream(nsIGlobalObject* aGlobal);
MOZ_CAN_RUN_SCRIPT_BOUNDARY static already_AddRefed<WebTransportReceiveStream>
Create(WebTransport* aWebTransport, nsIGlobalObject* aGlobal,
mozilla::ipc::DataPipeReceiver* receiver, ErrorResult& aRv);
// WebIDL Boilerplate
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
// WebIDL Interface
already_AddRefed<Promise> GetStats();
private:
~WebTransportReceiveStream() override = default;
};
} // namespace mozilla::dom
#else
namespace mozilla::dom {
class WebTransportReceiveStream final : public nsISupports {
protected:
WebTransportReceiveStream();
public:
NS_DECL_ISUPPORTS
already_AddRefed<Promise> GetStats();
};
#endif
}
#endif

Просмотреть файл

@ -1,69 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/WebTransportSendStream.h"
#include "mozilla/dom/UnderlyingSinkCallbackHelpers.h"
#include "mozilla/dom/WritableStream.h"
using namespace mozilla::ipc;
namespace mozilla::dom {
WebTransportSendStream::WebTransportSendStream(nsIGlobalObject* aGlobal)
: WritableStream(aGlobal,
WritableStream::HoldDropJSObjectsCaller::Implicit) {}
JSObject* WebTransportSendStream::WrapObject(
JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
return WebTransportSendStream_Binding::Wrap(aCx, this, aGivenProto);
}
// NOTE: this does not yet implement SendOrder; see bug 1816925
/* static */
already_AddRefed<WebTransportSendStream> WebTransportSendStream::Create(
WebTransport* aWebTransport, nsIGlobalObject* aGlobal,
DataPipeSender* sender, ErrorResult& aRv) {
// https://w3c.github.io/webtransport/#webtransportsendstream-create
AutoJSAPI jsapi;
if (!jsapi.Init(aGlobal)) {
return nullptr;
}
JSContext* cx = jsapi.cx();
auto stream = MakeRefPtr<WebTransportSendStream>(aGlobal);
nsCOMPtr<nsIAsyncOutputStream> outputStream = sender;
auto algorithms = MakeRefPtr<WritableStreamToOutput>(
stream->GetParentObject(), outputStream);
// Steps 2-5
RefPtr<QueuingStrategySize> writableSizeAlgorithm;
stream->SetUpNative(cx, *algorithms, Nothing(), writableSizeAlgorithm, aRv);
// Step 6: Add the following steps to streams [[controller]]'s [[signal]].
// Step 6.1: If stream.[[PendingOperation]] is null, then abort these steps.
// Step 6.2: Let reason be streams [[controller]]'s [[signal]]'s abort
// reason. Step 6.3: Let abortPromise be the result of aborting stream with
// reason. Step 6.4: Upon fulfillment of abortPromise, reject promise with
// reason. Step 6.5: Let pendingOperation be stream.[[PendingOperation]].
// Step 6.6: Set stream.[[PendingOperation]] to null.
// Step 6.7: Resolve pendingOperation with promise.
// XXX TODO
// Step 7: Append stream to SendStreams
aWebTransport->mSendStreams.AppendElement(stream);
// Step 8: return stream
return stream.forget();
}
already_AddRefed<Promise> WebTransportSendStream::GetStats() {
RefPtr<Promise> promise = Promise::CreateInfallible(WritableStream::mGlobal);
promise->MaybeRejectWithNotSupportedError("GetStats isn't supported yet");
return promise.forget();
}
} // namespace mozilla::dom

Просмотреть файл

@ -9,28 +9,31 @@
#include "mozilla/dom/WritableStream.h"
#if WEBTRANSPORT_STREAM_IMPLEMENTED
namespace mozilla::dom {
class WebTransportSendStream final : public WritableStream {
protected:
WebTransportSendStream();
public:
NS_INLINE_DECL_REFCOUNTING_INHERITED(WebTransportSendStream, WritableStream)
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WebTransportSendStream,
WritableStream)
explicit WebTransportSendStream(nsIGlobalObject* aGlobal);
MOZ_CAN_RUN_SCRIPT_BOUNDARY static already_AddRefed<WebTransportSendStream>
Create(WebTransport* aWebTransport, nsIGlobalObject* aGlobal,
mozilla::ipc::DataPipeSender* sender, ErrorResult& aRv);
// WebIDL Boilerplate
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
// WebIDL Interface
already_AddRefed<Promise> GetStats();
private:
~WebTransportSendStream() override = default;
};
} // namespace mozilla::dom
#else
namespace mozilla::dom {
class WebTransportSendStream final : public nsISupports {
protected:
WebTransportSendStream();
public:
NS_DECL_ISUPPORTS
already_AddRefed<Promise> GetStats();
};
#endif
}
#endif

Просмотреть файл

@ -6,19 +6,14 @@
#include "mozilla/dom/WebTransportStreams.h"
#include "mozilla/dom/WebTransportLog.h"
#include "mozilla/dom/Promise-inl.h"
#include "mozilla/dom/WebTransport.h"
#include "mozilla/dom/WebTransportReceiveStream.h"
#include "mozilla/dom/WebTransportSendStream.h"
#include "mozilla/Result.h"
using namespace mozilla::ipc;
namespace mozilla::dom {
NS_IMPL_CYCLE_COLLECTION_INHERITED(WebTransportIncomingStreamsAlgorithms,
UnderlyingSourceAlgorithmsWrapper,
mTransport, mCallback)
UnderlyingSourceAlgorithmsWrapper, mStream)
NS_IMPL_ADDREF_INHERITED(WebTransportIncomingStreamsAlgorithms,
UnderlyingSourceAlgorithmsWrapper)
NS_IMPL_RELEASE_INHERITED(WebTransportIncomingStreamsAlgorithms,
@ -26,10 +21,6 @@ NS_IMPL_RELEASE_INHERITED(WebTransportIncomingStreamsAlgorithms,
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebTransportIncomingStreamsAlgorithms)
NS_INTERFACE_MAP_END_INHERITING(UnderlyingSourceAlgorithmsWrapper)
WebTransportIncomingStreamsAlgorithms::WebTransportIncomingStreamsAlgorithms(
StreamType aUnidirectional, WebTransport* aTransport)
: mUnidirectional(aUnidirectional), mTransport(aTransport) {}
WebTransportIncomingStreamsAlgorithms::
~WebTransportIncomingStreamsAlgorithms() = default;
@ -38,153 +29,42 @@ WebTransportIncomingStreamsAlgorithms::PullCallbackImpl(
JSContext* aCx, ReadableStreamController& aController, ErrorResult& aRv) {
// https://w3c.github.io/webtransport/#pullbidirectionalstream and
// https://w3c.github.io/webtransport/#pullunidirectionalstream
// pullUnidirectionalStream Step 1: If WebTransport state is CONNECTING,
// return a promise and resolve or reject on state change
// Step 1: If transport.[[State]] is "connecting", then return the result
// of performing the following steps upon fulfillment of
// transport.[[Ready]]:
// We don't explicitly check mState here, since we'll reject
// We don't explicitly check Ready here, since we'll reject
// mIncomingStreamPromise if we go to FAILED or CLOSED
//
// Step 2: Let session be transport.[[Session]].
// Step 3: Let p be a new promise.
RefPtr<Promise> promise =
Promise::CreateInfallible(mTransport->GetParentObject());
// Step 2
RefPtr<Promise> promise = Promise::Create(mStream->GetParentObject(), aRv);
RefPtr<WebTransportIncomingStreamsAlgorithms> self(this);
// The real work of PullCallback()
// Step 5: Wait until there is an available incoming unidirectional stream.
if (mTransport->mUnidirectionalStreams.Length() == 0) {
// We need to wait.
// Per
// https://streams.spec.whatwg.org/#readablestreamdefaultcontroller-pulling
// we can't be called again until the promise is resolved
MOZ_ASSERT(!mCallback);
mCallback = promise;
LOG(("Incoming%sDirectionalStreams Pull waiting for a stream",
mUnidirectional == StreamType::Unidirectional ? "Uni" : "Bi"));
Result<RefPtr<Promise>, nsresult> returnResult =
promise->ThenWithCycleCollectedArgs(
[](JSContext* aCx, JS::Handle<JS::Value>, ErrorResult& aRv,
RefPtr<WebTransportIncomingStreamsAlgorithms> self,
RefPtr<Promise> aPromise) -> already_AddRefed<Promise> {
self->BuildStream(aCx, aRv);
return nullptr;
},
self, promise);
if (returnResult.isErr()) {
// XXX Reject?
aRv.Throw(returnResult.unwrapErr());
return nullptr;
}
// Step 4: Return p and run the remaining steps in parallel.
return returnResult.unwrap().forget();
}
self->BuildStream(aCx, aRv);
// Step 4: Return p and run the remaining steps in parallel.
return promise.forget();
}
// Note: fallible
void WebTransportIncomingStreamsAlgorithms::BuildStream(JSContext* aCx,
ErrorResult& aRv) {
// https://w3c.github.io/webtransport/#pullbidirectionalstream and
// https://w3c.github.io/webtransport/#pullunidirectionalstream
LOG(("Incoming%sDirectionalStreams Pull building a stream",
mUnidirectional == StreamType::Unidirectional ? "Uni" : "Bi"));
if (mUnidirectional == StreamType::Unidirectional) {
// Step 6: Let internalStream be the result of receiving an incoming
// unidirectional stream.
MOZ_ASSERT(mTransport->mUnidirectionalStreams.Length() > 0);
RefPtr<DataPipeReceiver> pipe = mTransport->mUnidirectionalStreams[0];
mTransport->mUnidirectionalStreams.RemoveElementAt(0);
// Step 7.1: Let stream be the result of creating a
// WebTransportReceiveStream with internalStream and transport
RefPtr<WebTransportReceiveStream> readableStream =
WebTransportReceiveStream::Create(mTransport, mTransport->mGlobal, pipe,
aRv);
if (MOZ_UNLIKELY(!readableStream)) {
aRv.ThrowUnknownError("Internal error");
return;
}
// Step 7.2 Enqueue stream to transport.[[IncomingUnidirectionalStreams]].
JS::Rooted<JS::Value> jsStream(aCx);
if (MOZ_UNLIKELY(!ToJSValue(aCx, readableStream, &jsStream))) {
aRv.ThrowUnknownError("Internal error");
return;
}
// EnqueueNative is CAN_RUN_SCRIPT
RefPtr<ReadableStream> incomingStream =
mTransport->mIncomingUnidirectionalStreams;
incomingStream->EnqueueNative(aCx, jsStream, aRv);
if (MOZ_UNLIKELY(aRv.Failed())) {
aRv.ThrowUnknownError("Internal error");
return;
}
} else {
// Step 6: Let internalStream be the result of receiving a bidirectional
// stream
MOZ_ASSERT(mTransport->mBidirectionalStreams.Length() > 0);
UniquePtr<BidirectionalPair> pipes =
std::move(mTransport->mBidirectionalStreams.ElementAt(0));
mTransport->mBidirectionalStreams.RemoveElementAt(0);
RefPtr<DataPipeReceiver> input = pipes->first.forget();
RefPtr<DataPipeSender> output = pipes->second.forget();
RefPtr<WebTransportBidirectionalStream> stream =
WebTransportBidirectionalStream::Create(mTransport, mTransport->mGlobal,
input, output, aRv);
// Step 7.2 Enqueue stream to transport.[[IncomingBidirectionalStreams]].
JS::Rooted<JS::Value> jsStream(aCx);
if (MOZ_UNLIKELY(!ToJSValue(aCx, stream, &jsStream))) {
return;
}
LOG(("Enqueuing bidirectional stream\n"));
// EnqueueNative is CAN_RUN_SCRIPT
RefPtr<ReadableStream> incomingStream =
mTransport->mIncomingBidirectionalStreams;
incomingStream->EnqueueNative(aCx, jsStream, aRv);
if (MOZ_UNLIKELY(aRv.Failed())) {
return;
}
}
// Step 7.3: Resolve p with undefined.
}
void WebTransportIncomingStreamsAlgorithms::NotifyIncomingStream() {
if (mUnidirectional == StreamType::Unidirectional) {
LOG(("NotifyIncomingStream: %zu Unidirectional ",
mTransport->mUnidirectionalStreams.Length()));
#ifdef DEBUG
auto number = mTransport->mUnidirectionalStreams.Length();
MOZ_ASSERT(number > 0);
#endif
RefPtr<Promise> promise = mCallback.forget();
if (promise) {
promise->MaybeResolveWithUndefined();
}
} else {
LOG(("NotifyIncomingStream: %zu Bidirectional ",
mTransport->mBidirectionalStreams.Length()));
#ifdef DEBUG
auto number = mTransport->mBidirectionalStreams.Length();
MOZ_ASSERT(number > 0);
#endif
RefPtr<Promise> promise = mCallback.forget();
if (promise) {
promise->MaybeResolveWithUndefined();
}
}
}
void WebTransportIncomingStreamsAlgorithms::NotifyRejectAll() {
// cancel all pulls
LOG(("Cancel all WebTransport Pulls"));
// Ensure we clear the callback before resolving/rejecting it
if (RefPtr<Promise> promise = mCallback.forget()) {
promise->MaybeReject(NS_ERROR_FAILURE);
// Wait until there's an incoming stream (or rejection)
// Step 5
Result<RefPtr<Promise>, nsresult> returnResult =
mIncomingStreamPromise->ThenWithCycleCollectedArgs(
[](JSContext* aCx, JS::Handle<JS::Value>, ErrorResult& aRv,
const RefPtr<WebTransportIncomingStreamsAlgorithms>& self,
RefPtr<Promise> newPromise) {
Unused << self->mUnidirectional;
// XXX Use self->mUnidirectional here
// Step 6 Get new transport stream
// Step 7.1 create stream using transport stream
// Step 7.2 Enqueue
// Add to ReceiveStreams
// mStream->mReceiveStreams.AppendElement(stream);
// Step 7.3
newPromise->MaybeResolveWithUndefined();
return newPromise.forget();
},
self, promise);
if (returnResult.isErr()) {
// XXX Reject?
aRv.Throw(returnResult.unwrapErr());
return nullptr;
}
// Step 4
return returnResult.unwrap().forget();
}
} // namespace mozilla::dom

Просмотреть файл

@ -8,18 +8,19 @@
#define DOM_WEBTRANSPORT_API_WEBTRANSPORTSTREAMS__H_
#include "mozilla/dom/UnderlyingSourceCallbackHelpers.h"
#include "mozilla/dom/WritableStream.h"
namespace mozilla::dom {
class WebTransport;
class WebTransportIncomingStreamsAlgorithms
: public UnderlyingSourceAlgorithmsWrapper {
public:
enum class StreamType : uint8_t { Unidirectional, Bidirectional };
WebTransportIncomingStreamsAlgorithms(StreamType aUnidirectional,
WebTransport* aTransport);
WebTransportIncomingStreamsAlgorithms(Promise* aIncomingStreamPromise,
bool aUnidirectional,
WebTransport* aStream)
: mIncomingStreamPromise(aIncomingStreamPromise),
mUnidirectional(aUnidirectional),
mStream(aStream) {}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(
@ -29,21 +30,13 @@ class WebTransportIncomingStreamsAlgorithms
JSContext* aCx, ReadableStreamController& aController,
ErrorResult& aRv) override;
// We call EnqueueNative, which is MOZ_CAN_RUN_SCRIPT but won't in this case
MOZ_CAN_RUN_SCRIPT_BOUNDARY void BuildStream(JSContext* aCx,
ErrorResult& aRv);
void NotifyIncomingStream();
void NotifyRejectAll();
protected:
~WebTransportIncomingStreamsAlgorithms() override;
private:
const StreamType mUnidirectional;
RefPtr<WebTransport> mTransport;
RefPtr<Promise> mCallback;
RefPtr<Promise> mIncomingStreamPromise;
const bool mUnidirectional;
RefPtr<WebTransport> mStream;
};
} // namespace mozilla::dom

Просмотреть файл

@ -19,8 +19,6 @@ UNIFIED_SOURCES += [
"WebTransportBidirectionalStream.cpp",
"WebTransportDatagramDuplexStream.cpp",
"WebTransportError.cpp",
"WebTransportReceiveStream.cpp",
"WebTransportSendStream.cpp",
"WebTransportStreams.cpp",
]

Просмотреть файл

@ -10,14 +10,13 @@
namespace mozilla::dom {
void WebTransportChild::Shutdown(bool aClose) {
LOG(("WebTransportChild::Shutdown() for %p (%p)", this, mTransport));
mTransport = nullptr;
if (!aClose || !CanSend()) {
void WebTransportChild::Shutdown() {
if (!CanSend()) {
return;
}
Close();
mTransport = nullptr;
}
void WebTransportChild::CloseAll() {
@ -31,28 +30,16 @@ void WebTransportChild::CloseAll() {
return IPC_OK();
}
::mozilla::ipc::IPCResult WebTransportChild::RecvRemoteClosed(
const bool& aCleanly, const uint32_t& aCode, const nsACString& aReason) {
if (mTransport) {
mTransport->RemoteClosed(aCleanly, aCode, aReason);
}
return IPC_OK();
}
::mozilla::ipc::IPCResult WebTransportChild::RecvIncomingBidirectionalStream(
const RefPtr<DataPipeReceiver>& aIncoming,
const RefPtr<DataPipeSender>& aOutgoing) {
if (mTransport) {
mTransport->NewBidirectionalStream(aIncoming, aOutgoing);
}
mTransport->NewBidirectionalStream(aIncoming, aOutgoing);
return IPC_OK();
}
::mozilla::ipc::IPCResult WebTransportChild::RecvIncomingUnidirectionalStream(
const RefPtr<DataPipeReceiver>& aStream) {
if (mTransport) {
mTransport->NewUnidirectionalStream(aStream);
}
mTransport->NewUnidirectionalStream(aStream);
return IPC_OK();
}

Просмотреть файл

@ -23,14 +23,10 @@ class WebTransportChild : public PWebTransportChild {
virtual void CloseAll();
void Shutdown(bool aClose);
virtual void Shutdown();
::mozilla::ipc::IPCResult RecvCloseAll(CloseAllResolver&& aResolver);
::mozilla::ipc::IPCResult RecvRemoteClosed(const bool& aCleanly,
const uint32_t& aCode,
const nsACString& aReason);
::mozilla::ipc::IPCResult RecvIncomingBidirectionalStream(
const RefPtr<mozilla::ipc::DataPipeReceiver>& aIncoming,
const RefPtr<mozilla::ipc::DataPipeSender>& aOutgoing);

Просмотреть файл

@ -14,15 +14,12 @@
#include "nsIOService.h"
#include "nsIPrincipal.h"
#include "nsIWebTransport.h"
#include "nsStreamUtils.h"
#include "nsIWebTransportStream.h"
using IPCResult = mozilla::ipc::IPCResult;
namespace mozilla::dom {
NS_IMPL_ISUPPORTS(WebTransportParent, WebTransportSessionEventListener);
using IPCResult = mozilla::ipc::IPCResult;
using CreateWebTransportPromise =
MozPromise<WebTransportReliabilityMode, nsresult, true>;
WebTransportParent::~WebTransportParent() {
@ -35,7 +32,7 @@ void WebTransportParent::Create(
// Sequence<WebTransportHash>* aServerCertHashes,
Endpoint<PWebTransportParent>&& aParentEndpoint,
std::function<void(Tuple<const nsresult&, const uint8_t&>)>&& aResolver) {
LOG(("Created WebTransportParent %p %s %s %s congestion=%s", this,
LOG(("Created WebTransportParent %s %s %s congestion=%s",
NS_ConvertUTF16toUTF8(aURL).get(),
aDedicated ? "Dedicated" : "AllowPooling",
aRequireUnreliable ? "RequireUnreliable" : "",
@ -61,16 +58,19 @@ void WebTransportParent::Create(
return;
}
RefPtr<WebTransportParent> parent = new WebTransportParent();
MOZ_ASSERT(parent);
MOZ_DIAGNOSTIC_ASSERT(mozilla::net::gIOService);
nsresult rv =
mozilla::net::gIOService->NewWebTransport(getter_AddRefs(mWebTransport));
nsresult rv = mozilla::net::gIOService->NewWebTransport(
getter_AddRefs(parent->mWebTransport));
if (NS_FAILED(rv)) {
aResolver(ResolveType(
rv, static_cast<uint8_t>(WebTransportReliabilityMode::Pending)));
return;
}
mOwningEventTarget = GetCurrentSerialEventTarget();
parent->mOwningEventTarget = GetCurrentSerialEventTarget();
MOZ_ASSERT(aPrincipal);
nsCOMPtr<nsIURI> uri;
@ -84,25 +84,22 @@ void WebTransportParent::Create(
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
"WebTransport AsyncConnect",
[self = RefPtr{this}, uri = std::move(uri),
[self = RefPtr{parent}, uri = std::move(uri),
principal = RefPtr{aPrincipal},
flags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL] {
LOG(("WebTransport %p AsyncConnect", self.get()));
if (NS_FAILED(self->mWebTransport->AsyncConnect(uri, principal, flags,
self))) {
LOG(("AsyncConnect failure; we should get OnSessionClosed"));
}
self->mWebTransport->AsyncConnect(uri, principal, flags, self);
});
// Bind to SocketThread for IPC - connection creation/destruction must
// hit MainThread, but keep all other traffic on SocketThread. Note that
// we must call aResolver() on this (PBackground) thread.
mSocketThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
nsCOMPtr<nsISerialEventTarget> sts =
do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
MOZ_ASSERT(NS_SUCCEEDED(rv));
InvokeAsync(mSocketThread, __func__,
InvokeAsync(sts, __func__,
[parentEndpoint = std::move(aParentEndpoint), runnable = r,
resolver = std::move(aResolver), p = RefPtr{this}]() mutable {
resolver = std::move(aResolver), p = RefPtr{parent}]() mutable {
p->mResolver = resolver;
LOG(("Binding parent endpoint"));
@ -113,13 +110,12 @@ void WebTransportParent::Create(
// IPC now holds a ref to parent
// Send connection to the server via MainThread
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
return CreateWebTransportPromise::CreateAndResolve(
WebTransportReliabilityMode::Supports_unreliable, __func__);
})
->Then(
GetCurrentSerialEventTarget(), __func__,
[p = RefPtr{this}](
[p = RefPtr{parent}](
const CreateWebTransportPromise::ResolveOrRejectValue& aValue) {
if (aValue.IsReject()) {
p->mResolver(ResolveType(
@ -135,9 +131,9 @@ void WebTransportParent::ActorDestroy(ActorDestroyReason aWhy) {
// We may not receive this response if the child side is destroyed without
// `Close` or `Shutdown` being explicitly called.
IPCResult WebTransportParent::RecvClose(const uint32_t& aCode,
const nsACString& aReason) {
LOG(("Close for %p received, code = %u, reason = %s", this, aCode,
mozilla::ipc::IPCResult WebTransportParent::RecvClose(
const uint32_t& aCode, const nsACString& aReason) {
LOG(("Close received, code = %u, reason = %s", aCode,
PromiseFlatCString(aReason).get()));
MOZ_ASSERT(!mClosed);
mClosed.Flip();
@ -146,158 +142,6 @@ IPCResult WebTransportParent::RecvClose(const uint32_t& aCode,
return IPC_OK();
}
class ReceiveStream final : public nsIWebTransportStreamCallback {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIWEBTRANSPORTSTREAMCALLBACK
ReceiveStream(
WebTransportParent::CreateUnidirectionalStreamResolver&& aResolver,
nsCOMPtr<nsISerialEventTarget>& aSocketThread)
: mUniResolver(aResolver), mSocketThread(aSocketThread) {}
ReceiveStream(
WebTransportParent::CreateBidirectionalStreamResolver&& aResolver,
nsCOMPtr<nsISerialEventTarget>& aSocketThread)
: mBiResolver(aResolver), mSocketThread(aSocketThread) {}
private:
~ReceiveStream() = default;
std::function<void(::mozilla::ipc::DataPipeSender*)> mUniResolver;
WebTransportParent::CreateBidirectionalStreamResolver mBiResolver;
nsCOMPtr<nsISerialEventTarget> mSocketThread;
};
NS_IMPL_ISUPPORTS(ReceiveStream, nsIWebTransportStreamCallback)
// nsIWebTransportStreamCallback:
NS_IMETHODIMP ReceiveStream::OnBidirectionalStreamReady(
nsIWebTransportBidirectionalStream* aStream) {
LOG(("Bidirectional stream ready!"));
MOZ_ASSERT(mSocketThread->IsOnCurrentThread());
RefPtr<mozilla::ipc::DataPipeSender> inputsender;
RefPtr<mozilla::ipc::DataPipeReceiver> inputreceiver;
nsresult rv =
NewDataPipe(mozilla::ipc::kDefaultDataPipeCapacity,
getter_AddRefs(inputsender), getter_AddRefs(inputreceiver));
if (NS_WARN_IF(NS_FAILED(rv))) {
mBiResolver(rv);
return rv;
}
nsCOMPtr<nsIAsyncInputStream> inputStream;
aStream->GetInputStream(getter_AddRefs(inputStream));
MOZ_ASSERT(inputStream);
rv = NS_AsyncCopy(inputStream, inputsender, mSocketThread,
NS_ASYNCCOPY_VIA_WRITESEGMENTS, // can we use READSEGMENTS?
mozilla::ipc::kDefaultDataPipeCapacity, nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv))) {
mBiResolver(rv);
return rv;
}
RefPtr<mozilla::ipc::DataPipeSender> outputsender;
RefPtr<mozilla::ipc::DataPipeReceiver> outputreceiver;
rv =
NewDataPipe(mozilla::ipc::kDefaultDataPipeCapacity,
getter_AddRefs(outputsender), getter_AddRefs(outputreceiver));
if (NS_WARN_IF(NS_FAILED(rv))) {
mBiResolver(rv);
return rv;
}
nsCOMPtr<nsIAsyncOutputStream> outputStream;
aStream->GetOutputStream(getter_AddRefs(outputStream));
MOZ_ASSERT(outputStream);
rv = NS_AsyncCopy(outputreceiver, outputStream, mSocketThread,
NS_ASYNCCOPY_VIA_READSEGMENTS,
mozilla::ipc::kDefaultDataPipeCapacity, nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv))) {
mBiResolver(rv);
return rv;
}
LOG(("Returning BidirectionalStream pipe to content"));
mBiResolver(BidirectionalStream(inputreceiver, outputsender));
return NS_OK;
}
NS_IMETHODIMP
ReceiveStream::OnUnidirectionalStreamReady(nsIWebTransportSendStream* aStream) {
LOG(("Unidirectional stream ready!"));
// We should be on the Socket Thread
MOZ_ASSERT(mSocketThread->IsOnCurrentThread());
RefPtr<::mozilla::ipc::DataPipeSender> sender;
RefPtr<::mozilla::ipc::DataPipeReceiver> receiver;
nsresult rv = NewDataPipe(mozilla::ipc::kDefaultDataPipeCapacity,
getter_AddRefs(sender), getter_AddRefs(receiver));
if (NS_WARN_IF(NS_FAILED(rv))) {
mUniResolver(nullptr);
return rv;
}
nsCOMPtr<nsIAsyncOutputStream> outputStream;
aStream->GetOutputStream(getter_AddRefs(outputStream));
MOZ_ASSERT(outputStream);
rv = NS_AsyncCopy(receiver, outputStream, mSocketThread,
NS_ASYNCCOPY_VIA_READSEGMENTS,
mozilla::ipc::kDefaultDataPipeCapacity, nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv))) {
mUniResolver(nullptr);
return rv;
}
LOG(("Returning UnidirectionalStream pipe to content"));
// pass the DataPipeSender to the content process
mUniResolver(sender);
return NS_OK;
}
JS_HAZ_CAN_RUN_SCRIPT NS_IMETHODIMP ReceiveStream::OnError(uint8_t aError) {
nsresult rv = aError == nsIWebTransport::INVALID_STATE_ERROR
? NS_ERROR_DOM_INVALID_STATE_ERR
: NS_ERROR_FAILURE;
if (mUniResolver) {
mUniResolver(nullptr);
} else if (mBiResolver) {
mBiResolver(rv);
}
return NS_OK;
}
IPCResult WebTransportParent::RecvCreateUnidirectionalStream(
Maybe<int64_t> aSendOrder, CreateUnidirectionalStreamResolver&& aResolver) {
LOG(("%s for %p received, useSendOrder=%d, sendOrder=%" PRIi64, __func__,
this, aSendOrder.isSome(),
aSendOrder.isSome() ? aSendOrder.value() : 0));
RefPtr<ReceiveStream> callback =
new ReceiveStream(std::move(aResolver), mSocketThread);
nsresult rv;
rv = mWebTransport->CreateOutgoingUnidirectionalStream(callback);
if (NS_FAILED(rv)) {
callback->OnError(0); // XXX
}
return IPC_OK();
}
IPCResult WebTransportParent::RecvCreateBidirectionalStream(
Maybe<int64_t> aSendOrder, CreateBidirectionalStreamResolver&& aResolver) {
LOG(("%s for %p received, useSendOrder=%d, sendOrder=%" PRIi64, __func__,
this, aSendOrder.isSome(),
aSendOrder.isSome() ? aSendOrder.value() : 0));
RefPtr<ReceiveStream> callback =
new ReceiveStream(std::move(aResolver), mSocketThread);
nsresult rv;
rv = mWebTransport->CreateOutgoingBidirectionalStream(callback);
if (NS_FAILED(rv)) {
callback->OnError(0); // XXX
}
return IPC_OK();
}
// We recieve this notification from the WebTransportSessionProxy if session was
// successfully created at the end of
// WebTransportSessionProxy::OnStopRequest
@ -306,8 +150,7 @@ WebTransportParent::OnSessionReady(uint64_t aSessionId) {
MOZ_ASSERT(mOwningEventTarget);
MOZ_ASSERT(!mOwningEventTarget->IsOnCurrentThread());
LOG(("Created web transport session, sessionID = %" PRIu64 ", for %p",
aSessionId, this));
LOG(("Created web transport session, sessionID = %" PRIu64 "", aSessionId));
mOwningEventTarget->Dispatch(NS_NewRunnableFunction(
"WebTransportParent::OnSessionReady", [self = RefPtr{this}] {
@ -316,12 +159,6 @@ WebTransportParent::OnSessionReady(uint64_t aSessionId) {
NS_OK, static_cast<uint8_t>(
WebTransportReliabilityMode::Supports_unreliable)));
self->mResolver = nullptr;
} else {
if (self->IsClosed()) {
LOG(("Session already closed at OnSessionReady %p", self.get()));
} else {
LOG(("No resolver at OnSessionReady %p", self.get()));
}
}
}));
@ -344,45 +181,30 @@ WebTransportParent::OnSessionReady(uint64_t aSessionId) {
NS_IMETHODIMP
WebTransportParent::OnSessionClosed(const uint32_t aErrorCode,
const nsACString& aReason) {
LOG(("Creating web transport session failed code= %u, reason= %s", aErrorCode,
PromiseFlatCString(aReason).get()));
nsresult rv = NS_OK;
if (aErrorCode != 0) {
// currently we just know if session was closed gracefully or not.
// we need better error propagation from lower-levels of http3
// webtransport session and it's subsequent error mapping to DOM.
// XXX See Bug 1806834
rv = NS_ERROR_FAILURE;
}
MOZ_ASSERT(mOwningEventTarget);
MOZ_ASSERT(!mOwningEventTarget->IsOnCurrentThread());
// currently we just know if session was closed gracefully or not.
// we need better error propagation from lower-levels of http3
// webtransport session and it's subsequent error mapping to DOM.
// XXX See Bug 1806834
if (mResolver) {
LOG(("webtransport %p session creation failed code= %u, reason= %s", this,
aErrorCode, PromiseFlatCString(aReason).get()));
// we know we haven't gone Ready yet
rv = NS_ERROR_FAILURE;
mOwningEventTarget->Dispatch(NS_NewRunnableFunction(
"WebTransportParent::OnSessionClosed",
[self = RefPtr{this}, result = rv] {
if (!self->IsClosed() && self->mResolver) {
self->mResolver(ResolveType(
result, static_cast<uint8_t>(
WebTransportReliabilityMode::Supports_unreliable)));
}
}));
} else {
// https://w3c.github.io/webtransport/#web-transport-termination
// Step 1: Let cleanly be a boolean representing whether the HTTP/3
// stream associated with the CONNECT request that initiated
// transport.[[Session]] is in the "Data Recvd" state. [QUIC]
// XXX not calculated yet
LOG(("webtransport %p session remote closed code= %u, reason= %s", this,
aErrorCode, PromiseFlatCString(aReason).get()));
mSocketThread->Dispatch(NS_NewRunnableFunction(
__func__,
[self = RefPtr{this}, aErrorCode, reason = nsCString{aReason}]() {
// Tell the content side we were closed by the server
Unused << self->SendRemoteClosed(/*XXX*/ true, aErrorCode, reason);
// Let the other end shut down the IPC channel after RecvClose()
}));
}
mOwningEventTarget->Dispatch(NS_NewRunnableFunction(
"WebTransportParent::OnSessionClosed",
[self = RefPtr{this}, result = rv] {
if (!self->IsClosed() && self->mResolver) {
self->mResolver(ResolveType(
result, static_cast<uint8_t>(
WebTransportReliabilityMode::Supports_unreliable)));
self->mResolver = nullptr;
}
}));
return NS_OK;
}
@ -409,89 +231,16 @@ WebTransportParent::OnIncomingStreamAvailableInternal(
NS_IMETHODIMP
WebTransportParent::OnIncomingUnidirectionalStreamAvailable(
nsIWebTransportReceiveStream* aStream) {
// Note: we need to hold a reference to the stream if we want to get stats,
// etc
LOG(("%p IncomingUnidirectonalStream available", this));
// We must be on the Socket Thread
MOZ_ASSERT(mSocketThread->IsOnCurrentThread());
RefPtr<DataPipeSender> sender;
RefPtr<DataPipeReceiver> receiver;
nsresult rv = NewDataPipe(mozilla::ipc::kDefaultDataPipeCapacity,
getter_AddRefs(sender), getter_AddRefs(receiver));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIAsyncInputStream> inputStream;
aStream->GetInputStream(getter_AddRefs(inputStream));
MOZ_ASSERT(inputStream);
rv = NS_AsyncCopy(inputStream, sender, mSocketThread,
NS_ASYNCCOPY_VIA_WRITESEGMENTS,
mozilla::ipc::kDefaultDataPipeCapacity);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
LOG(("%p Sending UnidirectionalStream pipe to content", this));
// pass the DataPipeReceiver to the content process
Unused << SendIncomingUnidirectionalStream(receiver);
// XXX implement once DOM WebAPI supports creation of streams
Unused << aStream;
return NS_OK;
}
NS_IMETHODIMP
WebTransportParent::OnIncomingBidirectionalStreamAvailable(
nsIWebTransportBidirectionalStream* aStream) {
// Note: we need to hold a reference to the stream if we want to get stats,
// etc
LOG(("%p IncomingBidirectonalStream available", this));
// We must be on the Socket Thread
MOZ_ASSERT(mSocketThread->IsOnCurrentThread());
RefPtr<DataPipeSender> inputSender;
RefPtr<DataPipeReceiver> inputReceiver;
nsresult rv =
NewDataPipe(mozilla::ipc::kDefaultDataPipeCapacity,
getter_AddRefs(inputSender), getter_AddRefs(inputReceiver));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIAsyncInputStream> inputStream;
aStream->GetInputStream(getter_AddRefs(inputStream));
MOZ_ASSERT(inputStream);
rv = NS_AsyncCopy(inputStream, inputSender, mSocketThread,
NS_ASYNCCOPY_VIA_WRITESEGMENTS,
mozilla::ipc::kDefaultDataPipeCapacity);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
RefPtr<DataPipeSender> outputSender;
RefPtr<DataPipeReceiver> outputReceiver;
rv =
NewDataPipe(mozilla::ipc::kDefaultDataPipeCapacity,
getter_AddRefs(outputSender), getter_AddRefs(outputReceiver));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIAsyncOutputStream> outputStream;
aStream->GetOutputStream(getter_AddRefs(outputStream));
MOZ_ASSERT(outputStream);
rv = NS_AsyncCopy(outputReceiver, outputStream, mSocketThread,
NS_ASYNCCOPY_VIA_READSEGMENTS,
mozilla::ipc::kDefaultDataPipeCapacity);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
LOG(("%p Sending BidirectionalStream pipe to content", this));
// pass the DataPipeSender to the content process
Unused << SendIncomingBidirectionalStream(inputReceiver, outputSender);
// XXX implement once DOM WebAPI supports creation of streams
Unused << aStream;
return NS_OK;
}

Просмотреть файл

@ -11,7 +11,6 @@
#include "mozilla/dom/FlippedOnce.h"
#include "mozilla/dom/PWebTransportParent.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "nsISupports.h"
#include "nsIPrincipal.h"
#include "nsIWebTransport.h"
@ -22,8 +21,6 @@ enum class WebTransportReliabilityMode : uint8_t;
class WebTransportParent : public PWebTransportParent,
public WebTransportSessionEventListener {
using IPCResult = mozilla::ipc::IPCResult;
public:
WebTransportParent() = default;
@ -37,13 +34,8 @@ class WebTransportParent : public PWebTransportParent,
Endpoint<PWebTransportParent>&& aParentEndpoint,
std::function<void(Tuple<const nsresult&, const uint8_t&>)>&& aResolver);
IPCResult RecvClose(const uint32_t& aCode, const nsACString& aReason);
IPCResult RecvCreateUnidirectionalStream(
Maybe<int64_t> aSendOrder,
CreateUnidirectionalStreamResolver&& aResolver);
IPCResult RecvCreateBidirectionalStream(
Maybe<int64_t> aSendOrder, CreateBidirectionalStreamResolver&& aResolver);
mozilla::ipc::IPCResult RecvClose(const uint32_t& aCode,
const nsACString& aReason);
void ActorDestroy(ActorDestroyReason aWhy) override;
@ -54,7 +46,6 @@ class WebTransportParent : public PWebTransportParent,
private:
using ResolveType = Tuple<const nsresult&, const uint8_t&>;
nsCOMPtr<nsISerialEventTarget> mSocketThread;
std::function<void(ResolveType)> mResolver;
FlippedOnce<false> mClosed;
nsCOMPtr<nsIWebTransport> mWebTransport;

Просмотреть файл

@ -9,15 +9,6 @@ include PBackgroundSharedTypes;
namespace mozilla {
namespace dom {
struct BidirectionalStream {
DataPipeReceiver inStream;
DataPipeSender outStream;
};
union BidirectionalStreamResponse {
nsresult;
BidirectionalStream;
};
async protocol PWebTransport
{
@ -26,18 +17,12 @@ async protocol PWebTransport
* TODO: documentation
*/
async Close(uint32_t code, nsCString reason);
async CreateUnidirectionalStream(int64_t? sendOrder)
returns(DataPipeSender sender);
async CreateBidirectionalStream(int64_t? sendOrder)
returns(BidirectionalStreamResponse response);
child:
async IncomingUnidirectionalStream(DataPipeReceiver receive);
async IncomingBidirectionalStream(DataPipeReceiver receive, DataPipeSender send);
async RemoteClosed(bool cleanly, uint32_t code, nsCString reason);
async CloseAll()
returns(nsresult rv);
};

Просмотреть файл

@ -272,7 +272,6 @@ nsresult Http3WebTransportStream::OnReadSegment(const char* buf, uint32_t count,
"error=0x%" PRIx32 ".",
this, static_cast<uint32_t>(rv)));
mStreamReadyCallback(Err(rv));
mStreamReadyCallback = nullptr;
break;
}
@ -287,13 +286,11 @@ nsresult Http3WebTransportStream::OnReadSegment(const char* buf, uint32_t count,
this, static_cast<uint32_t>(rv)));
mSendState = SEND_DONE;
mStreamReadyCallback(Err(rv));
mStreamReadyCallback = nullptr;
break;
}
// Successfully activated.
mStreamReadyCallback(RefPtr{this});
mStreamReadyCallback = nullptr;
break;
case SENDING: {
rv = mSession->SendRequestBody(mStreamId, buf, count, countRead);
@ -303,20 +300,9 @@ nsresult Http3WebTransportStream::OnReadSegment(const char* buf, uint32_t count,
this, static_cast<uint32_t>(rv)));
mTotalSent += *countRead;
} break;
case WAITING_DATA:
// Still waiting
LOG3((
"Http3WebTransportStream::OnReadSegment %p Still waiting for data...",
this));
break;
case SEND_DONE:
LOG3(("Http3WebTransportStream::OnReadSegment %p called after SEND_DONE ",
this));
default:
MOZ_ASSERT(false, "We are done sending this request!");
MOZ_ASSERT(mStreamReadyCallback);
rv = NS_ERROR_UNEXPECTED;
mStreamReadyCallback(Err(rv));
mStreamReadyCallback = nullptr;
break;
}

Просмотреть файл

@ -15,7 +15,6 @@
#include "nsProxyRelease.h"
#include "nsSocketTransportService2.h"
#include "mozilla/Logging.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/StaticPrefs_network.h"
namespace mozilla::net {
@ -68,14 +67,6 @@ nsresult WebTransportSessionProxy::AsyncConnect(
MutexAutoLock lock(mMutex);
mListener = aListener;
}
auto cleanup = MakeScopeExit([self = RefPtr<WebTransportSessionProxy>(this)] {
MutexAutoLock lock(self->mMutex);
self->mListener->OnSessionClosed(0, ""_ns); // TODO: find a better error.
self->mChannel = nullptr;
self->mListener = nullptr;
self->ChangeState(WebTransportSessionProxyState::DONE);
});
nsSecurityFlags flags = nsILoadInfo::SEC_COOKIES_OMIT | aSecurityFlags;
nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL |
nsIRequest::LOAD_BYPASS_CACHE |
@ -109,8 +100,11 @@ nsresult WebTransportSessionProxy::AsyncConnect(
}
rv = mChannel->AsyncOpen(this);
if (NS_SUCCEEDED(rv)) {
cleanup.release();
if (NS_FAILED(rv)) {
MutexAutoLock lock(mMutex);
mChannel = nullptr;
mListener = nullptr;
ChangeState(WebTransportSessionProxyState::DONE);
}
return rv;
}
@ -518,7 +512,7 @@ WebTransportSessionProxy::OnStopRequest(nsIRequest* aRequest,
case WebTransportSessionProxyState::INIT:
case WebTransportSessionProxyState::ACTIVE:
case WebTransportSessionProxyState::NEGOTIATING:
MOZ_ASSERT(false, "OnStopRequest cannot be called in this state.");
MOZ_ASSERT(false, "OnStotRequest cannot be called in this state.");
break;
case WebTransportSessionProxyState::CLOSE_CALLBACK_PENDING:
reason = mReason;

Просмотреть файл

@ -13,8 +13,8 @@ promise_test(async t => {
const close_info = await wt.closed;
assert_equals(close_info.closeCode, 0 , 'code');
assert_equals(close_info.reason, '', 'reason');
assert_not_own_property(close_info, 'closeCode');
assert_not_own_property(close_info, 'reason');
await wait(10);
const data = await query(id);

Просмотреть файл

@ -1,7 +1,6 @@
// META: global=window,worker
// META: script=/common/get-host-info.sub.js
// META: script=resources/webtransport-test-helpers.sub.js
// META: script=/common/utils.js
const BAD_URLS = [
null,
@ -34,8 +33,7 @@ const OPTIONS = [
for (const options of OPTIONS) {
promise_test(async t => {
const id = token();
const wt = new WebTransport(webtransport_url(`client-close.py?token=${id}`), options );
const wt = new WebTransport(`https://${HOST}:0/`, options );
await wt.ready;
wt.close();
}, "WebTransport constructor should allow options " + JSON.stringify(options));