1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is Mozilla.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Netscape Communications Corporation.
18 : * Portions created by the Initial Developer are Copyright (C) 2002
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Darin Fisher <darin@netscape.com> (original author)
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsStreamListenerTee.h"
39 : #include "nsProxyRelease.h"
40 :
41 21974 : NS_IMPL_ISUPPORTS3(nsStreamListenerTee,
42 : nsIStreamListener,
43 : nsIRequestObserver,
44 : nsIStreamListenerTee)
45 :
46 : NS_IMETHODIMP
47 249 : nsStreamListenerTee::OnStartRequest(nsIRequest *request,
48 : nsISupports *context)
49 : {
50 249 : NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED);
51 249 : nsresult rv1 = mListener->OnStartRequest(request, context);
52 249 : nsresult rv2 = NS_OK;
53 249 : if (mObserver)
54 1 : rv2 = mObserver->OnStartRequest(request, context);
55 :
56 : // Preserve NS_SUCCESS_XXX in rv1 in case mObserver didn't throw
57 249 : return (NS_FAILED(rv2) && NS_SUCCEEDED(rv1)) ? rv2 : rv1;
58 : }
59 :
60 : NS_IMETHODIMP
61 1407 : nsStreamListenerTee::OnStopRequest(nsIRequest *request,
62 : nsISupports *context,
63 : nsresult status)
64 : {
65 1407 : NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED);
66 : // it is critical that we close out the input stream tee
67 1407 : if (mInputTee) {
68 1301 : mInputTee->SetSink(nsnull);
69 1301 : mInputTee = 0;
70 : }
71 :
72 : // release sink on the same thread where the data was written (bug 716293)
73 1407 : if (mEventTarget) {
74 1134 : nsIOutputStream *sink = nsnull;
75 1134 : mSink.swap(sink);
76 1134 : NS_ProxyRelease(mEventTarget, sink);
77 : }
78 : else {
79 273 : mSink = 0;
80 : }
81 :
82 1407 : nsresult rv = mListener->OnStopRequest(request, context, status);
83 1407 : if (mObserver)
84 1 : mObserver->OnStopRequest(request, context, status);
85 1407 : mObserver = 0;
86 1407 : return rv;
87 : }
88 :
89 : NS_IMETHODIMP
90 1648 : nsStreamListenerTee::OnDataAvailable(nsIRequest *request,
91 : nsISupports *context,
92 : nsIInputStream *input,
93 : PRUint32 offset,
94 : PRUint32 count)
95 : {
96 1648 : NS_ENSURE_TRUE(mListener, NS_ERROR_NOT_INITIALIZED);
97 1648 : NS_ENSURE_TRUE(mSink, NS_ERROR_NOT_INITIALIZED);
98 :
99 3296 : nsCOMPtr<nsIInputStream> tee;
100 : nsresult rv;
101 :
102 1648 : if (!mInputTee) {
103 1301 : if (mEventTarget)
104 1028 : rv = NS_NewInputStreamTeeAsync(getter_AddRefs(tee), input,
105 1028 : mSink, mEventTarget);
106 : else
107 273 : rv = NS_NewInputStreamTee(getter_AddRefs(tee), input, mSink);
108 1301 : if (NS_FAILED(rv)) return rv;
109 :
110 1301 : mInputTee = do_QueryInterface(tee, &rv);
111 1301 : if (NS_FAILED(rv)) return rv;
112 : }
113 : else {
114 : // re-initialize the input tee since the input stream may have changed.
115 347 : rv = mInputTee->SetSource(input);
116 347 : if (NS_FAILED(rv)) return rv;
117 :
118 347 : tee = do_QueryInterface(mInputTee, &rv);
119 347 : if (NS_FAILED(rv)) return rv;
120 : }
121 :
122 1648 : return mListener->OnDataAvailable(request, context, tee, offset, count);
123 : }
124 :
125 : NS_IMETHODIMP
126 1407 : nsStreamListenerTee::Init(nsIStreamListener *listener,
127 : nsIOutputStream *sink,
128 : nsIRequestObserver *requestObserver)
129 : {
130 1407 : NS_ENSURE_ARG_POINTER(listener);
131 1407 : NS_ENSURE_ARG_POINTER(sink);
132 1407 : mListener = listener;
133 1407 : mSink = sink;
134 1407 : mObserver = requestObserver;
135 1407 : return NS_OK;
136 : }
137 :
138 : NS_IMETHODIMP
139 1134 : nsStreamListenerTee::InitAsync(nsIStreamListener *listener,
140 : nsIEventTarget *eventTarget,
141 : nsIOutputStream *sink,
142 : nsIRequestObserver *requestObserver)
143 : {
144 1134 : NS_ENSURE_ARG_POINTER(eventTarget);
145 1134 : mEventTarget = eventTarget;
146 1134 : return Init(listener, sink, requestObserver);
147 : }
|