Line data Source code
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 0 : 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 0 : nsFtpChannel::SetUploadStream(nsIInputStream *stream,
40 : const nsACString &contentType,
41 : int64_t contentLength)
42 : {
43 0 : NS_ENSURE_TRUE(!Pending(), NS_ERROR_IN_PROGRESS);
44 :
45 0 : mUploadStream = stream;
46 :
47 : // NOTE: contentLength is intentionally ignored here.
48 :
49 0 : return NS_OK;
50 : }
51 :
52 : NS_IMETHODIMP
53 0 : nsFtpChannel::GetUploadStream(nsIInputStream **stream)
54 : {
55 0 : NS_ENSURE_ARG_POINTER(stream);
56 0 : *stream = mUploadStream;
57 0 : NS_IF_ADDREF(*stream);
58 0 : return NS_OK;
59 : }
60 :
61 : //-----------------------------------------------------------------------------
62 :
63 : NS_IMETHODIMP
64 0 : nsFtpChannel::ResumeAt(uint64_t aStartPos, const nsACString& aEntityID)
65 : {
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 : }
72 :
73 : NS_IMETHODIMP
74 0 : nsFtpChannel::GetEntityID(nsACString& entityID)
75 : {
76 0 : if (mEntityID.IsEmpty())
77 0 : return NS_ERROR_NOT_RESUMABLE;
78 :
79 0 : entityID = mEntityID;
80 0 : return NS_OK;
81 : }
82 :
83 : //-----------------------------------------------------------------------------
84 : NS_IMETHODIMP
85 0 : nsFtpChannel::GetProxyInfo(nsIProxyInfo** aProxyInfo)
86 : {
87 0 : *aProxyInfo = ProxyInfo();
88 0 : NS_IF_ADDREF(*aProxyInfo);
89 0 : return NS_OK;
90 : }
91 :
92 : //-----------------------------------------------------------------------------
93 :
94 : nsresult
95 0 : nsFtpChannel::OpenContentStream(bool async, nsIInputStream **result,
96 : nsIChannel** channel)
97 : {
98 0 : if (!async)
99 0 : return NS_ERROR_NOT_IMPLEMENTED;
100 :
101 0 : nsFtpState *state = new nsFtpState();
102 0 : if (!state)
103 0 : return NS_ERROR_OUT_OF_MEMORY;
104 0 : NS_ADDREF(state);
105 :
106 0 : nsresult rv = state->Init(this);
107 0 : if (NS_FAILED(rv)) {
108 0 : NS_RELEASE(state);
109 0 : return rv;
110 : }
111 :
112 0 : *result = state;
113 0 : return NS_OK;
114 : }
115 :
116 : bool
117 0 : nsFtpChannel::GetStatusArg(nsresult status, nsString &statusArg)
118 : {
119 0 : nsAutoCString host;
120 0 : URI()->GetHost(host);
121 0 : CopyUTF8toUTF16(host, statusArg);
122 0 : return true;
123 : }
124 :
125 : void
126 0 : nsFtpChannel::OnCallbacksChanged()
127 : {
128 0 : mFTPEventSink = nullptr;
129 0 : }
130 :
131 : //-----------------------------------------------------------------------------
132 :
133 : namespace {
134 :
135 : class FTPEventSinkProxy final : public nsIFTPEventSink
136 : {
137 0 : ~FTPEventSinkProxy() {}
138 :
139 : public:
140 0 : explicit FTPEventSinkProxy(nsIFTPEventSink* aTarget)
141 0 : : mTarget(aTarget)
142 0 : , mEventTarget(GetCurrentThreadEventTarget())
143 0 : { }
144 :
145 : NS_DECL_THREADSAFE_ISUPPORTS
146 : NS_DECL_NSIFTPEVENTSINK
147 :
148 0 : class OnFTPControlLogRunnable : public Runnable
149 : {
150 : public:
151 0 : OnFTPControlLogRunnable(nsIFTPEventSink* aTarget,
152 : bool aServer,
153 : const char* aMessage)
154 0 : : mozilla::Runnable("FTPEventSinkProxy::OnFTPControlLogRunnable")
155 : , mTarget(aTarget)
156 : , mServer(aServer)
157 0 : , mMessage(aMessage)
158 : {
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 0 : NS_IMPL_ISUPPORTS(FTPEventSinkProxy, nsIFTPEventSink)
175 :
176 : NS_IMETHODIMP
177 0 : FTPEventSinkProxy::OnFTPControlLog(bool aServer, const char* aMsg)
178 : {
179 : RefPtr<OnFTPControlLogRunnable> r =
180 0 : new OnFTPControlLogRunnable(mTarget, aServer, aMsg);
181 0 : return mEventTarget->Dispatch(r, NS_DISPATCH_NORMAL);
182 : }
183 :
184 : NS_IMETHODIMP
185 0 : FTPEventSinkProxy::OnFTPControlLogRunnable::Run()
186 : {
187 0 : mTarget->OnFTPControlLog(mServer, mMessage.get());
188 0 : return NS_OK;
189 : }
190 :
191 : } // namespace
192 :
193 : void
194 0 : nsFtpChannel::GetFTPEventSink(nsCOMPtr<nsIFTPEventSink> &aResult)
195 : {
196 0 : if (!mFTPEventSink) {
197 0 : nsCOMPtr<nsIFTPEventSink> ftpSink;
198 0 : GetCallback(ftpSink);
199 0 : if (ftpSink) {
200 0 : mFTPEventSink = new FTPEventSinkProxy(ftpSink);
201 : }
202 : }
203 0 : aResult = mFTPEventSink;
204 0 : }
205 :
206 : NS_IMETHODIMP
207 0 : nsFtpChannel::ForcePending(bool aForcePending)
208 : {
209 : // Set true here so IsPending will return true.
210 : // Required for callback diversion from child back to parent. In such cases
211 : // OnStopRequest can be called in the parent before callbacks are diverted
212 : // back from the child to the listener in the parent.
213 0 : mForcePending = aForcePending;
214 :
215 0 : return NS_OK;
216 : }
217 :
218 : NS_IMETHODIMP
219 0 : nsFtpChannel::IsPending(bool *result)
220 : {
221 0 : *result = Pending();
222 0 : return NS_OK;
223 : }
224 :
225 : bool
226 0 : nsFtpChannel::Pending() const
227 : {
228 0 : return nsBaseChannel::Pending() || mForcePending;
229 : }
230 :
231 : NS_IMETHODIMP
232 0 : nsFtpChannel::Suspend()
233 : {
234 0 : LOG(("nsFtpChannel::Suspend [this=%p]\n", this));
235 :
236 0 : nsresult rv = nsBaseChannel::Suspend();
237 :
238 0 : nsresult rvParentChannel = NS_OK;
239 0 : if (mParentChannel) {
240 0 : rvParentChannel = mParentChannel->SuspendMessageDiversion();
241 : }
242 :
243 0 : return NS_FAILED(rv) ? rv : rvParentChannel;
244 : }
245 :
246 : NS_IMETHODIMP
247 0 : nsFtpChannel::Resume()
248 : {
249 0 : LOG(("nsFtpChannel::Resume [this=%p]\n", this));
250 :
251 0 : nsresult rv = nsBaseChannel::Resume();
252 :
253 0 : nsresult rvParentChannel = NS_OK;
254 0 : if (mParentChannel) {
255 0 : rvParentChannel = mParentChannel->ResumeMessageDiversion();
256 : }
257 :
258 0 : return NS_FAILED(rv) ? rv : rvParentChannel;
259 : }
260 :
261 : //-----------------------------------------------------------------------------
262 : // AChannelHasDivertableParentChannelAsListener internal functions
263 : //-----------------------------------------------------------------------------
264 :
265 : NS_IMETHODIMP
266 0 : nsFtpChannel::MessageDiversionStarted(ADivertableParentChannel *aParentChannel)
267 : {
268 0 : MOZ_ASSERT(!mParentChannel);
269 0 : mParentChannel = aParentChannel;
270 0 : return NS_OK;
271 : }
272 :
273 : NS_IMETHODIMP
274 0 : nsFtpChannel::MessageDiversionStop()
275 : {
276 0 : LOG(("nsFtpChannel::MessageDiversionStop [this=%p]", this));
277 0 : MOZ_ASSERT(mParentChannel);
278 0 : mParentChannel = nullptr;
279 0 : return NS_OK;
280 : }
281 :
282 : NS_IMETHODIMP
283 0 : nsFtpChannel::SuspendInternal()
284 : {
285 0 : LOG(("nsFtpChannel::SuspendInternal [this=%p]\n", this));
286 :
287 0 : return nsBaseChannel::Suspend();
288 : }
289 :
290 : NS_IMETHODIMP
291 0 : nsFtpChannel::ResumeInternal()
292 : {
293 0 : LOG(("nsFtpChannel::ResumeInternal [this=%p]\n", this));
294 :
295 0 : return nsBaseChannel::Resume();
296 : }
|