Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/netwerk/protocol/gio/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 14 kB image not shown  

Quelle  GIOChannelChild.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=4 sw=2 sts=2 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/. */


#include "mozilla/net/NeckoChild.h"
#include "GIOChannelChild.h"
#include "nsGIOProtocolHandler.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/BrowserChild.h"
#include "nsContentUtils.h"
#include "nsIBrowserChild.h"
#include "nsStringStream.h"
#include "nsNetUtil.h"
#include "mozilla/ipc/IPCStreamUtils.h"
#include "mozilla/ipc/URIUtils.h"
#include "SerializedLoadContext.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "nsIURIMutator.h"
#include "nsContentSecurityManager.h"
#include "SerializedLoadContext.h"
#include "mozilla/Logging.h"

using mozilla::dom::ContentChild;

namespace mozilla {
#undef LOG
#define LOG(args) MOZ_LOG(gGIOLog, mozilla::LogLevel::Debug, args)
namespace net {

GIOChannelChild::GIOChannelChild(nsIURI* aUri)
    : mEventQ(new ChannelEventQueue(static_cast<nsIChildChannel*>(this))) {
  SetURI(aUri);
  // We could support thread retargeting, but as long as we're being driven by
  // IPDL on the main thread it doesn't buy us anything.
  DisallowThreadRetargeting();
}

void GIOChannelChild::AddIPDLReference() {
  MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference");
  mIPCOpen = true;
  AddRef();
}

void GIOChannelChild::ReleaseIPDLReference() {
  MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference");
  mIPCOpen = false;
  Release();
}

//-----------------------------------------------------------------------------
// GIOChannelChild::nsISupports
//-----------------------------------------------------------------------------

NS_IMPL_ISUPPORTS_INHERITED(GIOChannelChild, nsBaseChannel, nsIChildChannel)

//-----------------------------------------------------------------------------

NS_IMETHODIMP
GIOChannelChild::AsyncOpen(nsIStreamListener* aListener) {
  nsCOMPtr<nsIStreamListener> listener = aListener;
  nsresult rv =
      nsContentSecurityManager::doContentSecurityCheck(this, listener);
  NS_ENSURE_SUCCESS(rv, rv);

  LOG(("GIOChannelChild::AsyncOpen [this=%p]\n"this));

  NS_ENSURE_TRUE((gNeckoChild), NS_ERROR_FAILURE);
  NS_ENSURE_TRUE(
      !static_cast<ContentChild*>(gNeckoChild->Manager())->IsShuttingDown(),
      NS_ERROR_FAILURE);
  NS_ENSURE_ARG_POINTER(listener);
  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);

  // Port checked in parent, but duplicate here so we can return with error
  // immediately, as we've done since before e10s.
  rv = NS_CheckPortSafety(nsBaseChannel::URI());  // Need to disambiguate,
                                                  // because in the child ipdl,
                                                  // a typedef URI is defined...
  if (NS_FAILED(rv)) {
    return rv;
  }

  mozilla::dom::BrowserChild* browserChild = nullptr;
  nsCOMPtr<nsIBrowserChild> iBrowserChild;
  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
                                NS_GET_IID(nsIBrowserChild),
                                getter_AddRefs(iBrowserChild));
  GetCallback(iBrowserChild);
  if (iBrowserChild) {
    browserChild =
        static_cast<mozilla::dom::BrowserChild*>(iBrowserChild.get());
  }

  mListener = listener;

  // add ourselves to the load group.
  if (mLoadGroup) {
    mLoadGroup->AddRequest(this, nullptr);
  }

  Maybe<mozilla::ipc::IPCStream> ipcStream;
  mozilla::ipc::SerializeIPCStream(do_AddRef(mUploadStream), ipcStream,
                                   /* aAllowLazy */ false);

  uint32_t loadFlags = 0;
  GetLoadFlags(&loadFlags);

  GIOChannelOpenArgs openArgs;
  SerializeURI(nsBaseChannel::URI(), openArgs.uri());
  openArgs.startPos() = mStartPos;
  openArgs.entityID() = mEntityID;
  openArgs.uploadStream() = ipcStream;
  openArgs.loadFlags() = loadFlags;

  nsCOMPtr<nsILoadInfo> loadInfo = LoadInfo();
  rv = mozilla::ipc::LoadInfoToLoadInfoArgs(loadInfo, &openArgs.loadInfo());
  NS_ENSURE_SUCCESS(rv, rv);

  // This must happen before the constructor message is sent.
  SetupNeckoTarget();

  // The socket transport layer in the chrome process now has a logical ref to
  // us until OnStopRequest is called.
  AddIPDLReference();

  if (!gNeckoChild->SendPGIOChannelConstructor(
          this, browserChild, IPC::SerializedLoadContext(this), openArgs)) {
    return NS_ERROR_FAILURE;
  }

  mIsPending = true;
  mWasOpened = true;

  return rv;
}

NS_IMETHODIMP
GIOChannelChild::IsPending(bool* aResult) {
  *aResult = mIsPending;
  return NS_OK;
}

nsresult GIOChannelChild::OpenContentStream(bool aAsync,
                                            nsIInputStream** aStream,
                                            nsIChannel** aChannel) {
  MOZ_CRASH("GIOChannel*Child* should never have OpenContentStream called!");
  return NS_OK;
}

mozilla::ipc::IPCResult GIOChannelChild::RecvOnStartRequest(
    const nsresult& aChannelStatus, const int64_t& aContentLength,
    const nsACString& aContentType, const nsACString& aEntityID,
    const URIParams& aURI) {
  LOG(("GIOChannelChild::RecvOnStartRequest [this=%p]\n"this));
  mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
      this, [self = UnsafePtr<GIOChannelChild>(this), aChannelStatus,
             aContentLength, aContentType = nsCString(aContentType),
             aEntityID = nsCString(aEntityID), aURI]() {
        self->DoOnStartRequest(aChannelStatus, aContentLength, aContentType,
                               aEntityID, aURI);
      }));
  return IPC_OK();
}

void GIOChannelChild::DoOnStartRequest(const nsresult& aChannelStatus,
                                       const int64_t& aContentLength,
                                       const nsACString& aContentType,
                                       const nsACString& aEntityID,
                                       const URIParams& aURI) {
  LOG(("GIOChannelChild::DoOnStartRequest [this=%p]\n"this));
  if (!mCanceled && NS_SUCCEEDED(mStatus)) {
    mStatus = aChannelStatus;
  }

  mContentLength = aContentLength;
  SetContentType(aContentType);
  mEntityID = aEntityID;

  nsCString spec;
  nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
  nsresult rv = uri->GetSpec(spec);
  if (NS_SUCCEEDED(rv)) {
    // Changes nsBaseChannel::URI()
    rv = NS_MutateURI(mURI).SetSpec(spec).Finalize(mURI);
  }

  if (NS_FAILED(rv)) {
    Cancel(rv);
  }

  AutoEventEnqueuer ensureSerialDispatch(mEventQ);
  rv = mListener->OnStartRequest(this);
  if (NS_FAILED(rv)) {
    Cancel(rv);
  }
}

mozilla::ipc::IPCResult GIOChannelChild::RecvOnDataAvailable(
    const nsresult& aChannelStatus, const nsACString& aData,
    const uint64_t& aOffset, const uint32_t& aCount) {
  LOG(("GIOChannelChild::RecvOnDataAvailable [this=%p]\n"this));
  mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
      this, [self = UnsafePtr<GIOChannelChild>(this), aChannelStatus,
             aData = nsCString(aData), aOffset, aCount]() {
        self->DoOnDataAvailable(aChannelStatus, aData, aOffset, aCount);
      }));

  return IPC_OK();
}

void GIOChannelChild::DoOnDataAvailable(const nsresult& aChannelStatus,
                                        const nsACString& aData,
                                        const uint64_t& aOffset,
                                        const uint32_t& aCount) {
  LOG(("GIOChannelChild::DoOnDataAvailable [this=%p]\n"this));

  if (!mCanceled && NS_SUCCEEDED(mStatus)) {
    mStatus = aChannelStatus;
  }

  if (mCanceled) {
    return;
  }

  // NOTE: the OnDataAvailable contract requires the client to read all the data
  // in the inputstream.  This code relies on that ('data' will go away after
  // this function).  Apparently the previous, non-e10s behavior was to actually
  // support only reading part of the data, allowing later calls to read the
  // rest.
  nsCOMPtr<nsIInputStream> stringStream;
  nsresult rv =
      NS_NewByteInputStream(getter_AddRefs(stringStream),
                            Span(aData).To(aCount), NS_ASSIGNMENT_DEPEND);
  if (NS_FAILED(rv)) {
    Cancel(rv);
    return;
  }

  AutoEventEnqueuer ensureSerialDispatch(mEventQ);
  rv = mListener->OnDataAvailable(this, stringStream, aOffset, aCount);
  if (NS_FAILED(rv)) {
    Cancel(rv);
  }
  stringStream->Close();
}

mozilla::ipc::IPCResult GIOChannelChild::RecvOnStopRequest(
    const nsresult& aChannelStatus) {
  LOG(("GIOChannelChild::RecvOnStopRequest [this=%p status=%" PRIx32 "]\n",
       thisstatic_cast<uint32_t>(aChannelStatus)));

  mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
      this, [self = UnsafePtr<GIOChannelChild>(this), aChannelStatus]() {
        self->DoOnStopRequest(aChannelStatus);
      }));
  return IPC_OK();
}

void GIOChannelChild::DoOnStopRequest(const nsresult& aChannelStatus) {
  LOG(("GIOChannelChild::DoOnStopRequest [this=%p status=%" PRIx32 "]\n"this,
       static_cast<uint32_t>(aChannelStatus)));

  if (!mCanceled) {
    mStatus = aChannelStatus;
  }

  {  // Ensure that all queued ipdl events are dispatched before
    // we initiate protocol deletion below.
    mIsPending = false;
    AutoEventEnqueuer ensureSerialDispatch(mEventQ);
    (void)mListener->OnStopRequest(this, aChannelStatus);

    mListener = nullptr;

    if (mLoadGroup) {
      mLoadGroup->RemoveRequest(this, nullptr, aChannelStatus);
    }
  }

  // This calls NeckoChild::DeallocPGIOChannelChild(), which deletes |this| if
  // IPDL holds the last reference.  Don't rely on |this| existing after here!
  Send__delete__(this);
}

mozilla::ipc::IPCResult GIOChannelChild::RecvFailedAsyncOpen(
    const nsresult& aStatusCode) {
  LOG(("GIOChannelChild::RecvFailedAsyncOpen [this=%p status=%" PRIx32 "]\n",
       thisstatic_cast<uint32_t>(aStatusCode)));
  mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
      this, [self = UnsafePtr<GIOChannelChild>(this), aStatusCode]() {
        self->DoFailedAsyncOpen(aStatusCode);
      }));
  return IPC_OK();
}

void GIOChannelChild::DoFailedAsyncOpen(const nsresult& aStatusCode) {
  LOG(("GIOChannelChild::DoFailedAsyncOpen [this=%p status=%" PRIx32 "]\n",
       thisstatic_cast<uint32_t>(aStatusCode)));
  mStatus = aStatusCode;

  if (mLoadGroup) {
    mLoadGroup->RemoveRequest(this, nullptr, aStatusCode);
  }

  if (mListener) {
    mListener->OnStartRequest(this);
    mIsPending = false;
    mListener->OnStopRequest(this, aStatusCode);
  } else {
    mIsPending = false;
  }

  mListener = nullptr;

  if (mIPCOpen) {
    Send__delete__(this);
  }
}

mozilla::ipc::IPCResult GIOChannelChild::RecvDeleteSelf() {
  mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
      this,
      [self = UnsafePtr<GIOChannelChild>(this)]() { self->DoDeleteSelf(); }));
  return IPC_OK();
}

void GIOChannelChild::DoDeleteSelf() {
  if (mIPCOpen) {
    Send__delete__(this);
  }
}

//-----------------------------------------------------------------------------
// GIOChannelChild::nsIResumableChannel
//-----------------------------------------------------------------------------

NS_IMETHODIMP
GIOChannelChild::Cancel(nsresult aStatus) {
  LOG(("GIOChannelChild::Cancel [this=%p]\n"this));

  if (mCanceled) {
    return NS_OK;
  }

  mCanceled = true;
  mStatus = aStatus;
  if (mIPCOpen) {
    SendCancel(aStatus);
  }
  return NS_OK;
}

NS_IMETHODIMP
GIOChannelChild::Suspend() {
  NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);

  LOG(("GIOChannelChild::Suspend [this=%p]\n"this));

  // SendSuspend only once, when suspend goes from 0 to 1.
  if (!mSuspendCount++) {
    SendSuspend();
    mSuspendSent = true;
  }
  mEventQ->Suspend();

  return NS_OK;
}

NS_IMETHODIMP
GIOChannelChild::Resume() {
  NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);

  LOG(("GIOChannelChild::Resume [this=%p]\n"this));

  // SendResume only once, when suspend count drops to 0.
  if (!--mSuspendCount && mSuspendSent) {
    SendResume();
  }
  mEventQ->Resume();

  return NS_OK;
}

//-----------------------------------------------------------------------------
// GIOChannelChild::nsIChildChannel
//-----------------------------------------------------------------------------

NS_IMETHODIMP
GIOChannelChild::ConnectParent(uint32_t aId) {
  NS_ENSURE_TRUE((gNeckoChild), NS_ERROR_FAILURE);
  NS_ENSURE_TRUE(
      !static_cast<ContentChild*>(gNeckoChild->Manager())->IsShuttingDown(),
      NS_ERROR_FAILURE);

  LOG(("GIOChannelChild::ConnectParent [this=%p]\n"this));

  mozilla::dom::BrowserChild* browserChild = nullptr;
  nsCOMPtr<nsIBrowserChild> iBrowserChild;
  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
                                NS_GET_IID(nsIBrowserChild),
                                getter_AddRefs(iBrowserChild));
  GetCallback(iBrowserChild);
  if (iBrowserChild) {
    browserChild =
        static_cast<mozilla::dom::BrowserChild*>(iBrowserChild.get());
  }

  // This must happen before the constructor message is sent.
  SetupNeckoTarget();

  // The socket transport in the chrome process now holds a logical ref to us
  // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
  AddIPDLReference();

  GIOChannelConnectArgs connectArgs(aId);

  if (!gNeckoChild->SendPGIOChannelConstructor(
          this, browserChild, IPC::SerializedLoadContext(this), connectArgs)) {
    return NS_ERROR_FAILURE;
  }

  return NS_OK;
}

NS_IMETHODIMP
GIOChannelChild::CompleteRedirectSetup(nsIStreamListener* aListener) {
  LOG(("GIOChannelChild::CompleteRedirectSetup [this=%p]\n"this));
  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);

  mIsPending = true;
  mWasOpened = true;
  mListener = aListener;

  // add ourselves to the load group.
  if (mLoadGroup) {
    mLoadGroup->AddRequest(this, nullptr);
  }

  // We already have an open IPDL connection to the parent. If on-modify-request
  // listeners or load group observers canceled us, let the parent handle it
  // and send it back to us naturally.
  return NS_OK;
}

void GIOChannelChild::SetupNeckoTarget() {
  if (mNeckoTarget) {
    return;
  }
  mNeckoTarget = GetMainThreadSerialEventTarget();
}

}  // namespace net
}  // namespace mozilla

100%


¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.