diff options
Diffstat (limited to '')
25 files changed, 1366 insertions, 0 deletions
diff --git a/dom/webtransport/api/WebTransport.cpp b/dom/webtransport/api/WebTransport.cpp new file mode 100644 index 0000000000..5915827f62 --- /dev/null +++ b/dom/webtransport/api/WebTransport.cpp @@ -0,0 +1,306 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "WebTransport.h" + +#include "nsUTF8Utils.h" +#include "nsIURL.h" +#include "mozilla/Assertions.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/PWebTransport.h" +#include "mozilla/dom/ReadableStream.h" +#include "mozilla/dom/WebTransportDatagramDuplexStream.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" + +namespace mozilla::dom { + +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) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebTransport) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +WebTransport::WebTransport(nsIGlobalObject* aGlobal) + : mGlobal(aGlobal), + mState(WebTransportState::CONNECTING), + mReliability(WebTransportReliabilityMode::Pending) { + LOG(("Creating WebTransport %p", this)); +} + +// WebIDL Boilerplate + +nsIGlobalObject* WebTransport::GetParentObject() const { return mGlobal; } + +JSObject* WebTransport::WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) { + return WebTransport_Binding::Wrap(aCx, this, aGivenProto); +} + +// WebIDL Interface + +/* static */ +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())); + + nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); + RefPtr<WebTransport> result = new WebTransport(global); + if (!result->Init(aGlobal, aURL, aOptions, aError)) { + return nullptr; + } + + return result.forget(); +} + +bool WebTransport::Init(const GlobalObject& aGlobal, const nsAString& aURL, + const WebTransportOptions& aOptions, + ErrorResult& aError) { + // Initiate connection with parent + using mozilla::ipc::BackgroundChild; + using mozilla::ipc::Endpoint; + using mozilla::ipc::PBackgroundChild; + + mReady = Promise::Create(mGlobal, aError); + if (NS_WARN_IF(aError.Failed())) { + return false; + } + + mClosed = Promise::Create(mGlobal, aError); + if (NS_WARN_IF(aError.Failed())) { + return false; + } + + QueuingStrategy strategy; + Optional<JS::Handle<JSObject*>> underlying; + mIncomingUnidirectionalStreams = + ReadableStream::Constructor(aGlobal, underlying, strategy, aError); + if (aError.Failed()) { + return false; + } + mIncomingBidirectionalStreams = + ReadableStream::Constructor(aGlobal, underlying, strategy, aError); + if (aError.Failed()) { + return false; + } + + PBackgroundChild* backgroundChild = + BackgroundChild::GetOrCreateForCurrentThread(); + if (NS_WARN_IF(!backgroundChild)) { + return false; + } + + nsCOMPtr<nsIPrincipal> principal = nsContentUtils::GetSystemPrincipal(); + // Create a new IPC connection + Endpoint<PWebTransportParent> parentEndpoint; + Endpoint<PWebTransportChild> childEndpoint; + MOZ_ALWAYS_SUCCEEDS( + PWebTransport::CreateEndpoints(&parentEndpoint, &childEndpoint)); + + RefPtr<WebTransportChild> child = new WebTransportChild(); + if (!childEndpoint.Bind(child)) { + return false; + } + + mState = WebTransportState::CONNECTING; + LOG(("Connecting WebTransport to parent for %s", + NS_ConvertUTF16toUTF8(aURL).get())); + + // Parse string for validity and Throw a SyntaxError if it isn't + if (!ParseURL(aURL)) { + aError.ThrowSyntaxError("Invalid WebTransport URL"); + return false; + } + bool dedicated = + !aOptions.mAllowPooling; // spec language, optimizer will eliminate this + bool requireUnreliable = aOptions.mRequireUnreliable; + WebTransportCongestionControl congestionControl = aOptions.mCongestionControl; + if (aOptions.mServerCertificateHashes.WasPassed()) { + // XXX bug 1806693 + aError.ThrowNotSupportedError("No support for serverCertificateHashes yet"); + // XXX if dedicated is false and serverCertificateHashes is non-null, then + // throw a TypeError. Also should enforce in parent + return false; + } + + // https://w3c.github.io/webtransport/#webtransport-constructor Spec 5.2 + backgroundChild + ->SendCreateWebTransportParent(aURL, principal, dedicated, + requireUnreliable, + (uint32_t)congestionControl, + // XXX serverCertHashes, + std::move(parentEndpoint)) + ->Then(GetCurrentSerialEventTarget(), __func__, + [self = RefPtr{this}, + child](PBackgroundChild::CreateWebTransportParentPromise:: + ResolveOrRejectValue&& aResult) { + // aResult is a Tuple<nsresult, uint8_t> + // TODO: is there a better/more-spec-compliant error in the + // reject case? Which begs the question, why would we get a + // reject? + nsresult rv = aResult.IsReject() + ? NS_ERROR_FAILURE + : Get<0>(aResult.ResolveValue()); + if (NS_FAILED(rv)) { + self->RejectWaitingConnection(rv); + } else { + // This will process anything waiting for the connection to + // complete; + self->ResolveWaitingConnection( + static_cast<WebTransportReliabilityMode>( + Get<1>(aResult.ResolveValue())), + child); + } + }); + + return true; +} + +void WebTransport::ResolveWaitingConnection( + WebTransportReliabilityMode aReliability, WebTransportChild* aChild) { + LOG(("Resolved Connection %p, reliability = %u", this, + (unsigned)aReliability)); + + MOZ_ASSERT(mState == WebTransportState::CONNECTING); + mChild = aChild; + mState = WebTransportState::CONNECTED; + mReliability = aReliability; + + mReady->MaybeResolve(true); +} + +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)); + + // https://w3c.github.io/webtransport/#webtransport-internal-slots + // "Reliability returns "pending" until a connection is established" so + // we leave it pending + mReady->MaybeReject(aRv); +} + +bool WebTransport::ParseURL(const nsAString& aURL) const { + NS_ENSURE_TRUE(!aURL.IsEmpty(), false); + + // 5.4 = https://w3c.github.io/webtransport/#webtransport-constructor + // 5.4 #1 and #2 + nsCOMPtr<nsIURI> uri; + nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL); + NS_ENSURE_SUCCESS(rv, false); + + // 5.4 #3 + if (!uri->SchemeIs("https")) { + return false; + } + + // 5.4 #4 no fragments + bool hasRef; + rv = uri->GetHasRef(&hasRef); + NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && !hasRef, false); + + return true; +} + +already_AddRefed<Promise> WebTransport::GetStats(ErrorResult& aError) { + aError.Throw(NS_ERROR_NOT_IMPLEMENTED); + return nullptr; +} + +already_AddRefed<Promise> WebTransport::Ready() { return do_AddRef(mReady); } + +WebTransportReliabilityMode WebTransport::Reliability() { return mReliability; } + +WebTransportCongestionControl WebTransport::CongestionControl() { + // XXX not implemented + return WebTransportCongestionControl::Default; +} + +already_AddRefed<Promise> WebTransport::Closed() { + ErrorResult error; + RefPtr<Promise> promise = Promise::Create(GetParentObject(), error); + if (error.Failed()) { + return nullptr; + } + promise->MaybeResolve(mState == WebTransportState::CLOSED); + return promise.forget(); +} + +void WebTransport::Close(const WebTransportCloseInfo& aOptions) { + LOG(("Close() called")); + if (mState == WebTransportState::CONNECTED || + mState == WebTransportState::CONNECTING) { + MOZ_ASSERT(mChild); + LOG(("Sending Close")); + // "Let reasonString be the maximal code unit prefix of + // closeInfo.reason where the length of the UTF-8 encoded prefix + // doesn’t exceed 1024." + // Take the maximal "code unit prefix" of mReason and limit to 1024 bytes + // https://w3c.github.io/webtransport/#webtransport-methods 5.4 + + if (aOptions.mReason.Length() > 1024u) { + // We want to start looking for the previous code point at one past the + // limit, since if a code point ends exactly at the specified length, the + // next byte will be the start of a new code point. Note + // RewindToPriorUTF8Codepoint doesn't reduce the index if it points to the + // start of a code point. We know reason[1024] is accessible since + // Length() > 1024 + mChild->SendClose( + aOptions.mCloseCode, + Substring(aOptions.mReason, 0, + RewindToPriorUTF8Codepoint(aOptions.mReason.get(), 1024u))); + } else { + mChild->SendClose(aOptions.mCloseCode, aOptions.mReason); + } + mState = WebTransportState::CLOSED; + + // The other side will call `Close()` for us now, make sure we don't call it + // in our destructor. + mChild = nullptr; + } +} + +already_AddRefed<WebTransportDatagramDuplexStream> WebTransport::Datagrams() { + LOG(("Datagrams() called")); + // XXX not implemented + return nullptr; +} + +already_AddRefed<Promise> WebTransport::CreateBidirectionalStream( + ErrorResult& aError) { + LOG(("CreateBidirectionalStream() called")); + aError.Throw(NS_ERROR_NOT_IMPLEMENTED); + return nullptr; +} + +already_AddRefed<ReadableStream> WebTransport::IncomingBidirectionalStreams() { + return do_AddRef(mIncomingBidirectionalStreams); +} + +already_AddRefed<Promise> WebTransport::CreateUnidirectionalStream( + ErrorResult& aError) { + LOG(("CreateUnidirectionalStream() called")); + aError.Throw(NS_ERROR_NOT_IMPLEMENTED); + return nullptr; +} + +already_AddRefed<ReadableStream> WebTransport::IncomingUnidirectionalStreams() { + return do_AddRef(mIncomingUnidirectionalStreams); +} + +} // namespace mozilla::dom diff --git a/dom/webtransport/api/WebTransport.h b/dom/webtransport/api/WebTransport.h new file mode 100644 index 0000000000..803a370676 --- /dev/null +++ b/dom/webtransport/api/WebTransport.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef DOM_WEBTRANSPORT_API_WEBTRANSPORT__H_ +#define DOM_WEBTRANSPORT_API_WEBTRANSPORT__H_ + +#include "nsCOMPtr.h" +#include "nsISupports.h" +#include "nsWrapperCache.h" +#include "mozilla/dom/WebTransportBinding.h" +#include "mozilla/dom/WebTransportChild.h" + +namespace mozilla::dom { + +class WebTransportDatagramDuplexStream; +class ReadableStream; +class WritableStream; + +class WebTransport final : public nsISupports, public nsWrapperCache { + public: + explicit WebTransport(nsIGlobalObject* aGlobal); + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(WebTransport) + + enum class WebTransportState { CONNECTING, CONNECTED, CLOSED, FAILED }; + + bool Init(const GlobalObject& aGlobal, const nsAString& aUrl, + const WebTransportOptions& aOptions, ErrorResult& aError); + void ResolveWaitingConnection(WebTransportReliabilityMode aReliability, + WebTransportChild* aChild); + void RejectWaitingConnection(nsresult aRv); + bool ParseURL(const nsAString& aURL) const; + + // WebIDL Boilerplate + nsIGlobalObject* GetParentObject() const; + + JSObject* WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) override; + + // WebIDL Interface + static already_AddRefed<WebTransport> Constructor( + const GlobalObject& aGlobal, const nsAString& aUrl, + const WebTransportOptions& aOptions, ErrorResult& aRv); + + already_AddRefed<Promise> GetStats(ErrorResult& aError); + + already_AddRefed<Promise> Ready(); + WebTransportReliabilityMode Reliability(); + WebTransportCongestionControl CongestionControl(); + already_AddRefed<Promise> Closed(); + void Close(const WebTransportCloseInfo& aOptions); + already_AddRefed<WebTransportDatagramDuplexStream> Datagrams(); + already_AddRefed<Promise> CreateBidirectionalStream(ErrorResult& aError); + already_AddRefed<ReadableStream> IncomingBidirectionalStreams(); + already_AddRefed<Promise> CreateUnidirectionalStream(ErrorResult& aError); + already_AddRefed<ReadableStream> IncomingUnidirectionalStreams(); + + void Shutdown() {} + + private: + ~WebTransport() { + // Should be empty by this point, because we should always have run cleanup: + // https://w3c.github.io/webtransport/#webtransport-procedures + MOZ_ASSERT(mSendStreams.IsEmpty()); + MOZ_ASSERT(mReceiveStreams.IsEmpty()); + // If this WebTransport was destroyed without being closed properly, make + // sure to clean up the channel. + if (mChild) { + mChild->Shutdown(); + } + } + + nsCOMPtr<nsIGlobalObject> mGlobal; + RefPtr<WebTransportChild> mChild; + + // Spec-defined slots: + // ordered sets, but we can't have duplicates, and this spec only appends. + // Order is visible due to + // https://w3c.github.io/webtransport/#webtransport-procedures step 10: "For + // 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<WritableStream>> mSendStreams; + nsTArray<RefPtr<ReadableStream>> mReceiveStreams; + + WebTransportState mState; + RefPtr<Promise> mReady; + WebTransportReliabilityMode mReliability; + // These are created in the constructor + RefPtr<ReadableStream> mIncomingUnidirectionalStreams; + RefPtr<ReadableStream> mIncomingBidirectionalStreams; + RefPtr<WebTransportDatagramDuplexStream> mDatagrams; + RefPtr<Promise> mClosed; +}; + +} // namespace mozilla::dom + +#endif diff --git a/dom/webtransport/api/WebTransportBidirectionalStream.cpp b/dom/webtransport/api/WebTransportBidirectionalStream.cpp new file mode 100644 index 0000000000..60f202cd03 --- /dev/null +++ b/dom/webtransport/api/WebTransportBidirectionalStream.cpp @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "WebTransportBidirectionalStream.h" +#include "mozilla/dom/Promise.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebTransportBidirectionalStream, mGlobal) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(WebTransportBidirectionalStream) +NS_IMPL_CYCLE_COLLECTING_RELEASE(WebTransportBidirectionalStream) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebTransportBidirectionalStream) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +// WebIDL Boilerplate + +nsIGlobalObject* WebTransportBidirectionalStream::GetParentObject() const { + return mGlobal; +} + +JSObject* WebTransportBidirectionalStream::WrapObject( + JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { + return WebTransportBidirectionalStream_Binding::Wrap(aCx, this, aGivenProto); +} + +// WebIDL Interface + +} // namespace mozilla::dom diff --git a/dom/webtransport/api/WebTransportBidirectionalStream.h b/dom/webtransport/api/WebTransportBidirectionalStream.h new file mode 100644 index 0000000000..0f9e90f767 --- /dev/null +++ b/dom/webtransport/api/WebTransportBidirectionalStream.h @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef DOM_WEBTRANSPORT_API_WEBTRANSPORTBIDIRECTIONALSTREAM__H_ +#define DOM_WEBTRANSPORT_API_WEBTRANSPORTBIDIRECTIONALSTREAM__H_ + +#include "nsCOMPtr.h" +#include "nsISupports.h" +#include "nsWrapperCache.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/ReadableStream.h" +#include "mozilla/dom/WritableStream.h" +#include "mozilla/dom/WebTransportSendReceiveStreamBinding.h" + +// #include "mozilla/dom/WebTransportReceiveStream.h" +// #include "mozilla/dom/WebTransportSendStream.h" + +namespace mozilla::dom { +class WebTransportBidirectionalStream final : public nsISupports, + public nsWrapperCache { + public: + explicit WebTransportBidirectionalStream(nsIGlobalObject* aGlobal) + : mGlobal(aGlobal) {} + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(WebTransportBidirectionalStream) + + // WebIDL Boilerplate + nsIGlobalObject* GetParentObject() const; + + JSObject* WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) override; + + // WebIDL Interface + // 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; +}; + +} // namespace mozilla::dom + +#endif diff --git a/dom/webtransport/api/WebTransportDatagramDuplexStream.cpp b/dom/webtransport/api/WebTransportDatagramDuplexStream.cpp new file mode 100644 index 0000000000..e4fac822e5 --- /dev/null +++ b/dom/webtransport/api/WebTransportDatagramDuplexStream.cpp @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "WebTransportDatagramDuplexStream.h" +#include "mozilla/dom/Promise.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebTransportDatagramDuplexStream, mGlobal, + mReadable, mWritable) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(WebTransportDatagramDuplexStream) +NS_IMPL_CYCLE_COLLECTING_RELEASE(WebTransportDatagramDuplexStream) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebTransportDatagramDuplexStream) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +// WebIDL Boilerplate + +nsIGlobalObject* WebTransportDatagramDuplexStream::GetParentObject() const { + return mGlobal; +} + +JSObject* WebTransportDatagramDuplexStream::WrapObject( + JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { + return WebTransportDatagramDuplexStream_Binding::Wrap(aCx, this, aGivenProto); +} + +// WebIDL Interface + +} // namespace mozilla::dom diff --git a/dom/webtransport/api/WebTransportDatagramDuplexStream.h b/dom/webtransport/api/WebTransportDatagramDuplexStream.h new file mode 100644 index 0000000000..1aa895cd53 --- /dev/null +++ b/dom/webtransport/api/WebTransportDatagramDuplexStream.h @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef DOM_WEBTRANSPORT_API_WEBTRANSPORTDATAGRAMDUPLEXSTREAM__H_ +#define DOM_WEBTRANSPORT_API_WEBTRANSPORTDATAGRAMDUPLEXSTREAM__H_ + +#include "nsCOMPtr.h" +#include "nsISupports.h" +#include "nsWrapperCache.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/ReadableStream.h" +#include "mozilla/dom/WritableStream.h" +#include "mozilla/dom/WebTransportDatagramDuplexStreamBinding.h" + +namespace mozilla::dom { + +class WebTransportDatagramDuplexStream final : public nsISupports, + public nsWrapperCache { + public: + explicit WebTransportDatagramDuplexStream(nsIGlobalObject* aGlobal) + : mGlobal(aGlobal) {} + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(WebTransportDatagramDuplexStream) + + // WebIDL Boilerplate + nsIGlobalObject* GetParentObject() const; + + JSObject* WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) override; + + // WebIDL Interface + already_AddRefed<ReadableStream> Readable() const { + RefPtr<ReadableStream> result(mReadable); + return result.forget(); + } + already_AddRefed<WritableStream> Writable() { + RefPtr<WritableStream> result(mWritable); + return result.forget(); + } + // XXX not implemented + uint64_t MaxDatagramSize() const { return 1500; } + Nullable<double> GetIncomingMaxAge() const { return mIncomingMaxAge; } + void SetIncomingMaxAge(const Nullable<double>& aMaxAge) { + mIncomingMaxAge = aMaxAge; + } + Nullable<double> GetOutgoingMaxAge() const { return mOutgoingMaxAge; } + void SetOutgoingMaxAge(const Nullable<double>& aMaxAge) { + mOutgoingMaxAge = aMaxAge; + } + int64_t IncomingHighWaterMark() const { return mIncomingHighWaterMark; } + void SetIncomingHighWaterMark(int64_t aWaterMark) { + mIncomingHighWaterMark = aWaterMark; + } + int64_t OutgoingHighWaterMark() const { return mOutgoingHighWaterMark; } + void SetOutgoingHighWaterMark(int64_t aWaterMark) { + mOutgoingHighWaterMark = aWaterMark; + } + + private: + ~WebTransportDatagramDuplexStream() = default; + + nsCOMPtr<nsIGlobalObject> mGlobal; + RefPtr<ReadableStream> mReadable; + RefPtr<WritableStream> mWritable; + + Nullable<double> mIncomingMaxAge; + Nullable<double> mOutgoingMaxAge; + int64_t mIncomingHighWaterMark = 0; + int64_t mOutgoingHighWaterMark = 0; +}; + +} // namespace mozilla::dom + +#endif diff --git a/dom/webtransport/api/WebTransportError.cpp b/dom/webtransport/api/WebTransportError.cpp new file mode 100644 index 0000000000..142d98d2b9 --- /dev/null +++ b/dom/webtransport/api/WebTransportError.cpp @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "WebTransportError.h" + +namespace mozilla::dom { + +/* static */ +already_AddRefed<WebTransportError> WebTransportError::Constructor( + const GlobalObject& aGlobal, const WebTransportErrorInit& aInit) { + nsCString message(""_ns); + if (aInit.mMessage.WasPassed()) { + CopyUTF16toUTF8(aInit.mMessage.Value(), message); + } + RefPtr<WebTransportError> error(new WebTransportError(message)); + if (aInit.mStreamErrorCode.WasPassed()) { + error->mStreamErrorCode = aInit.mStreamErrorCode.Value(); + } + return error.forget(); +} + +WebTransportErrorSource WebTransportError::Source() { + // XXX Not implemented + return WebTransportErrorSource::Stream; +} + +} // namespace mozilla::dom diff --git a/dom/webtransport/api/WebTransportError.h b/dom/webtransport/api/WebTransportError.h new file mode 100644 index 0000000000..96b195ca0e --- /dev/null +++ b/dom/webtransport/api/WebTransportError.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef DOM_WEBTRANSPORT_API_WEBTRANSPORTERROR__H_ +#define DOM_WEBTRANSPORT_API_WEBTRANSPORTERROR__H_ + +#include "mozilla/dom/DOMException.h" +#include "mozilla/dom/WebTransportErrorBinding.h" + +namespace mozilla::dom { +class WebTransportError final : public DOMException { + protected: + explicit WebTransportError(const nsACString& aMessage) + : DOMException(NS_OK, aMessage, "stream"_ns, 0) {} + + public: + static already_AddRefed<WebTransportError> Constructor( + const GlobalObject& aGlobal, const WebTransportErrorInit& aInit); + + WebTransportErrorSource Source(); + Nullable<uint8_t> GetStreamErrorCode() const { + return Nullable<uint8_t>(mStreamErrorCode); + } + + private: + uint8_t mStreamErrorCode = 0; +}; + +} // namespace mozilla::dom + +#endif diff --git a/dom/webtransport/api/WebTransportReceiveStream.h b/dom/webtransport/api/WebTransportReceiveStream.h new file mode 100644 index 0000000000..013af43424 --- /dev/null +++ b/dom/webtransport/api/WebTransportReceiveStream.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#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_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WebTransportReceiveStream, + ReadableStream) + + already_AddRefed<Promise> GetStats(); +}; +#else +namespace mozilla::dom { +class WebTransportReceiveStream final : public nsISupports { + protected: + WebTransportReceiveStream(); + + public: + NS_DECL_ISUPPORTS + + already_AddRefed<Promise> GetStats(); +}; +#endif +} + +#endif diff --git a/dom/webtransport/api/WebTransportSendStream.h b/dom/webtransport/api/WebTransportSendStream.h new file mode 100644 index 0000000000..0de62208b4 --- /dev/null +++ b/dom/webtransport/api/WebTransportSendStream.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef DOM_WEBTRANSPORT_API_WEBTRANSPORTSENDSTREAM__H_ +#define DOM_WEBTRANSPORT_API_WEBTRANSPORTSENDSTREAM__H_ + +#include "mozilla/dom/WritableStream.h" + +#if WEBTRANSPORT_STREAM_IMPLEMENTED +namespace mozilla::dom { +class WebTransportSendStream final : public WritableStream { + protected: + WebTransportSendStream(); + + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WebTransportSendStream, + WritableStream) + + already_AddRefed<Promise> GetStats(); +}; +#else +namespace mozilla::dom { +class WebTransportSendStream final : public nsISupports { + protected: + WebTransportSendStream(); + + public: + NS_DECL_ISUPPORTS + + already_AddRefed<Promise> GetStats(); +}; +#endif +} + +#endif diff --git a/dom/webtransport/api/moz.build b/dom/webtransport/api/moz.build new file mode 100644 index 0000000000..c456fb16d0 --- /dev/null +++ b/dom/webtransport/api/moz.build @@ -0,0 +1,25 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +EXPORTS.mozilla.dom += [ + "WebTransport.h", + "WebTransportBidirectionalStream.h", + "WebTransportDatagramDuplexStream.h", + "WebTransportError.h", + "WebTransportReceiveStream.h", + "WebTransportSendStream.h", +] + +UNIFIED_SOURCES += [ + "WebTransport.cpp", + "WebTransportBidirectionalStream.cpp", + "WebTransportDatagramDuplexStream.cpp", + "WebTransportError.cpp", +] + +FINAL_LIBRARY = "xul" + +include("/ipc/chromium/chromium-config.mozbuild") diff --git a/dom/webtransport/child/WebTransportChild.h b/dom/webtransport/child/WebTransportChild.h new file mode 100644 index 0000000000..3aa7c8d8e2 --- /dev/null +++ b/dom/webtransport/child/WebTransportChild.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef DOM_WEBTRANSPORT_WEBTRANSPORTCHILD_H_ +#define DOM_WEBTRANSPORT_WEBTRANSPORTCHILD_H_ + +#include "mozilla/dom/PWebTransportChild.h" +#include "nsISupportsImpl.h" + +namespace mozilla::dom { + +class WebTransportChild : public PWebTransportChild { + public: + NS_INLINE_DECL_REFCOUNTING(WebTransportChild) + + virtual void CloseAll() { + // XXX need impl + } + + virtual void Shutdown() { + if (!CanSend()) { + return; + } + + Close(); + } + + ::mozilla::ipc::IPCResult RecvCloseAll(CloseAllResolver&& aResolver) { + CloseAll(); + aResolver(NS_OK); + return IPC_OK(); + } + + protected: + virtual ~WebTransportChild() = default; +}; + +} // namespace mozilla::dom + +#endif // DOM_WEBTRANSPORT_WEBTRANSPORTCHILD_H_ diff --git a/dom/webtransport/child/moz.build b/dom/webtransport/child/moz.build new file mode 100644 index 0000000000..dd86788857 --- /dev/null +++ b/dom/webtransport/child/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +EXPORTS.mozilla.dom += [ + "WebTransportChild.h", +] + +FINAL_LIBRARY = "xul" + +include("/ipc/chromium/chromium-config.mozbuild") diff --git a/dom/webtransport/moz.build b/dom/webtransport/moz.build new file mode 100644 index 0000000000..971f041ddb --- /dev/null +++ b/dom/webtransport/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +DIRS += [ + "api", + "child", + "parent", + "shared", + "test", +] diff --git a/dom/webtransport/parent/WebTransportParent.cpp b/dom/webtransport/parent/WebTransportParent.cpp new file mode 100644 index 0000000000..fa84d49803 --- /dev/null +++ b/dom/webtransport/parent/WebTransportParent.cpp @@ -0,0 +1,266 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "WebTransportParent.h" +#include "Http3WebTransportSession.h" +#include "mozilla/StaticPrefs_network.h" +#include "mozilla/dom/WebTransportBinding.h" +#include "mozilla/dom/WebTransportLog.h" +#include "mozilla/ipc/BackgroundParent.h" +#include "nsIEventTarget.h" +#include "nsIOService.h" +#include "nsIPrincipal.h" +#include "nsIWebTransport.h" + +namespace mozilla::dom { + +NS_IMPL_ISUPPORTS(WebTransportParent, WebTransportSessionEventListener); + +using IPCResult = mozilla::ipc::IPCResult; +using CreateWebTransportPromise = + MozPromise<WebTransportReliabilityMode, nsresult, true>; +WebTransportParent::~WebTransportParent() { + LOG(("Destroying WebTransportParent %p", this)); +} + +void WebTransportParent::Create( + const nsAString& aURL, nsIPrincipal* aPrincipal, const bool& aDedicated, + const bool& aRequireUnreliable, const uint32_t& aCongestionControl, + // Sequence<WebTransportHash>* aServerCertHashes, + Endpoint<PWebTransportParent>&& aParentEndpoint, + std::function<void(Tuple<const nsresult&, const uint8_t&>)>&& aResolver) { + LOG(("Created WebTransportParent %s %s %s congestion=%s", + NS_ConvertUTF16toUTF8(aURL).get(), + aDedicated ? "Dedicated" : "AllowPooling", + aRequireUnreliable ? "RequireUnreliable" : "", + aCongestionControl == + (uint32_t)dom::WebTransportCongestionControl::Throughput + ? "ThroughPut" + : (aCongestionControl == + (uint32_t)dom::WebTransportCongestionControl::Low_latency + ? "Low-Latency" + : "Default"))); + + if (!StaticPrefs::network_webtransport_enabled()) { + aResolver(ResolveType( + NS_ERROR_DOM_NOT_ALLOWED_ERR, + static_cast<uint8_t>(WebTransportReliabilityMode::Pending))); + return; + } + + if (!aParentEndpoint.IsValid()) { + aResolver(ResolveType( + NS_ERROR_INVALID_ARG, + static_cast<uint8_t>(WebTransportReliabilityMode::Pending))); + return; + } + + RefPtr<WebTransportParent> parent = new WebTransportParent(); + MOZ_ASSERT(parent); + + MOZ_DIAGNOSTIC_ASSERT(mozilla::net::gIOService); + nsresult rv = mozilla::net::gIOService->NewWebTransport( + getter_AddRefs(parent->mWebTransport)); + if (NS_FAILED(rv)) { + aResolver(ResolveType( + rv, static_cast<uint8_t>(WebTransportReliabilityMode::Pending))); + return; + } + + parent->mOwningEventTarget = GetCurrentEventTarget(); + + MOZ_ASSERT(aPrincipal); + nsCOMPtr<nsIURI> uri; + rv = NS_NewURI(getter_AddRefs(uri), aURL); + if (NS_FAILED(rv)) { + aResolver(ResolveType( + NS_ERROR_INVALID_ARG, + static_cast<uint8_t>(WebTransportReliabilityMode::Pending))); + return; + } + + nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( + "WebTransport AsyncConnect", + [self = RefPtr{parent}, uri = std::move(uri), + principal = RefPtr{aPrincipal}, + flags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL] { + 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. + nsCOMPtr<nsISerialEventTarget> sts = + do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + + InvokeAsync(sts, __func__, + [parentEndpoint = std::move(aParentEndpoint), runnable = r, + resolver = std::move(aResolver), p = RefPtr{parent}]() mutable { + p->mResolver = resolver; + + LOG(("Binding parent endpoint")); + if (!parentEndpoint.Bind(p)) { + return CreateWebTransportPromise::CreateAndReject( + NS_ERROR_FAILURE, __func__); + } + // 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{parent}]( + const CreateWebTransportPromise::ResolveOrRejectValue& aValue) { + if (aValue.IsReject()) { + p->mResolver(ResolveType( + aValue.RejectValue(), + static_cast<uint8_t>(WebTransportReliabilityMode::Pending))); + } + }); +} + +void WebTransportParent::ActorDestroy(ActorDestroyReason aWhy) { + LOG(("ActorDestroy WebTransportParent %d", aWhy)); +} + +// We may not receive this response if the child side is destroyed without +// `Close` or `Shutdown` being explicitly called. +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(); + nsAutoCString reason(aReason); + NS_DispatchToMainThread(NS_NewRunnableFunction( + "WebTransport Close", [self = RefPtr{this}, aCode, reason] { + if (self->mWebTransport) { + self->mWebTransport->CloseSession(aCode, reason); + } + })); + Close(); + return IPC_OK(); +} + +// We recieve this notification from the WebTransportSessionProxy if session was +// successfully created at the end of +// WebTransportSessionProxy::OnStopRequest +NS_IMETHODIMP +WebTransportParent::OnSessionReady(uint64_t aSessionId) { + MOZ_ASSERT(mOwningEventTarget); + MOZ_ASSERT(!mOwningEventTarget->IsOnCurrentThread()); + + LOG(("Created web transport session, sessionID = %" PRIu64 "", aSessionId)); + + mOwningEventTarget->Dispatch(NS_NewRunnableFunction( + "WebTransportParent::OnSessionReady", [self = RefPtr{this}] { + if (!self->IsClosed() && self->mResolver) { + self->mResolver(ResolveType( + NS_OK, static_cast<uint8_t>( + WebTransportReliabilityMode::Supports_unreliable))); + self->mResolver = nullptr; + } + })); + + return NS_OK; +} + +// We recieve this notification from the WebTransportSessionProxy if session +// creation was unsuccessful at the end of +// WebTransportSessionProxy::OnStopRequest +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()); + + 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; +} + +// This method is currently not used by WebTransportSessionProxy to inform of +// any session related events. All notification is recieved via +// WebTransportSessionProxy::OnSessionReady and +// WebTransportSessionProxy::OnSessionClosed methods +NS_IMETHODIMP +WebTransportParent::OnSessionReadyInternal( + mozilla::net::Http3WebTransportSession* aSession) { + Unused << aSession; + return NS_OK; +} + +NS_IMETHODIMP +WebTransportParent::OnIncomingStreamAvailableInternal( + mozilla::net::Http3WebTransportStream* aStream) { + // XXX implement once DOM WebAPI supports creation of streams + Unused << aStream; + return NS_OK; +} + +NS_IMETHODIMP +WebTransportParent::OnIncomingUnidirectionalStreamAvailable( + nsIWebTransportReceiveStream* aStream) { + // XXX implement once DOM WebAPI supports creation of streams + Unused << aStream; + return NS_OK; +} + +NS_IMETHODIMP +WebTransportParent::OnIncomingBidirectionalStreamAvailable( + nsIWebTransportBidirectionalStream* aStream) { + // XXX implement once DOM WebAPI supports creation of streams + Unused << aStream; + return NS_OK; +} + +NS_IMETHODIMP WebTransportParent::OnDatagramReceived( + const nsTArray<uint8_t>& aData) { + // XXX revisit this function once DOM WebAPI supports datagrams + return NS_OK; +} + +NS_IMETHODIMP WebTransportParent::OnDatagramReceivedInternal( + nsTArray<uint8_t>&& aData) { + // XXX revisit this function once DOM WebAPI supports datagrams + return NS_OK; +} + +NS_IMETHODIMP +WebTransportParent::OnOutgoingDatagramOutCome( + uint64_t aId, WebTransportSessionEventListener::DatagramOutcome aOutCome) { + // XXX revisit this function once DOM WebAPI supports datagrams + return NS_OK; +} + +NS_IMETHODIMP WebTransportParent::OnMaxDatagramSize(uint64_t aSize) { + // XXX revisit this function once DOM WebAPI supports datagrams + return NS_OK; +} +} // namespace mozilla::dom diff --git a/dom/webtransport/parent/WebTransportParent.h b/dom/webtransport/parent/WebTransportParent.h new file mode 100644 index 0000000000..6ce822e17c --- /dev/null +++ b/dom/webtransport/parent/WebTransportParent.h @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef DOM_WEBTRANSPORT_PARENT_WEBTRANSPORTPARENT_H_ +#define DOM_WEBTRANSPORT_PARENT_WEBTRANSPORTPARENT_H_ + +#include "ErrorList.h" +#include "mozilla/dom/FlippedOnce.h" +#include "mozilla/dom/PWebTransportParent.h" +#include "mozilla/ipc/Endpoint.h" +#include "nsISupports.h" +#include "nsIPrincipal.h" +#include "nsIWebTransport.h" + +namespace mozilla::dom { + +enum class WebTransportReliabilityMode : uint8_t; + +class WebTransportParent : public PWebTransportParent, + public WebTransportSessionEventListener { + public: + WebTransportParent() = default; + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_WEBTRANSPORTSESSIONEVENTLISTENER + + void Create( + const nsAString& aURL, nsIPrincipal* aPrincipal, const bool& aDedicated, + const bool& aRequireUnreliable, const uint32_t& aCongestionControl, + // Sequence<WebTransportHash>* aServerCertHashes, + Endpoint<PWebTransportParent>&& aParentEndpoint, + std::function<void(Tuple<const nsresult&, const uint8_t&>)>&& aResolver); + + mozilla::ipc::IPCResult RecvClose(const uint32_t& aCode, + const nsACString& aReason); + + void ActorDestroy(ActorDestroyReason aWhy) override; + + bool IsClosed() const { return mClosed; } + + protected: + virtual ~WebTransportParent(); + + private: + using ResolveType = Tuple<const nsresult&, const uint8_t&>; + std::function<void(ResolveType)> mResolver; + FlippedOnce<false> mClosed; + nsCOMPtr<nsIWebTransport> mWebTransport; + nsCOMPtr<nsIEventTarget> mOwningEventTarget; +}; + +} // namespace mozilla::dom + +#endif // DOM_WEBTRANSPORT_PARENT_WEBTRANSPORTPARENT_H_ diff --git a/dom/webtransport/parent/moz.build b/dom/webtransport/parent/moz.build new file mode 100644 index 0000000000..f3486cc8c7 --- /dev/null +++ b/dom/webtransport/parent/moz.build @@ -0,0 +1,22 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +EXPORTS.mozilla.dom += [ + "WebTransportParent.h", +] + +UNIFIED_SOURCES += [ + "WebTransportParent.cpp", +] + +FINAL_LIBRARY = "xul" + +include("/ipc/chromium/chromium-config.mozbuild") + +LOCAL_INCLUDES += [ + "/netwerk/base", + "/netwerk/protocol/http", +] diff --git a/dom/webtransport/shared/PWebTransport.ipdl b/dom/webtransport/shared/PWebTransport.ipdl new file mode 100644 index 0000000000..9376e2c511 --- /dev/null +++ b/dom/webtransport/shared/PWebTransport.ipdl @@ -0,0 +1,26 @@ +/* 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/. */ + +using struct mozilla::void_t from "mozilla/ipc/IPCCore.h"; + +namespace mozilla { +namespace dom { + +async protocol PWebTransport +{ + parent: + /** + * TODO: documentation + */ + async Close(uint32_t code, nsCString reason); + + child: + + async CloseAll() + returns(nsresult rv); +}; + +} // namespace dom +} // namespace mozilla + diff --git a/dom/webtransport/shared/WebTransportLog.cpp b/dom/webtransport/shared/WebTransportLog.cpp new file mode 100644 index 0000000000..0193921fec --- /dev/null +++ b/dom/webtransport/shared/WebTransportLog.cpp @@ -0,0 +1,13 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "WebTransportLog.h" + +namespace mozilla { + +LazyLogModule gWebTransportLog("WebTransport"); + +} diff --git a/dom/webtransport/shared/WebTransportLog.h b/dom/webtransport/shared/WebTransportLog.h new file mode 100644 index 0000000000..5bd6da29bd --- /dev/null +++ b/dom/webtransport/shared/WebTransportLog.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef DOM_WEBTRANSPORT_SHARED_WEBTRANSPORTLOG_H_ +#define DOM_WEBTRANSPORT_SHARED_WEBTRANSPORTLOG_H_ + +#include "mozilla/Logging.h" + +namespace mozilla { +extern LazyLogModule gWebTransportLog; +} + +#define LOG(args) \ + MOZ_LOG(mozilla::gWebTransportLog, mozilla::LogLevel::Debug, args) + +#define LOG_VERBOSE(args) \ + MOZ_LOG(mozilla::gWebTransportLog, mozilla::LogLevel::Verbose, args) + +#define LOG_ENABLED() \ + MOZ_LOG_TEST(mozilla::gWebTransportLog, mozilla::LogLevel::Debug) + +#endif // DOM_WEBTRANSPORT_SHARED_WEBTRANSPORTLOG_H diff --git a/dom/webtransport/shared/moz.build b/dom/webtransport/shared/moz.build new file mode 100644 index 0000000000..2992b7dbeb --- /dev/null +++ b/dom/webtransport/shared/moz.build @@ -0,0 +1,21 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +EXPORTS.mozilla.dom += [ + "WebTransportLog.h", +] + +UNIFIED_SOURCES += [ + "WebTransportLog.cpp", +] + +FINAL_LIBRARY = "xul" + +IPDL_SOURCES += [ + "PWebTransport.ipdl", +] + +include("/ipc/chromium/chromium-config.mozbuild") diff --git a/dom/webtransport/test/moz.build b/dom/webtransport/test/moz.build new file mode 100644 index 0000000000..ddf7e1f9a9 --- /dev/null +++ b/dom/webtransport/test/moz.build @@ -0,0 +1,9 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +TEST_DIRS += [ + "xpcshell", +] diff --git a/dom/webtransport/test/xpcshell/moz.build b/dom/webtransport/test/xpcshell/moz.build new file mode 100644 index 0000000000..3d85532034 --- /dev/null +++ b/dom/webtransport/test/xpcshell/moz.build @@ -0,0 +1,9 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +XPCSHELL_TESTS_MANIFESTS += [ + "xpcshell.ini", +] diff --git a/dom/webtransport/test/xpcshell/test_close.js b/dom/webtransport/test/xpcshell/test_close.js new file mode 100644 index 0000000000..458b933ff3 --- /dev/null +++ b/dom/webtransport/test/xpcshell/test_close.js @@ -0,0 +1,64 @@ +// +// Simple WebTransport test +// +// keep eslint happy until it knows about WebTransport +/* global WebTransport:false */ + +"use strict"; + +var h3Port; +var host; + +registerCleanupFunction(async () => { + Services.prefs.clearUserPref("network.dns.localDomains"); +}); + +var { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); + +function readFile(file) { + let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance( + Ci.nsIFileInputStream + ); + fstream.init(file, -1, 0, 0); + let data = NetUtil.readInputStreamToString(fstream, fstream.available()); + fstream.close(); + return data; +} + +function addCertFromFile(certdb, filename, trustString) { + let certFile = do_get_file(filename, false); + let pem = readFile(certFile) + .replace(/-----BEGIN CERTIFICATE-----/, "") + .replace(/-----END CERTIFICATE-----/, "") + .replace(/[\r\n]/g, ""); + certdb.addCertFromBase64(pem, trustString); +} + +add_task(async function setup() { + Services.prefs.setCharPref("network.dns.localDomains", "foo.example.com"); + + h3Port = Services.env.get("MOZHTTP3_PORT"); + Assert.notEqual(h3Port, null); + Assert.notEqual(h3Port, ""); + host = "foo.example.com:" + h3Port; + do_get_profile(); + + let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService( + Ci.nsIX509CertDB + ); + // `../unit/` so that unit_ipc tests can use as well + addCertFromFile( + certdb, + "../../../../netwerk/test/unit/http2-ca.pem", + "CTu,u,u" + ); +}); + +add_task(async function test_webtransport_create() { + Services.prefs.setBoolPref("network.webtransport.enabled", true); + + const wt = new WebTransport("https://" + host + "/success"); + await wt.ready; + + wt.close(); +}); diff --git a/dom/webtransport/test/xpcshell/xpcshell.ini b/dom/webtransport/test/xpcshell/xpcshell.ini new file mode 100644 index 0000000000..816e096aa0 --- /dev/null +++ b/dom/webtransport/test/xpcshell/xpcshell.ini @@ -0,0 +1,11 @@ +# 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/. + +[DEFAULT] + +# XXX figure out why android doesn't get MOZHTTP3_PORT +[test_close.js] +skip-if = + os == 'android' || socketprocess_networking + os == 'win' && msix # https://bugzilla.mozilla.org/show_bug.cgi?id=1807925 |