Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/ftp/nsFTPChannel.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* vim:set ts=4 sts=4 sw=4 et cin: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsFTPChannel.h"
8
#include "nsFtpConnectionThread.h"  // defines nsFtpState
9
10
#include "nsThreadUtils.h"
11
#include "mozilla/Attributes.h"
12
13
using namespace mozilla;
14
using namespace mozilla::net;
15
extern LazyLogModule gFTPLog;
16
17
// There are two transport connections established for an
18
// ftp connection. One is used for the command channel , and
19
// the other for the data channel. The command channel is the first
20
// connection made and is used to negotiate the second, data, channel.
21
// The data channel is driven by the command channel and is either
22
// initiated by the server (PORT command) or by the client (PASV command).
23
// Client initiation is the most common case and is attempted first.
24
25
//-----------------------------------------------------------------------------
26
27
NS_IMPL_ISUPPORTS_INHERITED(nsFtpChannel,
28
                            nsBaseChannel,
29
                            nsIUploadChannel,
30
                            nsIResumableChannel,
31
                            nsIFTPChannel,
32
                            nsIProxiedChannel,
33
                            nsIForcePendingChannel,
34
                            nsIChannelWithDivertableParentListener)
35
36
//-----------------------------------------------------------------------------
37
38
NS_IMETHODIMP
39
nsFtpChannel::SetUploadStream(nsIInputStream *stream,
40
                              const nsACString &contentType,
41
                              int64_t contentLength)
42
0
{
43
0
    NS_ENSURE_TRUE(!Pending(), NS_ERROR_IN_PROGRESS);
44
0
45
0
    mUploadStream = stream;
46
0
47
0
    // NOTE: contentLength is intentionally ignored here.
48
0
49
0
    return NS_OK;
50
0
}
51
52
NS_IMETHODIMP
53
nsFtpChannel::GetUploadStream(nsIInputStream **stream)
54
0
{
55
0
    NS_ENSURE_ARG_POINTER(stream);
56
0
    *stream = mUploadStream;
57
0
    NS_IF_ADDREF(*stream);
58
0
    return NS_OK;
59
0
}
60
61
//-----------------------------------------------------------------------------
62
63
NS_IMETHODIMP
64
nsFtpChannel::ResumeAt(uint64_t aStartPos, const nsACString& aEntityID)
65
0
{
66
0
    NS_ENSURE_TRUE(!Pending(), NS_ERROR_IN_PROGRESS);
67
0
    mEntityID = aEntityID;
68
0
    mStartPos = aStartPos;
69
0
    mResumeRequested = (mStartPos || !mEntityID.IsEmpty());
70
0
    return NS_OK;
71
0
}
72
73
NS_IMETHODIMP
74
nsFtpChannel::GetEntityID(nsACString& entityID)
75
0
{
76
0
    if (mEntityID.IsEmpty())
77
0
      return NS_ERROR_NOT_RESUMABLE;
78
0
79
0
    entityID = mEntityID;
80
0
    return NS_OK;
81
0
}
82
83
//-----------------------------------------------------------------------------
84
NS_IMETHODIMP
85
nsFtpChannel::GetProxyInfo(nsIProxyInfo** aProxyInfo)
86
0
{
87
0
    *aProxyInfo = ProxyInfo();
88
0
    NS_IF_ADDREF(*aProxyInfo);
89
0
    return NS_OK;
90
0
}
91
92
//-----------------------------------------------------------------------------
93
94
nsresult
95
nsFtpChannel::OpenContentStream(bool async, nsIInputStream **result,
96
                                nsIChannel** channel)
97
0
{
98
0
    if (!async)
99
0
        return NS_ERROR_NOT_IMPLEMENTED;
100
0
101
0
    nsFtpState *state = new nsFtpState();
102
0
    if (!state)
103
0
        return NS_ERROR_OUT_OF_MEMORY;
104
0
    NS_ADDREF(state);
105
0
106
0
    nsresult rv = state->Init(this);
107
0
    if (NS_FAILED(rv)) {
108
0
        NS_RELEASE(state);
109
0
        return rv;
110
0
    }
111
0
112
0
    *result = state;
113
0
    return NS_OK;
114
0
}
115
116
bool
117
nsFtpChannel::GetStatusArg(nsresult status, nsString &statusArg)
118
0
{
119
0
    nsAutoCString host;
120
0
    URI()->GetHost(host);
121
0
    CopyUTF8toUTF16(host, statusArg);
122
0
    return true;
123
0
}
124
125
void
126
nsFtpChannel::OnCallbacksChanged()
127
0
{
128
0
    mFTPEventSink = nullptr;
129
0
}
130
131
//-----------------------------------------------------------------------------
132
133
namespace {
134
135
class FTPEventSinkProxy final : public nsIFTPEventSink
136
{
137
0
    ~FTPEventSinkProxy() = default;
138
139
public:
140
    explicit FTPEventSinkProxy(nsIFTPEventSink* aTarget)
141
        : mTarget(aTarget)
142
        , mEventTarget(GetCurrentThreadEventTarget())
143
0
    { }
144
145
    NS_DECL_THREADSAFE_ISUPPORTS
146
    NS_DECL_NSIFTPEVENTSINK
147
148
    class OnFTPControlLogRunnable : public Runnable
149
    {
150
    public:
151
      OnFTPControlLogRunnable(nsIFTPEventSink* aTarget,
152
                              bool aServer,
153
                              const char* aMessage)
154
        : mozilla::Runnable("FTPEventSinkProxy::OnFTPControlLogRunnable")
155
        , mTarget(aTarget)
156
        , mServer(aServer)
157
        , mMessage(aMessage)
158
0
      {
159
0
      }
160
161
      NS_DECL_NSIRUNNABLE
162
163
    private:
164
        nsCOMPtr<nsIFTPEventSink> mTarget;
165
        bool mServer;
166
        nsCString mMessage;
167
    };
168
169
private:
170
    nsCOMPtr<nsIFTPEventSink> mTarget;
171
    nsCOMPtr<nsIEventTarget> mEventTarget;
172
};
173
174
NS_IMPL_ISUPPORTS(FTPEventSinkProxy, nsIFTPEventSink)
175
176
NS_IMETHODIMP
177
FTPEventSinkProxy::OnFTPControlLog(bool aServer, const char* aMsg)
178
0
{
179
0
    RefPtr<OnFTPControlLogRunnable> r =
180
0
        new OnFTPControlLogRunnable(mTarget, aServer, aMsg);
181
0
    return mEventTarget->Dispatch(r, NS_DISPATCH_NORMAL);
182
0
}
183
184
NS_IMETHODIMP
185
FTPEventSinkProxy::OnFTPControlLogRunnable::Run()
186
0
{
187
0
    mTarget->OnFTPControlLog(mServer, mMessage.get());
188
0
    return NS_OK;
189
0
}
190
191
} // namespace
192
193
void
194
nsFtpChannel::GetFTPEventSink(nsCOMPtr<nsIFTPEventSink> &aResult)
195
0
{
196
0
    if (!mFTPEventSink) {
197
0
        nsCOMPtr<nsIFTPEventSink> ftpSink;
198
0
        GetCallback(ftpSink);
199
0
        if (ftpSink) {
200
0
            mFTPEventSink = new FTPEventSinkProxy(ftpSink);
201
0
        }
202
0
    }
203
0
    aResult = mFTPEventSink;
204
0
}
205
206
NS_IMETHODIMP
207
nsFtpChannel::ForcePending(bool aForcePending)
208
0
{
209
0
    // Set true here so IsPending will return true.
210
0
    // Required for callback diversion from child back to parent. In such cases
211
0
    // OnStopRequest can be called in the parent before callbacks are diverted
212
0
    // back from the child to the listener in the parent.
213
0
    mForcePending = aForcePending;
214
0
215
0
    return NS_OK;
216
0
}
217
218
NS_IMETHODIMP
219
nsFtpChannel::IsPending(bool *result)
220
0
{
221
0
  *result = Pending();
222
0
  return NS_OK;
223
0
}
224
225
bool
226
nsFtpChannel::Pending() const
227
0
{
228
0
  return nsBaseChannel::Pending() || mForcePending;
229
0
}
230
231
NS_IMETHODIMP
232
nsFtpChannel::Suspend()
233
0
{
234
0
    LOG(("nsFtpChannel::Suspend [this=%p]\n", this));
235
0
236
0
    nsresult rv = SuspendInternal();
237
0
238
0
    nsresult rvParentChannel = NS_OK;
239
0
    if (mParentChannel) {
240
0
      rvParentChannel = mParentChannel->SuspendMessageDiversion();
241
0
    }
242
0
243
0
    return NS_FAILED(rv) ? rv : rvParentChannel;
244
0
}
245
246
NS_IMETHODIMP
247
nsFtpChannel::Resume()
248
0
{
249
0
    LOG(("nsFtpChannel::Resume [this=%p]\n", this));
250
0
251
0
    nsresult rv = ResumeInternal();
252
0
253
0
    nsresult rvParentChannel = NS_OK;
254
0
    if (mParentChannel) {
255
0
      rvParentChannel = mParentChannel->ResumeMessageDiversion();
256
0
    }
257
0
258
0
    return NS_FAILED(rv) ? rv : rvParentChannel;
259
0
}
260
261
//-----------------------------------------------------------------------------
262
// AChannelHasDivertableParentChannelAsListener internal functions
263
//-----------------------------------------------------------------------------
264
265
NS_IMETHODIMP
266
nsFtpChannel::MessageDiversionStarted(ADivertableParentChannel *aParentChannel)
267
0
{
268
0
  MOZ_ASSERT(!mParentChannel);
269
0
  mParentChannel = aParentChannel;
270
0
  // If the channel is suspended, propagate that info to the parent's mEventQ.
271
0
  uint32_t suspendCount = mSuspendCount;
272
0
  while (suspendCount--) {
273
0
    mParentChannel->SuspendMessageDiversion();
274
0
  }
275
0
  return NS_OK;
276
0
}
277
278
NS_IMETHODIMP
279
nsFtpChannel::MessageDiversionStop()
280
0
{
281
0
  LOG(("nsFtpChannel::MessageDiversionStop [this=%p]", this));
282
0
  MOZ_ASSERT(mParentChannel);
283
0
  mParentChannel = nullptr;
284
0
  return NS_OK;
285
0
}
286
287
NS_IMETHODIMP
288
nsFtpChannel::SuspendInternal()
289
0
{
290
0
    LOG(("nsFtpChannel::SuspendInternal [this=%p]\n", this));
291
0
    ++mSuspendCount;
292
0
    return nsBaseChannel::Suspend();
293
0
}
294
295
NS_IMETHODIMP
296
nsFtpChannel::ResumeInternal()
297
0
{
298
0
    LOG(("nsFtpChannel::ResumeInternal [this=%p]\n", this));
299
0
    NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED);
300
0
    --mSuspendCount;
301
0
    return nsBaseChannel::Resume();
302
0
}