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>
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 "nsIOService.h"
39 : #include "nsAsyncStreamCopier.h"
40 : #include "nsIEventTarget.h"
41 : #include "nsStreamUtils.h"
42 : #include "nsNetSegmentUtils.h"
43 : #include "nsNetUtil.h"
44 : #include "prlog.h"
45 :
46 : using namespace mozilla;
47 :
48 : #if defined(PR_LOGGING)
49 : //
50 : // NSPR_LOG_MODULES=nsStreamCopier:5
51 : //
52 : static PRLogModuleInfo *gStreamCopierLog = nsnull;
53 : #endif
54 : #define LOG(args) PR_LOG(gStreamCopierLog, PR_LOG_DEBUG, args)
55 :
56 : //-----------------------------------------------------------------------------
57 :
58 399 : nsAsyncStreamCopier::nsAsyncStreamCopier()
59 : : mLock("nsAsyncStreamCopier.mLock")
60 : , mMode(NS_ASYNCCOPY_VIA_READSEGMENTS)
61 : , mChunkSize(nsIOService::gDefaultSegmentSize)
62 : , mStatus(NS_OK)
63 399 : , mIsPending(false)
64 : {
65 : #if defined(PR_LOGGING)
66 399 : if (!gStreamCopierLog)
67 25 : gStreamCopierLog = PR_NewLogModule("nsStreamCopier");
68 : #endif
69 399 : LOG(("Creating nsAsyncStreamCopier @%x\n", this));
70 399 : }
71 :
72 1197 : nsAsyncStreamCopier::~nsAsyncStreamCopier()
73 : {
74 399 : LOG(("Destroying nsAsyncStreamCopier @%x\n", this));
75 1596 : }
76 :
77 : bool
78 396 : nsAsyncStreamCopier::IsComplete(nsresult *status)
79 : {
80 792 : MutexAutoLock lock(mLock);
81 396 : if (status)
82 396 : *status = mStatus;
83 396 : return !mIsPending;
84 : }
85 :
86 : void
87 396 : nsAsyncStreamCopier::Complete(nsresult status)
88 : {
89 396 : LOG(("nsAsyncStreamCopier::Complete [this=%x status=%x]\n", this, status));
90 :
91 792 : nsCOMPtr<nsIRequestObserver> observer;
92 792 : nsCOMPtr<nsISupports> ctx;
93 : {
94 792 : MutexAutoLock lock(mLock);
95 396 : mCopierCtx = nsnull;
96 :
97 396 : if (mIsPending) {
98 396 : mIsPending = false;
99 396 : mStatus = status;
100 :
101 : // setup OnStopRequest callback and release references...
102 396 : observer = mObserver;
103 396 : ctx = mObserverContext;
104 396 : mObserver = nsnull;
105 396 : mObserverContext = nsnull;
106 : }
107 : }
108 :
109 396 : if (observer) {
110 396 : LOG((" calling OnStopRequest [status=%x]\n", status));
111 396 : observer->OnStopRequest(this, ctx, status);
112 : }
113 396 : }
114 :
115 : void
116 396 : nsAsyncStreamCopier::OnAsyncCopyComplete(void *closure, nsresult status)
117 : {
118 396 : nsAsyncStreamCopier *self = (nsAsyncStreamCopier *) closure;
119 396 : self->Complete(status);
120 396 : NS_RELEASE(self); // addref'd in AsyncCopy
121 396 : }
122 :
123 : //-----------------------------------------------------------------------------
124 : // nsISupports
125 :
126 16680 : NS_IMPL_THREADSAFE_ISUPPORTS2(nsAsyncStreamCopier,
127 : nsIRequest,
128 : nsIAsyncStreamCopier)
129 :
130 : //-----------------------------------------------------------------------------
131 : // nsIRequest
132 :
133 : NS_IMETHODIMP
134 0 : nsAsyncStreamCopier::GetName(nsACString &name)
135 : {
136 0 : name.Truncate();
137 0 : return NS_OK;
138 : }
139 :
140 : NS_IMETHODIMP
141 0 : nsAsyncStreamCopier::IsPending(bool *result)
142 : {
143 0 : *result = !IsComplete();
144 0 : return NS_OK;
145 : }
146 :
147 : NS_IMETHODIMP
148 396 : nsAsyncStreamCopier::GetStatus(nsresult *status)
149 : {
150 396 : IsComplete(status);
151 396 : return NS_OK;
152 : }
153 :
154 : NS_IMETHODIMP
155 7 : nsAsyncStreamCopier::Cancel(nsresult status)
156 : {
157 14 : nsCOMPtr<nsISupports> copierCtx;
158 : {
159 14 : MutexAutoLock lock(mLock);
160 7 : if (!mIsPending)
161 0 : return NS_OK;
162 14 : copierCtx.swap(mCopierCtx);
163 : }
164 :
165 7 : if (NS_SUCCEEDED(status)) {
166 0 : NS_WARNING("cancel with non-failure status code");
167 0 : status = NS_BASE_STREAM_CLOSED;
168 : }
169 :
170 7 : if (copierCtx)
171 7 : NS_CancelAsyncCopy(copierCtx, status);
172 :
173 7 : return NS_OK;
174 : }
175 :
176 : NS_IMETHODIMP
177 0 : nsAsyncStreamCopier::Suspend()
178 : {
179 0 : NS_NOTREACHED("nsAsyncStreamCopier::Suspend");
180 0 : return NS_ERROR_NOT_IMPLEMENTED;
181 : }
182 :
183 : NS_IMETHODIMP
184 0 : nsAsyncStreamCopier::Resume()
185 : {
186 0 : NS_NOTREACHED("nsAsyncStreamCopier::Resume");
187 0 : return NS_ERROR_NOT_IMPLEMENTED;
188 : }
189 :
190 : NS_IMETHODIMP
191 0 : nsAsyncStreamCopier::GetLoadFlags(nsLoadFlags *aLoadFlags)
192 : {
193 0 : *aLoadFlags = LOAD_NORMAL;
194 0 : return NS_OK;
195 : }
196 :
197 : NS_IMETHODIMP
198 0 : nsAsyncStreamCopier::SetLoadFlags(nsLoadFlags aLoadFlags)
199 : {
200 0 : return NS_OK;
201 : }
202 :
203 : NS_IMETHODIMP
204 0 : nsAsyncStreamCopier::GetLoadGroup(nsILoadGroup **aLoadGroup)
205 : {
206 0 : *aLoadGroup = nsnull;
207 0 : return NS_OK;
208 : }
209 :
210 : NS_IMETHODIMP
211 0 : nsAsyncStreamCopier::SetLoadGroup(nsILoadGroup *aLoadGroup)
212 : {
213 0 : return NS_OK;
214 : }
215 :
216 : //-----------------------------------------------------------------------------
217 : // nsIAsyncStreamCopier
218 :
219 : NS_IMETHODIMP
220 399 : nsAsyncStreamCopier::Init(nsIInputStream *source,
221 : nsIOutputStream *sink,
222 : nsIEventTarget *target,
223 : bool sourceBuffered,
224 : bool sinkBuffered,
225 : PRUint32 chunkSize,
226 : bool closeSource,
227 : bool closeSink)
228 : {
229 399 : NS_ASSERTION(sourceBuffered || sinkBuffered, "at least one stream must be buffered");
230 :
231 399 : if (chunkSize == 0)
232 0 : chunkSize = nsIOService::gDefaultSegmentSize;
233 399 : mChunkSize = chunkSize;
234 :
235 399 : mSource = source;
236 399 : mSink = sink;
237 399 : mCloseSource = closeSource;
238 399 : mCloseSink = closeSink;
239 :
240 : mMode = sourceBuffered ? NS_ASYNCCOPY_VIA_READSEGMENTS
241 399 : : NS_ASYNCCOPY_VIA_WRITESEGMENTS;
242 399 : if (target)
243 0 : mTarget = target;
244 : else {
245 : nsresult rv;
246 399 : mTarget = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
247 399 : if (NS_FAILED(rv)) return rv;
248 : }
249 399 : return NS_OK;
250 : }
251 :
252 : NS_IMETHODIMP
253 399 : nsAsyncStreamCopier::AsyncCopy(nsIRequestObserver *observer, nsISupports *ctx)
254 : {
255 399 : LOG(("nsAsyncStreamCopier::AsyncCopy [this=%x observer=%x]\n", this, observer));
256 :
257 399 : NS_ASSERTION(mSource && mSink, "not initialized");
258 : nsresult rv;
259 :
260 399 : if (observer) {
261 : // build proxy for observer events
262 399 : rv = NS_NewRequestObserverProxy(getter_AddRefs(mObserver), observer);
263 399 : if (NS_FAILED(rv)) return rv;
264 : }
265 :
266 : // from this point forward, AsyncCopy is going to return NS_OK. any errors
267 : // will be reported via OnStopRequest.
268 399 : mIsPending = true;
269 :
270 399 : mObserverContext = ctx;
271 399 : if (mObserver) {
272 399 : rv = mObserver->OnStartRequest(this, mObserverContext);
273 399 : if (NS_FAILED(rv))
274 0 : Cancel(rv);
275 : }
276 :
277 : // we want to receive progress notifications; release happens in
278 : // OnAsyncCopyComplete.
279 399 : NS_ADDREF_THIS();
280 : rv = NS_AsyncCopy(mSource, mSink, mTarget, mMode, mChunkSize,
281 : OnAsyncCopyComplete, this, mCloseSource, mCloseSink,
282 399 : getter_AddRefs(mCopierCtx));
283 399 : if (NS_FAILED(rv)) {
284 3 : NS_RELEASE_THIS();
285 3 : Cancel(rv);
286 : }
287 :
288 399 : return NS_OK;
289 : }
|