nsStreamListenerTee.cpp (5352B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "nsStreamListenerTee.h" 6 #include "nsProxyRelease.h" 7 #include "nsIRequest.h" 8 9 namespace mozilla { 10 namespace net { 11 12 NS_IMPL_ISUPPORTS(nsStreamListenerTee, nsIStreamListener, nsIRequestObserver, 13 nsIStreamListenerTee, nsIThreadRetargetableStreamListener, 14 nsIMultiPartChannelListener) 15 16 NS_IMETHODIMP 17 nsStreamListenerTee::OnStartRequest(nsIRequest* request) { 18 NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED); 19 20 nsCOMPtr<nsIMultiPartChannel> multiPartChannel = do_QueryInterface(request); 21 if (multiPartChannel) { 22 mIsMultiPart = true; 23 } 24 25 nsresult rv1 = mListener->OnStartRequest(request); 26 nsresult rv2 = NS_OK; 27 if (mObserver) rv2 = mObserver->OnStartRequest(request); 28 29 // Preserve NS_SUCCESS_XXX in rv1 in case mObserver didn't throw 30 return (NS_FAILED(rv2) && NS_SUCCEEDED(rv1)) ? rv2 : rv1; 31 } 32 33 NS_IMETHODIMP 34 nsStreamListenerTee::OnStopRequest(nsIRequest* request, nsresult status) { 35 NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED); 36 // it is critical that we close out the input stream tee 37 if (mInputTee) { 38 mInputTee->SetSink(nullptr); 39 mInputTee = nullptr; 40 } 41 42 if (!mIsMultiPart) { 43 // release sink on the same thread where the data was written (bug 716293) 44 if (mEventTarget) { 45 NS_ProxyRelease("nsStreamListenerTee::mSink", mEventTarget, 46 mSink.forget()); 47 } else { 48 mSink = nullptr; 49 } 50 } 51 52 nsresult rv = mListener->OnStopRequest(request, status); 53 if (!mIsMultiPart) { 54 mListener = nullptr; 55 } 56 if (mObserver) { 57 mObserver->OnStopRequest(request, status); 58 if (!mIsMultiPart) { 59 mObserver = nullptr; 60 } 61 } 62 return rv; 63 } 64 65 NS_IMETHODIMP 66 nsStreamListenerTee::OnDataAvailable(nsIRequest* request, nsIInputStream* input, 67 uint64_t offset, uint32_t count) { 68 NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED); 69 NS_ENSURE_TRUE(mSink, NS_ERROR_NOT_INITIALIZED); 70 71 nsCOMPtr<nsIInputStream> tee; 72 nsresult rv; 73 74 if (!mInputTee) { 75 if (mEventTarget) { 76 rv = NS_NewInputStreamTeeAsync(getter_AddRefs(tee), input, mSink, 77 mEventTarget); 78 } else { 79 rv = NS_NewInputStreamTee(getter_AddRefs(tee), input, mSink); 80 } 81 if (NS_FAILED(rv)) return rv; 82 83 mInputTee = do_QueryInterface(tee, &rv); 84 if (NS_FAILED(rv)) return rv; 85 } else { 86 // re-initialize the input tee since the input stream may have changed. 87 rv = mInputTee->SetSource(input); 88 if (NS_FAILED(rv)) return rv; 89 90 tee = mInputTee; 91 } 92 93 return mListener->OnDataAvailable(request, tee, offset, count); 94 } 95 96 NS_IMETHODIMP 97 nsStreamListenerTee::OnAfterLastPart(nsresult aStatus) { 98 // release sink on the same thread where the data was written (bug 716293) 99 if (mEventTarget) { 100 NS_ProxyRelease("nsStreamListenerTee::mSink", mEventTarget, mSink.forget()); 101 } else { 102 mSink = nullptr; 103 } 104 105 if (nsCOMPtr<nsIMultiPartChannelListener> multi = 106 do_QueryInterface(mListener)) { 107 multi->OnAfterLastPart(aStatus); 108 } 109 if (!SameCOMIdentity(mListener, mObserver)) { 110 if (nsCOMPtr<nsIMultiPartChannelListener> multi = 111 do_QueryInterface(mObserver)) { 112 multi->OnAfterLastPart(aStatus); 113 } 114 } 115 116 mObserver = nullptr; 117 return NS_OK; 118 } 119 120 NS_IMETHODIMP 121 nsStreamListenerTee::CheckListenerChain() { 122 NS_ASSERTION(NS_IsMainThread(), "Should be on main thread!"); 123 nsresult rv = NS_OK; 124 nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener = 125 do_QueryInterface(mListener, &rv); 126 if (retargetableListener) { 127 rv = retargetableListener->CheckListenerChain(); 128 } 129 if (NS_FAILED(rv)) { 130 return rv; 131 } 132 if (!mObserver) { 133 return rv; 134 } 135 retargetableListener = do_QueryInterface(mObserver, &rv); 136 if (retargetableListener) { 137 rv = retargetableListener->CheckListenerChain(); 138 } 139 return rv; 140 } 141 142 NS_IMETHODIMP 143 nsStreamListenerTee::OnDataFinished(nsresult aStatus) { 144 nsresult rv = NS_OK; 145 nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener = 146 do_QueryInterface(mListener, &rv); 147 if (retargetableListener) { 148 rv = retargetableListener->OnDataFinished(aStatus); 149 } 150 if (NS_FAILED(rv)) { 151 return rv; 152 } 153 if (!mObserver) { 154 return rv; 155 } 156 retargetableListener = do_QueryInterface(mObserver, &rv); 157 if (retargetableListener) { 158 rv = retargetableListener->OnDataFinished(aStatus); 159 } 160 return rv; 161 } 162 163 NS_IMETHODIMP 164 nsStreamListenerTee::Init(nsIStreamListener* listener, nsIOutputStream* sink, 165 nsIRequestObserver* requestObserver) { 166 NS_ENSURE_ARG_POINTER(listener); 167 NS_ENSURE_ARG_POINTER(sink); 168 mListener = listener; 169 mSink = sink; 170 mObserver = requestObserver; 171 return NS_OK; 172 } 173 174 NS_IMETHODIMP 175 nsStreamListenerTee::InitAsync(nsIStreamListener* listener, 176 nsIEventTarget* eventTarget, 177 nsIOutputStream* sink, 178 nsIRequestObserver* requestObserver) { 179 NS_ENSURE_ARG_POINTER(eventTarget); 180 mEventTarget = eventTarget; 181 return Init(listener, sink, requestObserver); 182 } 183 184 } // namespace net 185 } // namespace mozilla