DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Header

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
/* 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 "nsStreamListenerTee.h"
#include "nsProxyRelease.h"

namespace mozilla {
namespace net {

NS_IMPL_ISUPPORTS(nsStreamListenerTee, nsIStreamListener, nsIRequestObserver,
                  nsIStreamListenerTee, nsIThreadRetargetableStreamListener)

NS_IMETHODIMP
nsStreamListenerTee::OnStartRequest(nsIRequest* request) {
  NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED);
  nsresult rv1 = mListener->OnStartRequest(request);
  nsresult rv2 = NS_OK;
  if (mObserver) rv2 = mObserver->OnStartRequest(request);

  // Preserve NS_SUCCESS_XXX in rv1 in case mObserver didn't throw
  return (NS_FAILED(rv2) && NS_SUCCEEDED(rv1)) ? rv2 : rv1;
}

NS_IMETHODIMP
nsStreamListenerTee::OnStopRequest(nsIRequest* request, nsresult status) {
  NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED);
  // it is critical that we close out the input stream tee
  if (mInputTee) {
    mInputTee->SetSink(nullptr);
    mInputTee = nullptr;
  }

  // release sink on the same thread where the data was written (bug 716293)
  if (mEventTarget) {
    NS_ProxyRelease("nsStreamListenerTee::mSink", mEventTarget, mSink.forget());
  } else {
    mSink = nullptr;
  }

  nsresult rv = mListener->OnStopRequest(request, status);
  if (mObserver) mObserver->OnStopRequest(request, status);
  mObserver = nullptr;
  return rv;
}

NS_IMETHODIMP
nsStreamListenerTee::OnDataAvailable(nsIRequest* request, nsIInputStream* input,
                                     uint64_t offset, uint32_t count) {
  NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED);
  NS_ENSURE_TRUE(mSink, NS_ERROR_NOT_INITIALIZED);

  nsCOMPtr<nsIInputStream> tee;
  nsresult rv;

  if (!mInputTee) {
    if (mEventTarget)
      rv = NS_NewInputStreamTeeAsync(getter_AddRefs(tee), input, mSink,
                                     mEventTarget);
    else
      rv = NS_NewInputStreamTee(getter_AddRefs(tee), input, mSink);
    if (NS_FAILED(rv)) return rv;

    mInputTee = do_QueryInterface(tee, &rv);
    if (NS_FAILED(rv)) return rv;
  } else {
    // re-initialize the input tee since the input stream may have changed.
    rv = mInputTee->SetSource(input);
    if (NS_FAILED(rv)) return rv;

    tee = mInputTee;
  }

  return mListener->OnDataAvailable(request, tee, offset, count);
}

NS_IMETHODIMP
nsStreamListenerTee::CheckListenerChain() {
  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread!");
  nsresult rv = NS_OK;
  nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
      do_QueryInterface(mListener, &rv);
  if (retargetableListener) {
    rv = retargetableListener->CheckListenerChain();
  }
  if (NS_FAILED(rv)) {
    return rv;
  }
  if (!mObserver) {
    return rv;
  }
  retargetableListener = do_QueryInterface(mObserver, &rv);
  if (retargetableListener) {
    rv = retargetableListener->CheckListenerChain();
  }
  return rv;
}

NS_IMETHODIMP
nsStreamListenerTee::Init(nsIStreamListener* listener, nsIOutputStream* sink,
                          nsIRequestObserver* requestObserver) {
  NS_ENSURE_ARG_POINTER(listener);
  NS_ENSURE_ARG_POINTER(sink);
  mListener = listener;
  mSink = sink;
  mObserver = requestObserver;
  return NS_OK;
}

NS_IMETHODIMP
nsStreamListenerTee::InitAsync(nsIStreamListener* listener,
                               nsIEventTarget* eventTarget,
                               nsIOutputStream* sink,
                               nsIRequestObserver* requestObserver) {
  NS_ENSURE_ARG_POINTER(eventTarget);
  mEventTarget = eventTarget;
  return Init(listener, sink, requestObserver);
}

}  // namespace net
}  // namespace mozilla