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/. */
5 #include "mozilla/SpinEventLoopUntil.h"
6 #include "nsIOService.h"
8 #include "nsSyncStreamListener.h"
9 #include "nsThreadUtils.h"
12 using namespace mozilla::net
;
14 nsSyncStreamListener::nsSyncStreamListener() {
15 MOZ_ASSERT(NS_IsMainThread());
16 NS_NewPipe(getter_AddRefs(mPipeIn
), getter_AddRefs(mPipeOut
),
17 mozilla::net::nsIOService::gDefaultSegmentSize
,
18 UINT32_MAX
, // no size limit
22 nsresult
nsSyncStreamListener::WaitForData() {
25 if (!mozilla::SpinEventLoopUntil("nsSyncStreamListener::Create"_ns
,
26 [&]() { return !mKeepWaiting
; })) {
27 return NS_ERROR_FAILURE
;
33 //-----------------------------------------------------------------------------
34 // nsSyncStreamListener::nsISupports
35 //-----------------------------------------------------------------------------
37 NS_IMPL_ISUPPORTS(nsSyncStreamListener
, nsIStreamListener
, nsIRequestObserver
,
38 nsIInputStream
, nsISyncStreamListener
)
40 //-----------------------------------------------------------------------------
41 // nsSyncStreamListener::nsISyncStreamListener
42 //-----------------------------------------------------------------------------
45 nsSyncStreamListener::GetInputStream(nsIInputStream
** result
) {
46 *result
= do_AddRef(this).take();
50 //-----------------------------------------------------------------------------
51 // nsSyncStreamListener::nsIStreamListener
52 //-----------------------------------------------------------------------------
55 nsSyncStreamListener::OnStartRequest(nsIRequest
* request
) { return NS_OK
; }
58 nsSyncStreamListener::OnDataAvailable(nsIRequest
* request
,
59 nsIInputStream
* stream
, uint64_t offset
,
61 uint32_t bytesWritten
;
63 nsresult rv
= mPipeOut
->WriteFrom(stream
, count
, &bytesWritten
);
65 // if we get an error, then return failure. this will cause the
66 // channel to be canceled, and as a result our OnStopRequest method
67 // will be called immediately. because of this we do not need to
68 // set mStatus or mKeepWaiting here.
69 if (NS_FAILED(rv
)) return rv
;
71 // we expect that all data will be written to the pipe because
72 // the pipe was created to have "infinite" room.
73 NS_ASSERTION(bytesWritten
== count
, "did not write all data");
75 mKeepWaiting
= false; // unblock Read
80 nsSyncStreamListener::OnStopRequest(nsIRequest
* request
, nsresult status
) {
82 mKeepWaiting
= false; // unblock Read
87 //-----------------------------------------------------------------------------
88 // nsSyncStreamListener::nsIInputStream
89 //-----------------------------------------------------------------------------
92 nsSyncStreamListener::Close() {
93 mStatus
= NS_BASE_STREAM_CLOSED
;
96 // It'd be nice if we could explicitly cancel the request at this point,
97 // but we don't have a reference to it, so the best we can do is close the
98 // pipe so that the next OnDataAvailable event will fail.
107 nsSyncStreamListener::Available(uint64_t* result
) {
108 if (NS_FAILED(mStatus
)) return mStatus
;
110 mStatus
= mPipeIn
->Available(result
);
111 if (NS_SUCCEEDED(mStatus
) && (*result
== 0) && !mDone
) {
112 nsresult rv
= WaitForData();
114 // Note that `WaitForData` could fail `mStatus`. Do not overwrite if it's
116 mStatus
= NS_SUCCEEDED(mStatus
) ? rv
: mStatus
;
117 } else if (NS_SUCCEEDED(mStatus
)) {
118 mStatus
= mPipeIn
->Available(result
);
125 nsSyncStreamListener::StreamStatus() {
126 if (NS_FAILED(mStatus
)) {
130 mStatus
= mPipeIn
->StreamStatus();
135 nsSyncStreamListener::Read(char* buf
, uint32_t bufLen
, uint32_t* result
) {
136 if (mStatus
== NS_BASE_STREAM_CLOSED
) {
142 if (NS_FAILED(Available(&avail64
))) return mStatus
;
144 uint32_t avail
= (uint32_t)std::min(avail64
, (uint64_t)bufLen
);
145 mStatus
= mPipeIn
->Read(buf
, avail
, result
);
150 nsSyncStreamListener::ReadSegments(nsWriteSegmentFun writer
, void* closure
,
151 uint32_t count
, uint32_t* result
) {
152 if (mStatus
== NS_BASE_STREAM_CLOSED
) {
158 if (NS_FAILED(Available(&avail64
))) return mStatus
;
160 uint32_t avail
= (uint32_t)std::min(avail64
, (uint64_t)count
);
161 mStatus
= mPipeIn
->ReadSegments(writer
, closure
, avail
, result
);
166 nsSyncStreamListener::IsNonBlocking(bool* result
) {