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
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.
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"
45 BrowserStreamChild::BrowserStreamChild(PluginInstanceChild
* instance
,
47 const uint32_t& length
,
48 const uint32_t& lastmodified
,
49 StreamNotifyChild
* notifyData
,
50 const nsCString
& headers
,
51 const nsCString
& mimeType
,
56 , mStreamStatus(kStreamOpen
)
57 , mDestroyPending(NOT_DESTROYED
)
58 , mNotifyPending(false)
59 , mInstanceDying(false)
60 , mState(CONSTRUCTING
)
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()));
72 memset(&mStream
, 0, sizeof(mStream
));
73 mStream
.ndata
= static_cast<AStream
*>(this);
74 mStream
.url
= NullableStringGet(mURL
);
76 mStream
.lastmodified
= lastmodified
;
77 mStream
.headers
= NullableStringGet(mHeaders
);
79 mStream
.notifyData
= notifyData
->mClosure
;
83 BrowserStreamChild::StreamConstructed(
84 const nsCString
& mimeType
,
88 NPError rv
= NPERR_NO_ERROR
;
91 rv
= mInstance
->mPluginIface
->newstream(
92 &mInstance
->mData
, const_cast<char*>(NullableStringGet(mimeType
)),
93 &mStream
, seekable
, stype
);
94 if (rv
!= NPERR_NO_ERROR
) {
102 mStreamNotify
->SetAssociatedStream(this);
108 BrowserStreamChild::~BrowserStreamChild()
110 NS_ASSERTION(!mStreamNotify
, "Should have nulled it by now!");
114 BrowserStreamChild::RecvWrite(const int32_t& offset
,
116 const uint32_t& newlength
)
118 PLUGIN_LOG_DEBUG_FUNCTION
;
120 AssertPluginThread();
123 NS_RUNTIMEABORT("Unexpected state: received data after NPP_DestroyStream?");
125 if (kStreamOpen
!= mStreamStatus
)
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
;
137 EnsureDeliveryPending();
143 BrowserStreamChild::AnswerNPP_StreamAsFile(const nsCString
& fname
)
145 PLUGIN_LOG_DEBUG(("%s (fname=%s)", FULLFUNCTION
, fname
.get()));
147 AssertPluginThread();
150 NS_RUNTIMEABORT("Unexpected state: received file after NPP_DestroyStream?");
152 if (kStreamOpen
!= mStreamStatus
)
155 mInstance
->mPluginIface
->asfile(&mInstance
->mData
, &mStream
,
161 BrowserStreamChild::RecvNPP_DestroyStream(const NPReason
& reason
)
163 PLUGIN_LOG_DEBUG_METHOD
;
166 NS_RUNTIMEABORT("Unexpected state: recevied NPP_DestroyStream twice?");
169 mDestroyPending
= DESTROY_PENDING
;
170 if (NPRES_DONE
!= reason
)
171 mStreamStatus
= reason
;
173 EnsureDeliveryPending();
178 BrowserStreamChild::Recv__delete__()
180 AssertPluginThread();
182 if (DELETING
!= mState
)
183 NS_RUNTIMEABORT("Bad state, not DELETING");
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
);
205 CallNPN_RequestRead(ranges
, &result
);
210 BrowserStreamChild::NPN_DestroyStream(NPReason reason
)
212 mStreamStatus
= reason
;
214 SendNPN_DestroyStream(reason
);
216 EnsureDeliveryPending();
220 BrowserStreamChild::EnsureDeliveryPending()
222 MessageLoop::current()->PostTask(FROM_HERE
,
223 mDeliveryTracker
.NewRunnableMethod(&BrowserStreamChild::Deliver
));
227 BrowserStreamChild::Deliver()
229 while (kStreamOpen
== mStreamStatus
&& mPendingData
.Length()) {
230 if (DeliverPendingData() && kStreamOpen
== mStreamStatus
) {
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
;
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();
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
)
280 if (0 == r
) // plugin wants to suspend delivery
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
)
292 if (r
< 0) { // error condition
293 NPN_DestroyStream(NPRES_NETWORK_ERR
);
296 mPendingData
[0].curpos
+= r
;
298 mPendingData
.RemoveElementAt(0);
303 BrowserStreamChild::SetSuspendedTimer()
305 if (mSuspendedTimer
.IsRunning())
307 mSuspendedTimer
.Start(
308 base::TimeDelta::FromMilliseconds(100), // 100ms copied from Mozilla plugin host
309 this, &BrowserStreamChild::Deliver
);
313 BrowserStreamChild::ClearSuspendedTimer()
315 mSuspendedTimer
.Stop();
318 } /* namespace plugins */
319 } /* namespace mozilla */