netwerk/base/nsRequestObserverProxy.cpp
author Jonathan Kingston <jkt@mozilla.com>
Wed, 27 Feb 2019 23:41:04 +0000
changeset 461558 b5f7ff4ca9b58d002c2bebe0a11b529680068b0c
parent 460836 d5643033fdd801efda790a2836a3e196e7ba442e
child 461559 c48f47f793c0f0d9b4acf2caf9324b8bd7a5a683
permissions -rw-r--r--
Bug 1525319 - Removing context from OnStartRequest r=valentin Differential Revision: https://phabricator.services.mozilla.com/D20769

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/DebugOnly.h"

#include "nscore.h"
#include "nsRequestObserverProxy.h"
#include "nsIRequest.h"
#include "nsAutoPtr.h"
#include "mozilla/Logging.h"
#include "mozilla/IntegerPrintfMacros.h"

namespace mozilla {
namespace net {

static LazyLogModule gRequestObserverProxyLog("nsRequestObserverProxy");

#undef LOG
#define LOG(args) MOZ_LOG(gRequestObserverProxyLog, LogLevel::Debug, args)

//-----------------------------------------------------------------------------
// nsARequestObserverEvent internal class...
//-----------------------------------------------------------------------------

nsARequestObserverEvent::nsARequestObserverEvent(nsIRequest *request)
    : Runnable("net::nsARequestObserverEvent"), mRequest(request) {
  MOZ_ASSERT(mRequest, "null pointer");
}

//-----------------------------------------------------------------------------
// nsOnStartRequestEvent internal class...
//-----------------------------------------------------------------------------

class nsOnStartRequestEvent : public nsARequestObserverEvent {
  RefPtr<nsRequestObserverProxy> mProxy;

 public:
  nsOnStartRequestEvent(nsRequestObserverProxy *proxy, nsIRequest *request)
      : nsARequestObserverEvent(request), mProxy(proxy) {
    MOZ_ASSERT(mProxy, "null pointer");
  }

  virtual ~nsOnStartRequestEvent() = default;

  NS_IMETHOD Run() override {
    LOG(("nsOnStartRequestEvent::HandleEvent [req=%p]\n", mRequest.get()));

    if (!mProxy->mObserver) {
      MOZ_ASSERT_UNREACHABLE(
          "already handled onStopRequest event "
          "(observer is null)");
      return NS_OK;
    }

    LOG(("handle startevent=%p\n", this));
    nsresult rv = mProxy->mObserver->OnStartRequest(mRequest);
    if (NS_FAILED(rv)) {
      LOG(("OnStartRequest failed [rv=%" PRIx32 "] canceling request!\n",
           static_cast<uint32_t>(rv)));
      rv = mRequest->Cancel(rv);
      NS_ASSERTION(NS_SUCCEEDED(rv), "Cancel failed for request!");
    }

    return NS_OK;
  }
};

//-----------------------------------------------------------------------------
// nsOnStopRequestEvent internal class...
//-----------------------------------------------------------------------------

class nsOnStopRequestEvent : public nsARequestObserverEvent {
  RefPtr<nsRequestObserverProxy> mProxy;

 public:
  nsOnStopRequestEvent(nsRequestObserverProxy *proxy, nsIRequest *request)
      : nsARequestObserverEvent(request), mProxy(proxy) {
    MOZ_ASSERT(mProxy, "null pointer");
  }

  virtual ~nsOnStopRequestEvent() = default;

  NS_IMETHOD Run() override {
    LOG(("nsOnStopRequestEvent::HandleEvent [req=%p]\n", mRequest.get()));

    nsMainThreadPtrHandle<nsIRequestObserver> observer = mProxy->mObserver;
    if (!observer) {
      MOZ_ASSERT_UNREACHABLE(
          "already handled onStopRequest event "
          "(observer is null)");
      return NS_OK;
    }
    // Do not allow any more events to be handled after OnStopRequest
    mProxy->mObserver = nullptr;

    nsresult status = NS_OK;
    DebugOnly<nsresult> rv = mRequest->GetStatus(&status);
    NS_ASSERTION(NS_SUCCEEDED(rv), "GetStatus failed for request!");

    LOG(("handle stopevent=%p\n", this));
    (void)observer->OnStopRequest(mRequest, mProxy->mContext, status);

    return NS_OK;
  }
};

//-----------------------------------------------------------------------------
// nsRequestObserverProxy::nsISupports implementation...
//-----------------------------------------------------------------------------

NS_IMPL_ISUPPORTS(nsRequestObserverProxy, nsIRequestObserver,
                  nsIRequestObserverProxy)

//-----------------------------------------------------------------------------
// nsRequestObserverProxy::nsIRequestObserver implementation...
//-----------------------------------------------------------------------------

NS_IMETHODIMP
nsRequestObserverProxy::OnStartRequest(nsIRequest *request) {
  LOG(("nsRequestObserverProxy::OnStartRequest [this=%p req=%p]\n", this,
       request));

  nsOnStartRequestEvent *ev = new nsOnStartRequestEvent(this, request);
  if (!ev) return NS_ERROR_OUT_OF_MEMORY;

  LOG(("post startevent=%p\n", ev));
  nsresult rv = FireEvent(ev);
  if (NS_FAILED(rv)) delete ev;
  return rv;
}

NS_IMETHODIMP
nsRequestObserverProxy::OnStopRequest(nsIRequest *request, nsISupports *context,
                                      nsresult status) {
  MOZ_ASSERT(!context || context == mContext);
  LOG(("nsRequestObserverProxy: OnStopRequest [this=%p req=%p status=%" PRIx32
       "]\n",
       this, request, static_cast<uint32_t>(status)));

  // The status argument is ignored because, by the time the OnStopRequestEvent
  // is actually processed, the status of the request may have changed :-(
  // To make sure that an accurate status code is always used, GetStatus() is
  // called when the OnStopRequestEvent is actually processed (see above).

  nsOnStopRequestEvent *ev = new nsOnStopRequestEvent(this, request);
  if (!ev) return NS_ERROR_OUT_OF_MEMORY;

  LOG(("post stopevent=%p\n", ev));
  nsresult rv = FireEvent(ev);
  if (NS_FAILED(rv)) delete ev;
  return rv;
}

//-----------------------------------------------------------------------------
// nsRequestObserverProxy::nsIRequestObserverProxy implementation...
//-----------------------------------------------------------------------------

NS_IMETHODIMP
nsRequestObserverProxy::Init(nsIRequestObserver *observer,
                             nsISupports *context) {
  NS_ENSURE_ARG_POINTER(observer);
  mObserver = new nsMainThreadPtrHolder<nsIRequestObserver>(
      "nsRequestObserverProxy::mObserver", observer);
  mContext = new nsMainThreadPtrHolder<nsISupports>(
      "nsRequestObserverProxy::mContext", context);

  return NS_OK;
}

//-----------------------------------------------------------------------------
// nsRequestObserverProxy implementation...
//-----------------------------------------------------------------------------

nsresult nsRequestObserverProxy::FireEvent(nsARequestObserverEvent *event) {
  nsCOMPtr<nsIEventTarget> mainThread(GetMainThreadEventTarget());
  return mainThread->Dispatch(event, NS_DISPATCH_NORMAL);
}

}  // namespace net
}  // namespace mozilla