1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/base/src/nsSyncStreamListener.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,181 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "nsIOService.h" 1.9 +#include "nsSyncStreamListener.h" 1.10 +#include "nsIPipe.h" 1.11 +#include "nsThreadUtils.h" 1.12 +#include <algorithm> 1.13 + 1.14 +nsresult 1.15 +nsSyncStreamListener::Init() 1.16 +{ 1.17 + return NS_NewPipe(getter_AddRefs(mPipeIn), 1.18 + getter_AddRefs(mPipeOut), 1.19 + nsIOService::gDefaultSegmentSize, 1.20 + UINT32_MAX, // no size limit 1.21 + false, 1.22 + false); 1.23 +} 1.24 + 1.25 +nsresult 1.26 +nsSyncStreamListener::WaitForData() 1.27 +{ 1.28 + mKeepWaiting = true; 1.29 + 1.30 + while (mKeepWaiting) 1.31 + NS_ENSURE_STATE(NS_ProcessNextEvent(NS_GetCurrentThread())); 1.32 + 1.33 + return NS_OK; 1.34 +} 1.35 + 1.36 +//----------------------------------------------------------------------------- 1.37 +// nsSyncStreamListener::nsISupports 1.38 +//----------------------------------------------------------------------------- 1.39 + 1.40 +NS_IMPL_ISUPPORTS(nsSyncStreamListener, 1.41 + nsIStreamListener, 1.42 + nsIRequestObserver, 1.43 + nsIInputStream, 1.44 + nsISyncStreamListener) 1.45 + 1.46 +//----------------------------------------------------------------------------- 1.47 +// nsSyncStreamListener::nsISyncStreamListener 1.48 +//----------------------------------------------------------------------------- 1.49 + 1.50 +NS_IMETHODIMP 1.51 +nsSyncStreamListener::GetInputStream(nsIInputStream **result) 1.52 +{ 1.53 + NS_ADDREF(*result = this); 1.54 + return NS_OK; 1.55 +} 1.56 + 1.57 +//----------------------------------------------------------------------------- 1.58 +// nsSyncStreamListener::nsIStreamListener 1.59 +//----------------------------------------------------------------------------- 1.60 + 1.61 +NS_IMETHODIMP 1.62 +nsSyncStreamListener::OnStartRequest(nsIRequest *request, 1.63 + nsISupports *context) 1.64 +{ 1.65 + return NS_OK; 1.66 +} 1.67 + 1.68 +NS_IMETHODIMP 1.69 +nsSyncStreamListener::OnDataAvailable(nsIRequest *request, 1.70 + nsISupports *context, 1.71 + nsIInputStream *stream, 1.72 + uint64_t offset, 1.73 + uint32_t count) 1.74 +{ 1.75 + uint32_t bytesWritten; 1.76 + 1.77 + nsresult rv = mPipeOut->WriteFrom(stream, count, &bytesWritten); 1.78 + 1.79 + // if we get an error, then return failure. this will cause the 1.80 + // channel to be canceled, and as a result our OnStopRequest method 1.81 + // will be called immediately. because of this we do not need to 1.82 + // set mStatus or mKeepWaiting here. 1.83 + if (NS_FAILED(rv)) 1.84 + return rv; 1.85 + 1.86 + // we expect that all data will be written to the pipe because 1.87 + // the pipe was created to have "infinite" room. 1.88 + NS_ASSERTION(bytesWritten == count, "did not write all data"); 1.89 + 1.90 + mKeepWaiting = false; // unblock Read 1.91 + return NS_OK; 1.92 +} 1.93 + 1.94 +NS_IMETHODIMP 1.95 +nsSyncStreamListener::OnStopRequest(nsIRequest *request, 1.96 + nsISupports *context, 1.97 + nsresult status) 1.98 +{ 1.99 + mStatus = status; 1.100 + mKeepWaiting = false; // unblock Read 1.101 + mDone = true; 1.102 + return NS_OK; 1.103 +} 1.104 + 1.105 +//----------------------------------------------------------------------------- 1.106 +// nsSyncStreamListener::nsIInputStream 1.107 +//----------------------------------------------------------------------------- 1.108 + 1.109 +NS_IMETHODIMP 1.110 +nsSyncStreamListener::Close() 1.111 +{ 1.112 + mStatus = NS_BASE_STREAM_CLOSED; 1.113 + mDone = true; 1.114 + 1.115 + // It'd be nice if we could explicitly cancel the request at this point, 1.116 + // but we don't have a reference to it, so the best we can do is close the 1.117 + // pipe so that the next OnDataAvailable event will fail. 1.118 + if (mPipeIn) { 1.119 + mPipeIn->Close(); 1.120 + mPipeIn = nullptr; 1.121 + } 1.122 + return NS_OK; 1.123 +} 1.124 + 1.125 +NS_IMETHODIMP 1.126 +nsSyncStreamListener::Available(uint64_t *result) 1.127 +{ 1.128 + if (NS_FAILED(mStatus)) 1.129 + return mStatus; 1.130 + 1.131 + mStatus = mPipeIn->Available(result); 1.132 + if (NS_SUCCEEDED(mStatus) && (*result == 0) && !mDone) { 1.133 + mStatus = WaitForData(); 1.134 + if (NS_SUCCEEDED(mStatus)) 1.135 + mStatus = mPipeIn->Available(result); 1.136 + } 1.137 + return mStatus; 1.138 +} 1.139 + 1.140 +NS_IMETHODIMP 1.141 +nsSyncStreamListener::Read(char *buf, 1.142 + uint32_t bufLen, 1.143 + uint32_t *result) 1.144 +{ 1.145 + if (mStatus == NS_BASE_STREAM_CLOSED) { 1.146 + *result = 0; 1.147 + return NS_OK; 1.148 + } 1.149 + 1.150 + uint64_t avail64; 1.151 + if (NS_FAILED(Available(&avail64))) 1.152 + return mStatus; 1.153 + 1.154 + uint32_t avail = (uint32_t)std::min(avail64, (uint64_t)bufLen); 1.155 + mStatus = mPipeIn->Read(buf, avail, result); 1.156 + return mStatus; 1.157 +} 1.158 + 1.159 +NS_IMETHODIMP 1.160 +nsSyncStreamListener::ReadSegments(nsWriteSegmentFun writer, 1.161 + void *closure, 1.162 + uint32_t count, 1.163 + uint32_t *result) 1.164 +{ 1.165 + if (mStatus == NS_BASE_STREAM_CLOSED) { 1.166 + *result = 0; 1.167 + return NS_OK; 1.168 + } 1.169 + 1.170 + uint64_t avail64; 1.171 + if (NS_FAILED(Available(&avail64))) 1.172 + return mStatus; 1.173 + 1.174 + uint32_t avail = (uint32_t)std::min(avail64, (uint64_t)count); 1.175 + mStatus = mPipeIn->ReadSegments(writer, closure, avail, result); 1.176 + return mStatus; 1.177 +} 1.178 + 1.179 +NS_IMETHODIMP 1.180 +nsSyncStreamListener::IsNonBlocking(bool *result) 1.181 +{ 1.182 + *result = false; 1.183 + return NS_OK; 1.184 +}