|
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 } |