Bug 1857095 [wpt PR 42347] - [FedCM] Add a simple wpt test for the signin status...
[gecko.git] / netwerk / base / nsSyncStreamListener.cpp
blob7e5ec94231de20a8748a8d4d339910ed0ec51bd4
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"
7 #include "nsIPipe.h"
8 #include "nsSyncStreamListener.h"
9 #include "nsThreadUtils.h"
10 #include <algorithm>
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
19 false, false);
22 nsresult nsSyncStreamListener::WaitForData() {
23 mKeepWaiting = true;
25 if (!mozilla::SpinEventLoopUntil("nsSyncStreamListener::Create"_ns,
26 [&]() { return !mKeepWaiting; })) {
27 return NS_ERROR_FAILURE;
30 return NS_OK;
33 //-----------------------------------------------------------------------------
34 // nsSyncStreamListener::nsISupports
35 //-----------------------------------------------------------------------------
37 NS_IMPL_ISUPPORTS(nsSyncStreamListener, nsIStreamListener, nsIRequestObserver,
38 nsIInputStream, nsISyncStreamListener)
40 //-----------------------------------------------------------------------------
41 // nsSyncStreamListener::nsISyncStreamListener
42 //-----------------------------------------------------------------------------
44 NS_IMETHODIMP
45 nsSyncStreamListener::GetInputStream(nsIInputStream** result) {
46 *result = do_AddRef(this).take();
47 return NS_OK;
50 //-----------------------------------------------------------------------------
51 // nsSyncStreamListener::nsIStreamListener
52 //-----------------------------------------------------------------------------
54 NS_IMETHODIMP
55 nsSyncStreamListener::OnStartRequest(nsIRequest* request) { return NS_OK; }
57 NS_IMETHODIMP
58 nsSyncStreamListener::OnDataAvailable(nsIRequest* request,
59 nsIInputStream* stream, uint64_t offset,
60 uint32_t count) {
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
76 return NS_OK;
79 NS_IMETHODIMP
80 nsSyncStreamListener::OnStopRequest(nsIRequest* request, nsresult status) {
81 mStatus = status;
82 mKeepWaiting = false; // unblock Read
83 mDone = true;
84 return NS_OK;
87 //-----------------------------------------------------------------------------
88 // nsSyncStreamListener::nsIInputStream
89 //-----------------------------------------------------------------------------
91 NS_IMETHODIMP
92 nsSyncStreamListener::Close() {
93 mStatus = NS_BASE_STREAM_CLOSED;
94 mDone = true;
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.
99 if (mPipeIn) {
100 mPipeIn->Close();
101 mPipeIn = nullptr;
103 return NS_OK;
106 NS_IMETHODIMP
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();
113 if (NS_FAILED(rv)) {
114 // Note that `WaitForData` could fail `mStatus`. Do not overwrite if it's
115 // the case.
116 mStatus = NS_SUCCEEDED(mStatus) ? rv : mStatus;
117 } else if (NS_SUCCEEDED(mStatus)) {
118 mStatus = mPipeIn->Available(result);
121 return mStatus;
124 NS_IMETHODIMP
125 nsSyncStreamListener::StreamStatus() {
126 if (NS_FAILED(mStatus)) {
127 return mStatus;
130 mStatus = mPipeIn->StreamStatus();
131 return mStatus;
134 NS_IMETHODIMP
135 nsSyncStreamListener::Read(char* buf, uint32_t bufLen, uint32_t* result) {
136 if (mStatus == NS_BASE_STREAM_CLOSED) {
137 *result = 0;
138 return NS_OK;
141 uint64_t avail64;
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);
146 return mStatus;
149 NS_IMETHODIMP
150 nsSyncStreamListener::ReadSegments(nsWriteSegmentFun writer, void* closure,
151 uint32_t count, uint32_t* result) {
152 if (mStatus == NS_BASE_STREAM_CLOSED) {
153 *result = 0;
154 return NS_OK;
157 uint64_t avail64;
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);
162 return mStatus;
165 NS_IMETHODIMP
166 nsSyncStreamListener::IsNonBlocking(bool* result) {
167 *result = false;
168 return NS_OK;