netwerk/protocol/ftp/nsFTPChannel.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:001115f53b0e
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 #if defined(PR_LOGGING)
14 extern PRLogModuleInfo* gFTPLog;
15 #endif /* PR_LOGGING */
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
34 //-----------------------------------------------------------------------------
35
36 NS_IMETHODIMP
37 nsFtpChannel::SetUploadStream(nsIInputStream *stream,
38 const nsACString &contentType,
39 int64_t contentLength)
40 {
41 NS_ENSURE_TRUE(!Pending(), NS_ERROR_IN_PROGRESS);
42
43 mUploadStream = stream;
44
45 // NOTE: contentLength is intentionally ignored here.
46
47 return NS_OK;
48 }
49
50 NS_IMETHODIMP
51 nsFtpChannel::GetUploadStream(nsIInputStream **stream)
52 {
53 NS_ENSURE_ARG_POINTER(stream);
54 *stream = mUploadStream;
55 NS_IF_ADDREF(*stream);
56 return NS_OK;
57 }
58
59 //-----------------------------------------------------------------------------
60
61 NS_IMETHODIMP
62 nsFtpChannel::ResumeAt(uint64_t aStartPos, const nsACString& aEntityID)
63 {
64 NS_ENSURE_TRUE(!Pending(), NS_ERROR_IN_PROGRESS);
65 mEntityID = aEntityID;
66 mStartPos = aStartPos;
67 mResumeRequested = (mStartPos || !mEntityID.IsEmpty());
68 return NS_OK;
69 }
70
71 NS_IMETHODIMP
72 nsFtpChannel::GetEntityID(nsACString& entityID)
73 {
74 if (mEntityID.IsEmpty())
75 return NS_ERROR_NOT_RESUMABLE;
76
77 entityID = mEntityID;
78 return NS_OK;
79 }
80
81 //-----------------------------------------------------------------------------
82 NS_IMETHODIMP
83 nsFtpChannel::GetProxyInfo(nsIProxyInfo** aProxyInfo)
84 {
85 *aProxyInfo = ProxyInfo();
86 NS_IF_ADDREF(*aProxyInfo);
87 return NS_OK;
88 }
89
90 //-----------------------------------------------------------------------------
91
92 nsresult
93 nsFtpChannel::OpenContentStream(bool async, nsIInputStream **result,
94 nsIChannel** channel)
95 {
96 if (!async)
97 return NS_ERROR_NOT_IMPLEMENTED;
98
99 nsFtpState *state = new nsFtpState();
100 if (!state)
101 return NS_ERROR_OUT_OF_MEMORY;
102 NS_ADDREF(state);
103
104 nsresult rv = state->Init(this);
105 if (NS_FAILED(rv)) {
106 NS_RELEASE(state);
107 return rv;
108 }
109
110 *result = state;
111 return NS_OK;
112 }
113
114 bool
115 nsFtpChannel::GetStatusArg(nsresult status, nsString &statusArg)
116 {
117 nsAutoCString host;
118 URI()->GetHost(host);
119 CopyUTF8toUTF16(host, statusArg);
120 return true;
121 }
122
123 void
124 nsFtpChannel::OnCallbacksChanged()
125 {
126 mFTPEventSink = nullptr;
127 }
128
129 //-----------------------------------------------------------------------------
130
131 namespace {
132
133 class FTPEventSinkProxy MOZ_FINAL : public nsIFTPEventSink
134 {
135 public:
136 FTPEventSinkProxy(nsIFTPEventSink* aTarget)
137 : mTarget(aTarget)
138 , mTargetThread(do_GetCurrentThread())
139 { }
140
141 NS_DECL_THREADSAFE_ISUPPORTS
142 NS_DECL_NSIFTPEVENTSINK
143
144 class OnFTPControlLogRunnable : public nsRunnable
145 {
146 public:
147 OnFTPControlLogRunnable(nsIFTPEventSink* aTarget,
148 bool aServer,
149 const char* aMessage)
150 : mTarget(aTarget)
151 , mServer(aServer)
152 , mMessage(aMessage)
153 { }
154
155 NS_DECL_NSIRUNNABLE
156
157 private:
158 nsCOMPtr<nsIFTPEventSink> mTarget;
159 bool mServer;
160 nsCString mMessage;
161 };
162
163 private:
164 nsCOMPtr<nsIFTPEventSink> mTarget;
165 nsCOMPtr<nsIThread> mTargetThread;
166 };
167
168 NS_IMPL_ISUPPORTS(FTPEventSinkProxy, nsIFTPEventSink)
169
170 NS_IMETHODIMP
171 FTPEventSinkProxy::OnFTPControlLog(bool aServer, const char* aMsg)
172 {
173 nsRefPtr<OnFTPControlLogRunnable> r =
174 new OnFTPControlLogRunnable(mTarget, aServer, aMsg);
175 return mTargetThread->Dispatch(r, NS_DISPATCH_NORMAL);
176 }
177
178 NS_IMETHODIMP
179 FTPEventSinkProxy::OnFTPControlLogRunnable::Run()
180 {
181 mTarget->OnFTPControlLog(mServer, mMessage.get());
182 return NS_OK;
183 }
184
185 } // anonymous namespace
186
187 void
188 nsFtpChannel::GetFTPEventSink(nsCOMPtr<nsIFTPEventSink> &aResult)
189 {
190 if (!mFTPEventSink) {
191 nsCOMPtr<nsIFTPEventSink> ftpSink;
192 GetCallback(ftpSink);
193 if (ftpSink) {
194 mFTPEventSink = new FTPEventSinkProxy(ftpSink);
195 }
196 }
197 aResult = mFTPEventSink;
198 }
199
200 void
201 nsFtpChannel::ForcePending(bool aForcePending)
202 {
203 // Set true here so IsPending will return true.
204 // Required for callback diversion from child back to parent. In such cases
205 // OnStopRequest can be called in the parent before callbacks are diverted
206 // back from the child to the listener in the parent.
207 mForcePending = aForcePending;
208 }
209
210 NS_IMETHODIMP
211 nsFtpChannel::IsPending(bool *result)
212 {
213 *result = Pending();
214 return NS_OK;
215 }
216
217 bool
218 nsFtpChannel::Pending() const
219 {
220 return nsBaseChannel::Pending() || mForcePending;
221 }

mercurial