1
/* ***** BEGIN LICENSE BLOCK *****
2
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
14
* The Original Code is Mozilla.
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.
22
* Darin Fisher <darin@netscape.com>
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.
36
* ***** END LICENSE BLOCK ***** */
38
#include "nsStreamTransportService.h"
39
#include "nsNetSegmentUtils.h"
40
#include "nsAutoLock.h"
41
#include "nsTransportUtils.h"
42
#include "nsStreamUtils.h"
43
#include "nsNetError.h"
46
#include "nsIServiceManager.h"
47
#include "nsIAsyncInputStream.h"
48
#include "nsIAsyncOutputStream.h"
49
#include "nsISeekableStream.h"
51
#include "nsITransport.h"
52
#include "nsIRunnable.h"
53
#include "nsIProxyObjectManager.h"
54
#include "nsIEventTarget.h"
56
//-----------------------------------------------------------------------------
57
// nsInputStreamTransport
59
// Implements nsIInputStream as a wrapper around the real input stream. This
60
// allows the transport to support seeking, range-limiting, progress reporting,
61
// and close-when-done semantics while utilizing NS_AsyncCopy.
62
//-----------------------------------------------------------------------------
64
class nsInputStreamTransport : public nsITransport
65
, public nsIInputStream
70
NS_DECL_NSIINPUTSTREAM
72
nsInputStreamTransport(nsIInputStream *source,
79
, mCloseWhenDone(closeWhenDone)
81
, mInProgress(PR_FALSE)
85
virtual ~nsInputStreamTransport()
90
nsCOMPtr<nsIAsyncInputStream> mPipeIn;
92
// while the copy is active, these members may only be accessed from the
93
// nsIInputStream implementation.
94
nsCOMPtr<nsITransportEventSink> mEventSink;
95
nsCOMPtr<nsIInputStream> mSource;
98
PRPackedBool mCloseWhenDone;
99
PRPackedBool mFirstTime;
101
// this variable serves as a lock to prevent the state of the transport
102
// from being modified once the copy is in progress.
103
PRPackedBool mInProgress;
106
NS_IMPL_THREADSAFE_ISUPPORTS2(nsInputStreamTransport,
113
nsInputStreamTransport::OpenInputStream(PRUint32 flags,
116
nsIInputStream **result)
118
NS_ENSURE_TRUE(!mInProgress, NS_ERROR_IN_PROGRESS);
121
nsCOMPtr<nsIEventTarget> target =
122
do_GetService(NS_IOTHREADPOOL_CONTRACTID, &rv);
123
if (NS_FAILED(rv)) return rv;
125
// XXX if the caller requests an unbuffered stream, then perhaps
126
// we'd want to simply return mSource; however, then we would
127
// not be reading mSource on a background thread. is this ok?
129
PRBool nonblocking = !(flags & OPEN_BLOCKING);
131
net_ResolveSegmentParams(segsize, segcount);
132
nsIMemory *segalloc = net_GetSegmentAlloc(segsize);
134
nsCOMPtr<nsIAsyncOutputStream> pipeOut;
135
rv = NS_NewPipe2(getter_AddRefs(mPipeIn),
136
getter_AddRefs(pipeOut),
137
nonblocking, PR_TRUE,
138
segsize, segcount, segalloc);
139
if (NS_FAILED(rv)) return rv;
141
mInProgress = PR_TRUE;
143
// startup async copy process...
144
rv = NS_AsyncCopy(this, pipeOut, target,
145
NS_ASYNCCOPY_VIA_WRITESEGMENTS, segsize);
146
if (NS_SUCCEEDED(rv))
147
NS_ADDREF(*result = mPipeIn);
153
nsInputStreamTransport::OpenOutputStream(PRUint32 flags,
156
nsIOutputStream **result)
158
// this transport only supports reading!
159
NS_NOTREACHED("nsInputStreamTransport::OpenOutputStream");
160
return NS_ERROR_UNEXPECTED;
164
nsInputStreamTransport::Close(nsresult reason)
166
if (NS_SUCCEEDED(reason))
167
reason = NS_BASE_STREAM_CLOSED;
169
return mPipeIn->CloseWithStatus(reason);
173
nsInputStreamTransport::SetEventSink(nsITransportEventSink *sink,
174
nsIEventTarget *target)
176
NS_ENSURE_TRUE(!mInProgress, NS_ERROR_IN_PROGRESS);
179
return net_NewTransportEventSinkProxy(getter_AddRefs(mEventSink),
186
/** nsIInputStream **/
189
nsInputStreamTransport::Close()
194
// make additional reads return early...
195
mOffset = mLimit = 0;
200
nsInputStreamTransport::Available(PRUint32 *result)
202
return NS_ERROR_NOT_IMPLEMENTED;
206
nsInputStreamTransport::Read(char *buf, PRUint32 count, PRUint32 *result)
209
mFirstTime = PR_FALSE;
211
// read from current position if offset equal to max
212
if (mOffset != PR_UINT32_MAX) {
213
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mSource);
215
seekable->Seek(nsISeekableStream::NS_SEEK_SET, mOffset);
217
// reset offset to zero so we can use it to enforce limit
223
PRUint32 max = mLimit - mOffset;
232
nsresult rv = mSource->Read(buf, count, result);
234
if (NS_SUCCEEDED(rv)) {
237
mEventSink->OnTransportStatus(this, STATUS_READING, mOffset, mLimit);
243
nsInputStreamTransport::ReadSegments(nsWriteSegmentFun writer, void *closure,
244
PRUint32 count, PRUint32 *result)
246
return NS_ERROR_NOT_IMPLEMENTED;
250
nsInputStreamTransport::IsNonBlocking(PRBool *result)
256
//-----------------------------------------------------------------------------
257
// nsOutputStreamTransport
259
// Implements nsIOutputStream as a wrapper around the real input stream. This
260
// allows the transport to support seeking, range-limiting, progress reporting,
261
// and close-when-done semantics while utilizing NS_AsyncCopy.
262
//-----------------------------------------------------------------------------
264
class nsOutputStreamTransport : public nsITransport
265
, public nsIOutputStream
270
NS_DECL_NSIOUTPUTSTREAM
272
nsOutputStreamTransport(nsIOutputStream *sink,
275
PRBool closeWhenDone)
279
, mCloseWhenDone(closeWhenDone)
280
, mFirstTime(PR_TRUE)
281
, mInProgress(PR_FALSE)
285
virtual ~nsOutputStreamTransport()
290
nsCOMPtr<nsIAsyncOutputStream> mPipeOut;
292
// while the copy is active, these members may only be accessed from the
293
// nsIOutputStream implementation.
294
nsCOMPtr<nsITransportEventSink> mEventSink;
295
nsCOMPtr<nsIOutputStream> mSink;
298
PRPackedBool mCloseWhenDone;
299
PRPackedBool mFirstTime;
301
// this variable serves as a lock to prevent the state of the transport
302
// from being modified once the copy is in progress.
303
PRPackedBool mInProgress;
306
NS_IMPL_THREADSAFE_ISUPPORTS2(nsOutputStreamTransport,
313
nsOutputStreamTransport::OpenInputStream(PRUint32 flags,
316
nsIInputStream **result)
318
// this transport only supports writing!
319
NS_NOTREACHED("nsOutputStreamTransport::OpenInputStream");
320
return NS_ERROR_UNEXPECTED;
324
nsOutputStreamTransport::OpenOutputStream(PRUint32 flags,
327
nsIOutputStream **result)
329
NS_ENSURE_TRUE(!mInProgress, NS_ERROR_IN_PROGRESS);
332
nsCOMPtr<nsIEventTarget> target =
333
do_GetService(NS_IOTHREADPOOL_CONTRACTID, &rv);
334
if (NS_FAILED(rv)) return rv;
336
// XXX if the caller requests an unbuffered stream, then perhaps
337
// we'd want to simply return mSink; however, then we would
338
// not be writing to mSink on a background thread. is this ok?
340
PRBool nonblocking = !(flags & OPEN_BLOCKING);
342
net_ResolveSegmentParams(segsize, segcount);
343
nsIMemory *segalloc = net_GetSegmentAlloc(segsize);
345
nsCOMPtr<nsIAsyncInputStream> pipeIn;
346
rv = NS_NewPipe2(getter_AddRefs(pipeIn),
347
getter_AddRefs(mPipeOut),
348
PR_TRUE, nonblocking,
349
segsize, segcount, segalloc);
350
if (NS_FAILED(rv)) return rv;
352
mInProgress = PR_TRUE;
354
// startup async copy process...
355
rv = NS_AsyncCopy(pipeIn, this, target,
356
NS_ASYNCCOPY_VIA_READSEGMENTS, segsize);
357
if (NS_SUCCEEDED(rv))
358
NS_ADDREF(*result = mPipeOut);
364
nsOutputStreamTransport::Close(nsresult reason)
366
if (NS_SUCCEEDED(reason))
367
reason = NS_BASE_STREAM_CLOSED;
369
return mPipeOut->CloseWithStatus(reason);
373
nsOutputStreamTransport::SetEventSink(nsITransportEventSink *sink,
374
nsIEventTarget *target)
376
NS_ENSURE_TRUE(!mInProgress, NS_ERROR_IN_PROGRESS);
379
return net_NewTransportEventSinkProxy(getter_AddRefs(mEventSink),
386
/** nsIOutputStream **/
389
nsOutputStreamTransport::Close()
394
// make additional writes return early...
395
mOffset = mLimit = 0;
400
nsOutputStreamTransport::Flush()
406
nsOutputStreamTransport::Write(const char *buf, PRUint32 count, PRUint32 *result)
409
mFirstTime = PR_FALSE;
411
// write to current position if offset equal to max
412
if (mOffset != PR_UINT32_MAX) {
413
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mSink);
415
seekable->Seek(nsISeekableStream::NS_SEEK_SET, mOffset);
417
// reset offset to zero so we can use it to enforce limit
422
// limit amount written
423
PRUint32 max = mLimit - mOffset;
432
nsresult rv = mSink->Write(buf, count, result);
434
if (NS_SUCCEEDED(rv)) {
437
mEventSink->OnTransportStatus(this, STATUS_WRITING, mOffset, mLimit);
443
nsOutputStreamTransport::WriteSegments(nsReadSegmentFun reader, void *closure,
444
PRUint32 count, PRUint32 *result)
446
return NS_ERROR_NOT_IMPLEMENTED;
450
nsOutputStreamTransport::WriteFrom(nsIInputStream *in, PRUint32 count, PRUint32 *result)
452
return NS_ERROR_NOT_IMPLEMENTED;
456
nsOutputStreamTransport::IsNonBlocking(PRBool *result)
462
//-----------------------------------------------------------------------------
463
// nsStreamTransportService
464
//-----------------------------------------------------------------------------
466
NS_IMPL_THREADSAFE_ISUPPORTS1(nsStreamTransportService, nsIStreamTransportService)
469
nsStreamTransportService::CreateInputTransport(nsIInputStream *stream,
472
PRBool closeWhenDone,
473
nsITransport **result)
475
nsInputStreamTransport *trans =
476
new nsInputStreamTransport(stream, offset, limit, closeWhenDone);
478
return NS_ERROR_OUT_OF_MEMORY;
479
NS_ADDREF(*result = trans);
484
nsStreamTransportService::CreateOutputTransport(nsIOutputStream *stream,
487
PRBool closeWhenDone,
488
nsITransport **result)
490
nsOutputStreamTransport *trans =
491
new nsOutputStreamTransport(stream, offset, limit, closeWhenDone);
493
return NS_ERROR_OUT_OF_MEMORY;
494
NS_ADDREF(*result = trans);