Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/plugins/ipc/BrowserStreamChild.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "mozilla/plugins/BrowserStreamChild.h"
7
8
#include "mozilla/Attributes.h"
9
#include "mozilla/plugins/PluginInstanceChild.h"
10
#include "mozilla/plugins/StreamNotifyChild.h"
11
12
namespace mozilla {
13
namespace plugins {
14
15
BrowserStreamChild::BrowserStreamChild(PluginInstanceChild* instance,
16
                                       const nsCString& url,
17
                                       const uint32_t& length,
18
                                       const uint32_t& lastmodified,
19
                                       StreamNotifyChild* notifyData,
20
                                       const nsCString& headers)
21
  : mInstance(instance)
22
  , mStreamStatus(kStreamOpen)
23
  , mDestroyPending(NOT_DESTROYED)
24
  , mNotifyPending(false)
25
  , mInstanceDying(false)
26
  , mState(CONSTRUCTING)
27
  , mURL(url)
28
  , mHeaders(headers)
29
  , mStreamNotify(notifyData)
30
  , mDeliveryTracker(this)
31
0
{
32
0
  PLUGIN_LOG_DEBUG(("%s (%s, %i, %i, %p, %s)", FULLFUNCTION,
33
0
                    url.get(), length, lastmodified, (void*) notifyData,
34
0
                    headers.get()));
35
0
36
0
  AssertPluginThread();
37
0
38
0
  memset(&mStream, 0, sizeof(mStream));
39
0
  mStream.ndata = static_cast<AStream*>(this);
40
0
  mStream.url = NullableStringGet(mURL);
41
0
  mStream.end = length;
42
0
  mStream.lastmodified = lastmodified;
43
0
  mStream.headers = NullableStringGet(mHeaders);
44
0
  if (notifyData) {
45
0
    mStream.notifyData = notifyData->mClosure;
46
0
    notifyData->SetAssociatedStream(this);
47
0
  }
48
0
}
49
50
NPError
51
BrowserStreamChild::StreamConstructed(
52
            const nsCString& mimeType,
53
            const bool& seekable,
54
            uint16_t* stype)
55
0
{
56
0
  NPError rv = NPERR_NO_ERROR;
57
0
58
0
  *stype = NP_NORMAL;
59
0
  rv = mInstance->mPluginIface->newstream(
60
0
    &mInstance->mData, const_cast<char*>(NullableStringGet(mimeType)),
61
0
    &mStream, seekable, stype);
62
0
63
0
  // NP_NORMAL is the only permissible stream type
64
0
  if (*stype != NP_NORMAL) {
65
0
    rv = NPERR_INVALID_PARAM;
66
0
    // The plugin thinks the stream is alive, so we kill it explicitly
67
0
    (void) mInstance->mPluginIface
68
0
      ->destroystream(&mInstance->mData, &mStream, NPRES_NETWORK_ERR);
69
0
  }
70
0
71
0
  if (rv != NPERR_NO_ERROR) {
72
0
    mState = DELETING;
73
0
    if (mStreamNotify) {
74
0
      mStreamNotify->SetAssociatedStream(nullptr);
75
0
      mStreamNotify = nullptr;
76
0
    }
77
0
  }
78
0
  else {
79
0
    mState = ALIVE;
80
0
  }
81
0
82
0
  return rv;
83
0
}
84
85
BrowserStreamChild::~BrowserStreamChild()
86
0
{
87
0
  NS_ASSERTION(!mStreamNotify, "Should have nulled it by now!");
88
0
}
89
90
mozilla::ipc::IPCResult
91
BrowserStreamChild::RecvWrite(const int32_t& offset,
92
                              const uint32_t& newlength,
93
                              const Buffer& data)
94
0
{
95
0
  PLUGIN_LOG_DEBUG_FUNCTION;
96
0
97
0
  AssertPluginThread();
98
0
99
0
  if (ALIVE != mState)
100
0
    MOZ_CRASH("Unexpected state: received data after NPP_DestroyStream?");
101
0
102
0
  if (kStreamOpen != mStreamStatus)
103
0
    return IPC_OK();
104
0
105
0
  mStream.end = newlength;
106
0
107
0
  NS_ASSERTION(data.Length() > 0, "Empty data");
108
0
109
0
  PendingData* newdata = mPendingData.AppendElement();
110
0
  newdata->offset = offset;
111
0
  newdata->data = data;
112
0
  newdata->curpos = 0;
113
0
114
0
  EnsureDeliveryPending();
115
0
116
0
  return IPC_OK();
117
0
}
118
119
mozilla::ipc::IPCResult
120
BrowserStreamChild::RecvNPP_DestroyStream(const NPReason& reason)
121
0
{
122
0
  PLUGIN_LOG_DEBUG_METHOD;
123
0
124
0
  if (ALIVE != mState)
125
0
    MOZ_CRASH("Unexpected state: recevied NPP_DestroyStream twice?");
126
0
127
0
  mState = DYING;
128
0
  mDestroyPending = DESTROY_PENDING;
129
0
  if (NPRES_DONE != reason)
130
0
    mStreamStatus = reason;
131
0
132
0
  EnsureDeliveryPending();
133
0
  return IPC_OK();
134
0
}
135
136
mozilla::ipc::IPCResult
137
BrowserStreamChild::Recv__delete__()
138
0
{
139
0
  AssertPluginThread();
140
0
141
0
  if (DELETING != mState)
142
0
    MOZ_CRASH("Bad state, not DELETING");
143
0
144
0
  return IPC_OK();
145
0
}
146
147
void
148
BrowserStreamChild::EnsureDeliveryPending()
149
0
{
150
0
  MessageLoop::current()->PostTask(
151
0
    mDeliveryTracker.NewRunnableMethod(&BrowserStreamChild::Deliver));
152
0
}
153
154
void
155
BrowserStreamChild::Deliver()
156
0
{
157
0
  while (kStreamOpen == mStreamStatus && mPendingData.Length()) {
158
0
    if (DeliverPendingData() && kStreamOpen == mStreamStatus) {
159
0
      SetSuspendedTimer();
160
0
      return;
161
0
    }
162
0
  }
163
0
  ClearSuspendedTimer();
164
0
165
0
  NS_ASSERTION(kStreamOpen != mStreamStatus || 0 == mPendingData.Length(),
166
0
               "Exit out of the data-delivery loop with pending data");
167
0
  mPendingData.Clear();
168
0
169
0
  if (DESTROY_PENDING == mDestroyPending) {
170
0
    mDestroyPending = DESTROYED;
171
0
    if (mState != DYING)
172
0
      MOZ_CRASH("mDestroyPending but state not DYING");
173
0
174
0
    NS_ASSERTION(NPRES_DONE != mStreamStatus, "Success status set too early!");
175
0
    if (kStreamOpen == mStreamStatus)
176
0
      mStreamStatus = NPRES_DONE;
177
0
178
0
    (void) mInstance->mPluginIface
179
0
      ->destroystream(&mInstance->mData, &mStream, mStreamStatus);
180
0
  }
181
0
  if (DESTROYED == mDestroyPending && mNotifyPending) {
182
0
    NS_ASSERTION(mStreamNotify, "mDestroyPending but no mStreamNotify?");
183
0
184
0
    mNotifyPending = false;
185
0
    mStreamNotify->NPP_URLNotify(mStreamStatus);
186
0
    delete mStreamNotify;
187
0
    mStreamNotify = nullptr;
188
0
  }
189
0
  if (DYING == mState && DESTROYED == mDestroyPending
190
0
      && !mStreamNotify && !mInstanceDying) {
191
0
    SendStreamDestroyed();
192
0
    mState = DELETING;
193
0
  }
194
0
}
195
196
bool
197
BrowserStreamChild::DeliverPendingData()
198
0
{
199
0
  if (mState != ALIVE && mState != DYING)
200
0
    MOZ_CRASH("Unexpected state");
201
0
202
0
  NS_ASSERTION(mPendingData.Length(), "Called from Deliver with empty pending");
203
0
204
0
  while (mPendingData[0].curpos < static_cast<int32_t>(mPendingData[0].data.Length())) {
205
0
    int32_t r = mInstance->mPluginIface->writeready(&mInstance->mData, &mStream);
206
0
    if (kStreamOpen != mStreamStatus)
207
0
      return false;
208
0
    if (0 == r) // plugin wants to suspend delivery
209
0
      return true;
210
0
211
0
    r = mInstance->mPluginIface->write(
212
0
      &mInstance->mData, &mStream,
213
0
      mPendingData[0].offset + mPendingData[0].curpos, // offset
214
0
      mPendingData[0].data.Length() - mPendingData[0].curpos, // length
215
0
      const_cast<char*>(mPendingData[0].data.BeginReading() + mPendingData[0].curpos));
216
0
    if (kStreamOpen != mStreamStatus)
217
0
      return false;
218
0
    if (0 == r)
219
0
      return true;
220
0
    if (r < 0) { // error condition
221
0
      mStreamStatus = NPRES_NETWORK_ERR;
222
0
223
0
      // Set up stream destruction
224
0
      EnsureDeliveryPending();
225
0
      return false;
226
0
    }
227
0
    mPendingData[0].curpos += r;
228
0
  }
229
0
  mPendingData.RemoveElementAt(0);
230
0
  return false;
231
0
}
232
233
void
234
BrowserStreamChild::SetSuspendedTimer()
235
0
{
236
0
  if (mSuspendedTimer.IsRunning())
237
0
    return;
238
0
  mSuspendedTimer.Start(
239
0
    base::TimeDelta::FromMilliseconds(100), // 100ms copied from Mozilla plugin host
240
0
    this, &BrowserStreamChild::Deliver);
241
0
}
242
243
void
244
BrowserStreamChild::ClearSuspendedTimer()
245
0
{
246
0
  mSuspendedTimer.Stop();
247
0
}
248
249
} /* namespace plugins */
250
} /* namespace mozilla */