summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/http/ObliviousHttpChannel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/protocol/http/ObliviousHttpChannel.cpp')
-rw-r--r--netwerk/protocol/http/ObliviousHttpChannel.cpp860
1 files changed, 860 insertions, 0 deletions
diff --git a/netwerk/protocol/http/ObliviousHttpChannel.cpp b/netwerk/protocol/http/ObliviousHttpChannel.cpp
new file mode 100644
index 0000000000..fafbf84b0b
--- /dev/null
+++ b/netwerk/protocol/http/ObliviousHttpChannel.cpp
@@ -0,0 +1,860 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et 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/. */
+
+// HttpLog.h should generally be included first
+#include "HttpLog.h"
+
+#include "ObliviousHttpChannel.h"
+
+#include "BinaryHttpRequest.h"
+#include "nsIHttpHeaderVisitor.h"
+#include "nsStringStream.h"
+
+namespace mozilla::net {
+
+NS_IMPL_ISUPPORTS(ObliviousHttpChannel, nsIChannel, nsIHttpChannel,
+ nsIObliviousHttpChannel, nsIHttpChannelInternal,
+ nsIIdentChannel, nsIRequest, nsIRequestObserver,
+ nsIStreamListener, nsIUploadChannel2, nsITimedChannel)
+
+ObliviousHttpChannel::ObliviousHttpChannel(
+ nsIURI* targetURI, const nsTArray<uint8_t>& encodedConfig,
+ nsIHttpChannel* innerChannel)
+ : mTargetURI(targetURI),
+ mEncodedConfig(encodedConfig.Clone()),
+ mInnerChannel(innerChannel),
+ mInnerChannelInternal(do_QueryInterface(innerChannel)),
+ mInnerChannelTimed(do_QueryInterface(innerChannel)) {
+ LOG(("ObliviousHttpChannel ctor [this=%p]", this));
+ MOZ_ASSERT(mInnerChannel);
+ MOZ_ASSERT(mInnerChannelInternal);
+ MOZ_ASSERT(mInnerChannelTimed);
+}
+
+ObliviousHttpChannel::~ObliviousHttpChannel() {
+ LOG(("ObliviousHttpChannel dtor [this=%p]", this));
+}
+
+//-----------------------------------------------------------------------------
+// ObliviousHttpChannel::nsIHttpChannel
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetTopLevelContentWindowId(uint64_t* aWindowId) {
+ return mInnerChannel->GetTopLevelContentWindowId(aWindowId);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetTopLevelContentWindowId(uint64_t aWindowId) {
+ return mInnerChannel->SetTopLevelContentWindowId(aWindowId);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetBrowserId(uint64_t* aWindowId) {
+ return mInnerChannel->GetBrowserId(aWindowId);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetBrowserId(uint64_t aId) {
+ return mInnerChannel->SetBrowserId(aId);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetTransferSize(uint64_t* aTransferSize) {
+ return mInnerChannel->GetTransferSize(aTransferSize);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetRequestSize(uint64_t* aRequestSize) {
+ return mInnerChannel->GetRequestSize(aRequestSize);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetDecodedBodySize(uint64_t* aDecodedBodySize) {
+ return mInnerChannel->GetDecodedBodySize(aDecodedBodySize);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetRequestMethod(nsACString& aRequestMethod) {
+ aRequestMethod.Assign(mMethod);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetRequestMethod(const nsACString& aRequestMethod) {
+ mMethod.Assign(aRequestMethod);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetReferrerInfo(nsIReferrerInfo** aReferrerInfo) {
+ return mInnerChannel->GetReferrerInfo(aReferrerInfo);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
+ return mInnerChannel->SetReferrerInfo(aReferrerInfo);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetReferrerInfoWithoutClone(
+ nsIReferrerInfo* aReferrerInfo) {
+ return mInnerChannel->SetReferrerInfoWithoutClone(aReferrerInfo);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetRequestHeader(const nsACString& aHeader,
+ nsACString& _retval) {
+ _retval.Truncate();
+ auto value = mHeaders.Lookup(aHeader);
+ if (!value) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ _retval.Assign(*value);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetRequestHeader(const nsACString& aHeader,
+ const nsACString& aValue, bool aMerge) {
+ mHeaders.WithEntryHandle(aHeader, [&aValue, aMerge](auto&& entry) {
+ if (!entry) {
+ entry.Insert(aValue);
+ return;
+ }
+ if (!aMerge) {
+ entry.Update(aValue);
+ return;
+ }
+ nsAutoCString newValue(*entry);
+ newValue.AppendLiteral(", ");
+ newValue.Append(aValue);
+ entry.Update(newValue);
+ });
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetNewReferrerInfo(
+ const nsACString& aUrl, nsIReferrerInfo::ReferrerPolicyIDL aPolicy,
+ bool aSendReferrer) {
+ return mInnerChannel->SetNewReferrerInfo(aUrl, aPolicy, aSendReferrer);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetEmptyRequestHeader(const nsACString& aHeader) {
+ return SetRequestHeader(aHeader, EmptyCString(), false);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::VisitRequestHeaders(nsIHttpHeaderVisitor* aVisitor) {
+ for (auto iter = mHeaders.ConstIter(); !iter.Done(); iter.Next()) {
+ nsresult rv = aVisitor->VisitHeader(iter.Key(), iter.Data());
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::VisitNonDefaultRequestHeaders(
+ nsIHttpHeaderVisitor* aVisitor) {
+ return mInnerChannel->VisitNonDefaultRequestHeaders(aVisitor);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetAllowSTS(bool* aAllowSTS) {
+ return mInnerChannel->GetAllowSTS(aAllowSTS);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetAllowSTS(bool aAllowSTS) {
+ return mInnerChannel->SetAllowSTS(aAllowSTS);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetRedirectionLimit(uint32_t* aRedirectionLimit) {
+ return mInnerChannel->GetRedirectionLimit(aRedirectionLimit);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetRedirectionLimit(uint32_t aRedirectionLimit) {
+ return mInnerChannel->SetRedirectionLimit(aRedirectionLimit);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetResponseStatus(uint32_t* aResponseStatus) {
+ if (!mBinaryHttpResponse) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ uint16_t responseStatus;
+ nsresult rv = mBinaryHttpResponse->GetStatus(&responseStatus);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ *aResponseStatus = responseStatus;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetResponseStatusText(nsACString& aResponseStatusText) {
+ LOG(("ObliviousHttpChannel::GetResponseStatusText NOT IMPLEMENTED [this=%p]",
+ this));
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetRequestSucceeded(bool* aRequestSucceeded) {
+ uint32_t responseStatus;
+ nsresult rv = GetResponseStatus(&responseStatus);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ *aRequestSucceeded = (responseStatus / 100) == 2;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetIsMainDocumentChannel(bool* aValue) {
+ return mInnerChannel->GetIsMainDocumentChannel(aValue);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetIsMainDocumentChannel(bool aValue) {
+ return mInnerChannel->SetIsMainDocumentChannel(aValue);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetResponseHeader(const nsACString& header,
+ nsACString& _retval) {
+ if (!mBinaryHttpResponse) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ nsTArray<nsCString> responseHeaderNames;
+ nsTArray<nsCString> responseHeaderValues;
+ nsresult rv = mBinaryHttpResponse->GetHeaderNames(responseHeaderNames);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = mBinaryHttpResponse->GetHeaderValues(responseHeaderValues);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ for (size_t i = 0;
+ i < responseHeaderNames.Length() && i < responseHeaderValues.Length();
+ i++) {
+ if (responseHeaderNames[i].EqualsIgnoreCase(header)) {
+ _retval.Assign(responseHeaderValues[i]);
+ return NS_OK;
+ }
+ }
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetResponseHeader(const nsACString& header,
+ const nsACString& value, bool merge) {
+ LOG(("ObliviousHttpChannel::SetResponseHeader NOT IMPLEMENTED [this=%p]",
+ this));
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::VisitResponseHeaders(nsIHttpHeaderVisitor* aVisitor) {
+ if (!mBinaryHttpResponse) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ nsTArray<nsCString> responseHeaderNames;
+ nsTArray<nsCString> responseHeaderValues;
+ nsresult rv = mBinaryHttpResponse->GetHeaderNames(responseHeaderNames);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = mBinaryHttpResponse->GetHeaderValues(responseHeaderValues);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ for (size_t i = 0;
+ i < responseHeaderNames.Length() && i < responseHeaderValues.Length();
+ i++) {
+ rv = aVisitor->VisitHeader(responseHeaderNames[i], responseHeaderValues[i]);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetOriginalResponseHeader(
+ const nsACString& header, nsIHttpHeaderVisitor* aVisitor) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::VisitOriginalResponseHeaders(
+ nsIHttpHeaderVisitor* aVisitor) {
+ LOG(
+ ("ObliviousHttpChannel::VisitOriginalResponseHeaders NOT IMPLEMENTED "
+ "[this=%p]",
+ this));
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::ShouldStripRequestBodyHeader(const nsACString& aMethod,
+ bool* aResult) {
+ LOG(
+ ("ObliviousHttpChannel::ShouldStripRequestBodyHeader NOT IMPLEMENTED "
+ "[this=%p]",
+ this));
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::IsNoStoreResponse(bool* _retval) {
+ LOG(("ObliviousHttpChannel::IsNoStoreResponse NOT IMPLEMENTED [this=%p]",
+ this));
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::IsNoCacheResponse(bool* _retval) {
+ LOG(("ObliviousHttpChannel::IsNoCacheResponse NOT IMPLEMENTED [this=%p]",
+ this));
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::IsPrivateResponse(bool* _retval) {
+ LOG(("ObliviousHttpChannel::IsPrivateResponse NOT IMPLEMENTED [this=%p]",
+ this));
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::RedirectTo(nsIURI* aNewURI) {
+ LOG(("ObliviousHttpChannel::RedirectTo NOT IMPLEMENTED [this=%p]", this));
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::UpgradeToSecure() {
+ LOG(("ObliviousHttpChannel::UpgradeToSecure NOT IMPLEMENTED [this=%p]",
+ this));
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetRequestContextID(uint64_t* _retval) {
+ return mInnerChannel->GetRequestContextID(_retval);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetRequestContextID(uint64_t rcID) {
+ return mInnerChannel->SetRequestContextID(rcID);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetProtocolVersion(nsACString& aProtocolVersion) {
+ return mInnerChannel->GetProtocolVersion(aProtocolVersion);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetEncodedBodySize(uint64_t* aEncodedBodySize) {
+ LOG(("ObliviousHttpChannel::GetEncodedBodySize NOT IMPLEMENTED [this=%p]",
+ this));
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::LogBlockedCORSRequest(const nsAString& aMessage,
+ const nsACString& aCategory,
+ bool aIsWarning) {
+ return mInnerChannel->LogBlockedCORSRequest(aMessage, aCategory, aIsWarning);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::LogMimeTypeMismatch(const nsACString& aMessageName,
+ bool aWarning, const nsAString& aURL,
+ const nsAString& aContentType) {
+ return mInnerChannel->LogMimeTypeMismatch(aMessageName, aWarning, aURL,
+ aContentType);
+}
+
+void ObliviousHttpChannel::SetSource(
+ mozilla::UniquePtr<mozilla::ProfileChunkedBuffer> aSource) {
+ LOG(("ObliviousHttpChannel::SetSource NOT IMPLEMENTED [this=%p]", this));
+ // NS_ERROR_NOT_IMPLEMENTED
+}
+
+void ObliviousHttpChannel::SetConnectionInfo(nsHttpConnectionInfo* aCi) {
+ if (mInnerChannelInternal) {
+ mInnerChannelInternal->SetConnectionInfo(aCi);
+ }
+}
+
+void ObliviousHttpChannel::DoDiagnosticAssertWhenOnStopNotCalledOnDestroy() {
+ if (mInnerChannelInternal) {
+ mInnerChannelInternal->DoDiagnosticAssertWhenOnStopNotCalledOnDestroy();
+ }
+}
+
+void ObliviousHttpChannel::DisableAltDataCache() {
+ if (mInnerChannelInternal) {
+ mInnerChannelInternal->DisableAltDataCache();
+ }
+}
+
+void ObliviousHttpChannel::SetAltDataForChild(bool aIsForChild) {
+ if (mInnerChannelInternal) {
+ mInnerChannelInternal->SetAltDataForChild(aIsForChild);
+ }
+}
+
+void ObliviousHttpChannel::SetCorsPreflightParameters(
+ nsTArray<nsTString<char>> const& aUnsafeHeaders,
+ bool aShouldStripRequestBodyHeader) {
+ if (mInnerChannelInternal) {
+ mInnerChannelInternal->SetCorsPreflightParameters(
+ aUnsafeHeaders, aShouldStripRequestBodyHeader);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// ObliviousHttpChannel::nsIChannel
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetOriginalURI(nsIURI** aOriginalURI) {
+ return mInnerChannel->GetOriginalURI(aOriginalURI);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetOriginalURI(nsIURI* aOriginalURI) {
+ return mInnerChannel->SetOriginalURI(aOriginalURI);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetURI(nsIURI** aURI) {
+ *aURI = do_AddRef(mTargetURI).take();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetOwner(nsISupports** aOwner) {
+ return mInnerChannel->GetOwner(aOwner);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetOwner(nsISupports* aOwner) {
+ return mInnerChannel->SetOwner(aOwner);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetNotificationCallbacks(
+ nsIInterfaceRequestor** aNotificationCallbacks) {
+ return mInnerChannel->GetNotificationCallbacks(aNotificationCallbacks);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetNotificationCallbacks(
+ nsIInterfaceRequestor* aNotificationCallbacks) {
+ return mInnerChannel->SetNotificationCallbacks(aNotificationCallbacks);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetSecurityInfo(
+ nsITransportSecurityInfo** aSecurityInfo) {
+ return mInnerChannel->GetSecurityInfo(aSecurityInfo);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetContentType(nsACString& aContentType) {
+ return GetResponseHeader("content-type"_ns, aContentType);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetContentType(const nsACString& aContentType) {
+ mContentType = aContentType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetContentCharset(nsACString& aContentCharset) {
+ return mInnerChannel->GetContentCharset(aContentCharset);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetContentCharset(const nsACString& aContentCharset) {
+ return mInnerChannel->SetContentCharset(aContentCharset);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetContentLength(int64_t* aContentLength) {
+ return mInnerChannel->GetContentLength(aContentLength);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetContentLength(int64_t aContentLength) {
+ return mInnerChannel->SetContentLength(aContentLength);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::Open(nsIInputStream** aStream) {
+ LOG(("ObliviousHttpChannel::Open NOT IMPLEMENTED [this=%p]", this));
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::AsyncOpen(nsIStreamListener* aListener) {
+ LOG(("ObliviousHttpChannel::AsyncOpen [this=%p, listener=%p]", this,
+ aListener));
+ mStreamListener = aListener;
+ nsresult rv = mInnerChannel->SetRequestMethod("POST"_ns);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = mInnerChannel->SetRequestHeader("Content-Type"_ns,
+ "message/ohttp-req"_ns, false);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ nsAutoCString scheme;
+ if (!mTargetURI) {
+ return NS_ERROR_NULL_POINTER;
+ }
+ rv = mTargetURI->GetScheme(scheme);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ nsAutoCString authority;
+ rv = mTargetURI->GetHostPort(authority);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ nsAutoCString path;
+ rv = mTargetURI->GetPathQueryRef(path);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ nsTArray<nsCString> headerNames;
+ nsTArray<nsCString> headerValues;
+ for (auto iter = mHeaders.ConstIter(); !iter.Done(); iter.Next()) {
+ headerNames.AppendElement(iter.Key());
+ headerValues.AppendElement(iter.Data());
+ }
+ if (!mContentType.IsEmpty() && !headerNames.Contains("Content-Type")) {
+ headerNames.AppendElement("Content-Type"_ns);
+ headerValues.AppendElement(mContentType);
+ }
+ nsCOMPtr<nsIBinaryHttp> bhttp(
+ do_GetService("@mozilla.org/network/binary-http;1"));
+ nsCOMPtr<nsIBinaryHttpRequest> bhttpRequest(new BinaryHttpRequest(
+ mMethod, scheme, authority, path, std::move(headerNames),
+ std::move(headerValues), std::move(mContent)));
+ nsTArray<uint8_t> encodedRequest;
+ rv = bhttp->EncodeRequest(bhttpRequest, encodedRequest);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ nsCOMPtr<nsIObliviousHttp> obliviousHttp(
+ do_GetService("@mozilla.org/network/oblivious-http;1"));
+ if (!obliviousHttp) {
+ return NS_ERROR_FAILURE;
+ }
+ rv = obliviousHttp->EncapsulateRequest(mEncodedConfig, encodedRequest,
+ getter_AddRefs(mEncapsulatedRequest));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ nsTArray<uint8_t> encRequest;
+ rv = mEncapsulatedRequest->GetEncRequest(encRequest);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ nsCOMPtr<nsIUploadChannel2> uploadChannel(do_QueryInterface(mInnerChannel));
+ if (!uploadChannel) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ nsCOMPtr<nsIInputStream> uploadStream;
+ uint32_t streamLength = encRequest.Length();
+ rv = NS_NewByteInputStream(getter_AddRefs(uploadStream),
+ std::move(encRequest));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = uploadChannel->ExplicitSetUploadStream(
+ uploadStream, "message/ohttp-req"_ns, streamLength, "POST"_ns, false);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return mInnerChannel->AsyncOpen(this);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetCanceled(bool* aCanceled) {
+ return mInnerChannel->GetCanceled(aCanceled);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetContentDisposition(uint32_t* aContentDisposition) {
+ return mInnerChannel->GetContentDisposition(aContentDisposition);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetContentDisposition(uint32_t aContentDisposition) {
+ return mInnerChannel->SetContentDisposition(aContentDisposition);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetContentDispositionFilename(
+ nsAString& aContentDispositionFilename) {
+ return mInnerChannel->GetContentDispositionFilename(
+ aContentDispositionFilename);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetContentDispositionFilename(
+ const nsAString& aContentDispositionFilename) {
+ return mInnerChannel->SetContentDispositionFilename(
+ aContentDispositionFilename);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetContentDispositionHeader(
+ nsACString& aContentDispositionHeader) {
+ return mInnerChannel->GetContentDispositionHeader(aContentDispositionHeader);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetLoadInfo(nsILoadInfo** aLoadInfo) {
+ return mInnerChannel->GetLoadInfo(aLoadInfo);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::SetLoadInfo(nsILoadInfo* aLoadInfo) {
+ return mInnerChannel->SetLoadInfo(aLoadInfo);
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetIsDocument(bool* aIsDocument) {
+ return mInnerChannel->GetIsDocument(aIsDocument);
+}
+
+//-----------------------------------------------------------------------------
+// ObliviousHttpChannel::nsIStreamListener
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+ObliviousHttpChannel::OnDataAvailable(nsIRequest* aRequest,
+ nsIInputStream* aStream, uint64_t aOffset,
+ uint32_t aCount) {
+ LOG(
+ ("ObliviousHttpChannel::OnDataAvailable [this=%p, request=%p, stream=%p, "
+ "offset=%" PRIu64 ", count=%u]",
+ this, aRequest, aStream, aOffset, aCount));
+ MOZ_ASSERT(aOffset == mRawResponse.Length());
+ size_t oldLength = mRawResponse.Length();
+ size_t newLength = oldLength + aCount;
+ if (newLength < oldLength) { // i.e., overflow
+ return NS_ERROR_FAILURE;
+ }
+ mRawResponse.SetCapacity(newLength);
+ mRawResponse.SetLengthAndRetainStorage(newLength);
+ void* dest = mRawResponse.Elements() + oldLength;
+ uint64_t written = 0;
+ nsresult rv = NS_ReadInputStreamToBuffer(aStream, &dest, aCount, &written);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ if (written != aCount) {
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// ObliviousHttpChannel::nsIRequestObserver
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+ObliviousHttpChannel::OnStartRequest(nsIRequest* aRequest) {
+ LOG(("ObliviousHttpChannel::OnStartRequest [this=%p, request=%p]", this,
+ aRequest));
+ return NS_OK;
+}
+
+nsresult ObliviousHttpChannel::ProcessOnStopRequest() {
+ if (mRawResponse.IsEmpty()) {
+ return NS_OK;
+ }
+ nsCOMPtr<nsIObliviousHttp> obliviousHttp(
+ do_GetService("@mozilla.org/network/oblivious-http;1"));
+ if (!obliviousHttp) {
+ return NS_ERROR_FAILURE;
+ }
+ nsCOMPtr<nsIObliviousHttpClientResponse> response;
+ nsresult rv = mEncapsulatedRequest->GetResponse(getter_AddRefs(response));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ nsTArray<uint8_t> decapsulated;
+ rv = response->Decapsulate(mRawResponse, decapsulated);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ nsCOMPtr<nsIBinaryHttp> bhttp(
+ do_GetService("@mozilla.org/network/binary-http;1"));
+ if (!bhttp) {
+ return NS_ERROR_FAILURE;
+ }
+ return bhttp->DecodeResponse(decapsulated,
+ getter_AddRefs(mBinaryHttpResponse));
+}
+
+void ObliviousHttpChannel::EmitOnDataAvailable() {
+ if (!mBinaryHttpResponse) {
+ return;
+ }
+ nsTArray<uint8_t> content;
+ nsresult rv = mBinaryHttpResponse->GetContent(content);
+ if (NS_FAILED(rv)) {
+ return;
+ }
+ if (content.IsEmpty()) {
+ return;
+ }
+ if (content.Length() > std::numeric_limits<uint32_t>::max()) {
+ return;
+ }
+ uint32_t contentLength = (uint32_t)content.Length();
+ nsCOMPtr<nsIInputStream> contentStream;
+ rv = NS_NewByteInputStream(getter_AddRefs(contentStream), std::move(content));
+ if (NS_FAILED(rv)) {
+ return;
+ }
+ rv = mStreamListener->OnDataAvailable(this, contentStream, 0, contentLength);
+ Unused << rv;
+}
+
+NS_IMETHODIMP
+ObliviousHttpChannel::OnStopRequest(nsIRequest* aRequest,
+ nsresult aStatusCode) {
+ LOG(("ObliviousHttpChannel::OnStopRequest [this=%p, request=%p, status=%u]",
+ this, aRequest, (uint32_t)aStatusCode));
+
+ auto releaseStreamListener = MakeScopeExit(
+ [self = RefPtr{this}]() mutable { self->mStreamListener = nullptr; });
+
+ if (NS_SUCCEEDED(aStatusCode)) {
+ bool requestSucceeded;
+ nsresult rv = mInnerChannel->GetRequestSucceeded(&requestSucceeded);
+ if (NS_SUCCEEDED(rv) && requestSucceeded) {
+ aStatusCode = ProcessOnStopRequest();
+ }
+ }
+ Unused << mStreamListener->OnStartRequest(this);
+ if (NS_SUCCEEDED(aStatusCode)) {
+ EmitOnDataAvailable();
+ }
+ Unused << mStreamListener->OnStopRequest(this, aStatusCode);
+
+ return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// ObliviousHttpChannel::nsIObliviousHttpChannel
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+ObliviousHttpChannel::GetRelayChannel(nsIHttpChannel** aChannel) {
+ if (!aChannel) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ *aChannel = do_AddRef(mInnerChannel).take();
+ return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// ObliviousHttpChannel::nsIUploadChannel2
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP ObliviousHttpChannel::ExplicitSetUploadStream(
+ nsIInputStream* aStream, const nsACString& aContentType,
+ int64_t aContentLength, const nsACString& aMethod, bool aStreamHasHeaders) {
+ // This function should only be called before AsyncOpen.
+ if (mStreamListener) {
+ return NS_ERROR_IN_PROGRESS;
+ }
+ if (aMethod != "POST"_ns || aStreamHasHeaders) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ mMethod.Assign(aMethod);
+ uint64_t available;
+ if (aContentLength < 0) {
+ nsresult rv = aStream->Available(&available);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ } else {
+ available = aContentLength;
+ }
+ if (available > std::numeric_limits<int64_t>::max()) {
+ return NS_ERROR_FAILURE;
+ }
+ mContent.SetCapacity(available);
+ mContent.SetLengthAndRetainStorage(available);
+ void* dest = mContent.Elements();
+ uint64_t written = 0;
+ nsresult rv =
+ NS_ReadInputStreamToBuffer(aStream, &dest, (int64_t)available, &written);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ if (written != available) {
+ return NS_ERROR_FAILURE;
+ }
+ mContentType = aContentType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP ObliviousHttpChannel::GetUploadStreamHasHeaders(
+ bool* aUploadStreamHasHeaders) {
+ *aUploadStreamHasHeaders = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP ObliviousHttpChannel::CloneUploadStream(
+ int64_t* aContentLength, nsIInputStream** _retval) {
+ LOG(("ObliviousHttpChannel::CloneUploadStream NOT IMPLEMENTED [this=%p]",
+ this));
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP ObliviousHttpChannel::SetClassicScriptHintCharset(
+ const nsAString& aClassicScriptHintCharset) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP ObliviousHttpChannel::GetClassicScriptHintCharset(
+ nsAString& aClassicScriptHintCharset) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP ObliviousHttpChannel::SetDocumentCharacterSet(
+ const nsAString& aDocumentCharacterSet) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP ObliviousHttpChannel::GetDocumentCharacterSet(
+ nsAString& aDocumenharacterSet) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+} // namespace mozilla::net