Fix trace_tests.py when showing output. (r=jorendorff)
[mozilla-central.git] / dom / plugins / BrowserStreamChild.cpp
blob9154dfcc27399b0c863792ac699990cd4d8524e4
1 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Plugin App.
17 * The Initial Developer of the Original Code is
18 * Benjamin Smedberg <benjamin@smedbergs.us>
19 * Portions created by the Initial Developer are Copyright (C) 2009
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
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 "BrowserStreamChild.h"
39 #include "PluginInstanceChild.h"
40 #include "StreamNotifyChild.h"
42 namespace mozilla {
43 namespace plugins {
45 BrowserStreamChild::BrowserStreamChild(PluginInstanceChild* instance,
46 const nsCString& url,
47 const uint32_t& length,
48 const uint32_t& lastmodified,
49 StreamNotifyChild* notifyData,
50 const nsCString& headers,
51 const nsCString& mimeType,
52 const bool& seekable,
53 NPError* rv,
54 uint16_t* stype)
55 : mInstance(instance)
56 , mStreamStatus(kStreamOpen)
57 , mDestroyPending(NOT_DESTROYED)
58 , mNotifyPending(false)
59 , mInstanceDying(false)
60 , mState(CONSTRUCTING)
61 , mURL(url)
62 , mHeaders(headers)
63 , mStreamNotify(notifyData)
64 , mDeliveryTracker(this)
66 PLUGIN_LOG_DEBUG(("%s (%s, %i, %i, %p, %s, %s)", FULLFUNCTION,
67 url.get(), length, lastmodified, (void*) notifyData,
68 headers.get(), mimeType.get()));
70 AssertPluginThread();
72 memset(&mStream, 0, sizeof(mStream));
73 mStream.ndata = static_cast<AStream*>(this);
74 mStream.url = NullableStringGet(mURL);
75 mStream.end = length;
76 mStream.lastmodified = lastmodified;
77 mStream.headers = NullableStringGet(mHeaders);
78 if (notifyData)
79 mStream.notifyData = notifyData->mClosure;
82 NPError
83 BrowserStreamChild::StreamConstructed(
84 const nsCString& mimeType,
85 const bool& seekable,
86 uint16_t* stype)
88 NPError rv = NPERR_NO_ERROR;
90 *stype = NP_NORMAL;
91 rv = mInstance->mPluginIface->newstream(
92 &mInstance->mData, const_cast<char*>(NullableStringGet(mimeType)),
93 &mStream, seekable, stype);
94 if (rv != NPERR_NO_ERROR) {
95 mState = DELETING;
96 mStreamNotify = NULL;
98 else {
99 mState = ALIVE;
101 if (mStreamNotify)
102 mStreamNotify->SetAssociatedStream(this);
105 return rv;
108 BrowserStreamChild::~BrowserStreamChild()
110 NS_ASSERTION(!mStreamNotify, "Should have nulled it by now!");
113 bool
114 BrowserStreamChild::RecvWrite(const int32_t& offset,
115 const Buffer& data,
116 const uint32_t& newlength)
118 PLUGIN_LOG_DEBUG_FUNCTION;
120 AssertPluginThread();
122 if (ALIVE != mState)
123 NS_RUNTIMEABORT("Unexpected state: received data after NPP_DestroyStream?");
125 if (kStreamOpen != mStreamStatus)
126 return true;
128 mStream.end = newlength;
130 NS_ASSERTION(data.Length() > 0, "Empty data");
132 PendingData* newdata = mPendingData.AppendElement();
133 newdata->offset = offset;
134 newdata->data = data;
135 newdata->curpos = 0;
137 EnsureDeliveryPending();
139 return true;
142 bool
143 BrowserStreamChild::AnswerNPP_StreamAsFile(const nsCString& fname)
145 PLUGIN_LOG_DEBUG(("%s (fname=%s)", FULLFUNCTION, fname.get()));
147 AssertPluginThread();
149 if (ALIVE != mState)
150 NS_RUNTIMEABORT("Unexpected state: received file after NPP_DestroyStream?");
152 if (kStreamOpen != mStreamStatus)
153 return true;
155 mInstance->mPluginIface->asfile(&mInstance->mData, &mStream,
156 fname.get());
157 return true;
160 bool
161 BrowserStreamChild::RecvNPP_DestroyStream(const NPReason& reason)
163 PLUGIN_LOG_DEBUG_METHOD;
165 if (ALIVE != mState)
166 NS_RUNTIMEABORT("Unexpected state: recevied NPP_DestroyStream twice?");
168 mState = DYING;
169 mDestroyPending = DESTROY_PENDING;
170 if (NPRES_DONE != reason)
171 mStreamStatus = reason;
173 EnsureDeliveryPending();
174 return true;
177 bool
178 BrowserStreamChild::Recv__delete__()
180 AssertPluginThread();
182 if (DELETING != mState)
183 NS_RUNTIMEABORT("Bad state, not DELETING");
185 return true;
188 NPError
189 BrowserStreamChild::NPN_RequestRead(NPByteRange* aRangeList)
191 PLUGIN_LOG_DEBUG_FUNCTION;
193 AssertPluginThread();
195 if (ALIVE != mState || kStreamOpen != mStreamStatus)
196 return NPERR_GENERIC_ERROR;
198 IPCByteRanges ranges;
199 for (; aRangeList; aRangeList = aRangeList->next) {
200 IPCByteRange br = {aRangeList->offset, aRangeList->length};
201 ranges.push_back(br);
204 NPError result;
205 CallNPN_RequestRead(ranges, &result);
206 return result;
209 void
210 BrowserStreamChild::NPN_DestroyStream(NPReason reason)
212 mStreamStatus = reason;
213 if (ALIVE == mState)
214 SendNPN_DestroyStream(reason);
216 EnsureDeliveryPending();
219 void
220 BrowserStreamChild::EnsureDeliveryPending()
222 MessageLoop::current()->PostTask(FROM_HERE,
223 mDeliveryTracker.NewRunnableMethod(&BrowserStreamChild::Deliver));
226 void
227 BrowserStreamChild::Deliver()
229 while (kStreamOpen == mStreamStatus && mPendingData.Length()) {
230 if (DeliverPendingData() && kStreamOpen == mStreamStatus) {
231 SetSuspendedTimer();
232 return;
235 ClearSuspendedTimer();
237 NS_ASSERTION(kStreamOpen != mStreamStatus || 0 == mPendingData.Length(),
238 "Exit out of the data-delivery loop with pending data");
239 mPendingData.Clear();
241 if (DESTROY_PENDING == mDestroyPending) {
242 mDestroyPending = DESTROYED;
243 if (mState != DYING)
244 NS_RUNTIMEABORT("mDestroyPending but state not DYING");
246 NS_ASSERTION(NPRES_DONE != mStreamStatus, "Success status set too early!");
247 if (kStreamOpen == mStreamStatus)
248 mStreamStatus = NPRES_DONE;
250 (void) mInstance->mPluginIface
251 ->destroystream(&mInstance->mData, &mStream, mStreamStatus);
253 if (DESTROYED == mDestroyPending && mNotifyPending) {
254 NS_ASSERTION(mStreamNotify, "mDestroyPending but no mStreamNotify?");
256 mNotifyPending = false;
257 mStreamNotify->NPP_URLNotify(mStreamStatus);
258 delete mStreamNotify;
259 mStreamNotify = NULL;
261 if (DYING == mState && DESTROYED == mDestroyPending
262 && !mStreamNotify && !mInstanceDying) {
263 SendStreamDestroyed();
264 mState = DELETING;
268 bool
269 BrowserStreamChild::DeliverPendingData()
271 if (mState != ALIVE && mState != DYING)
272 NS_RUNTIMEABORT("Unexpected state");
274 NS_ASSERTION(mPendingData.Length(), "Called from Deliver with empty pending");
276 while (mPendingData[0].curpos < static_cast<int32_t>(mPendingData[0].data.Length())) {
277 int32_t r = mInstance->mPluginIface->writeready(&mInstance->mData, &mStream);
278 if (kStreamOpen != mStreamStatus)
279 return false;
280 if (0 == r) // plugin wants to suspend delivery
281 return true;
283 r = mInstance->mPluginIface->write(
284 &mInstance->mData, &mStream,
285 mPendingData[0].offset + mPendingData[0].curpos, // offset
286 mPendingData[0].data.Length() - mPendingData[0].curpos, // length
287 const_cast<char*>(mPendingData[0].data.BeginReading() + mPendingData[0].curpos));
288 if (kStreamOpen != mStreamStatus)
289 return false;
290 if (0 == r)
291 return true;
292 if (r < 0) { // error condition
293 NPN_DestroyStream(NPRES_NETWORK_ERR);
294 return false;
296 mPendingData[0].curpos += r;
298 mPendingData.RemoveElementAt(0);
299 return false;
302 void
303 BrowserStreamChild::SetSuspendedTimer()
305 if (mSuspendedTimer.IsRunning())
306 return;
307 mSuspendedTimer.Start(
308 base::TimeDelta::FromMilliseconds(100), // 100ms copied from Mozilla plugin host
309 this, &BrowserStreamChild::Deliver);
312 void
313 BrowserStreamChild::ClearSuspendedTimer()
315 mSuspendedTimer.Stop();
318 } /* namespace plugins */
319 } /* namespace mozilla */