1//
2// FTPSStreamFactory.cpp
3//
4// Library: Net
5// Package: FTP
6// Module: FTPSStreamFactory
7//
8// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Net/FTPSStreamFactory.h"
16#include "Poco/Net/FTPSClientSession.h"
17#include "Poco/Net/NetException.h"
18#include "Poco/URI.h"
19#include "Poco/URIStreamOpener.h"
20#include "Poco/UnbufferedStreamBuf.h"
21#include "Poco/Path.h"
22
23
24using Poco::URIStreamFactory;
25using Poco::URI;
26using Poco::URIStreamOpener;
27using Poco::UnbufferedStreamBuf;
28using Poco::Path;
29
30
31namespace Poco {
32namespace Net {
33
34
35class FTPStreamBuf: public UnbufferedStreamBuf
36{
37public:
38 FTPStreamBuf(std::istream& istr):
39 _istr(istr)
40 {
41 // make sure exceptions from underlying string propagate
42 _istr.exceptions(std::ios::badbit);
43 }
44
45 ~FTPStreamBuf()
46 {
47 }
48
49private:
50 int readFromDevice()
51 {
52 return _istr.get();
53 }
54
55 std::istream& _istr;
56};
57
58
59class FTPSIOS: public virtual std::ios
60{
61public:
62 FTPSIOS(std::istream& istr):
63 _buf(istr)
64 {
65 poco_ios_init(&_buf);
66 }
67
68 ~FTPSIOS()
69 {
70 }
71
72 FTPStreamBuf* rdbuf()
73 {
74 return &_buf;
75 }
76
77protected:
78 FTPStreamBuf _buf;
79};
80
81
82class FTPSStream: public FTPSIOS, public std::istream
83{
84public:
85 FTPSStream(std::istream& istr, FTPSClientSession* pSession):
86 FTPSIOS(istr),
87 std::istream(&_buf),
88 _pSession(pSession)
89 {
90 }
91
92 ~FTPSStream()
93 {
94 delete _pSession;
95 }
96
97private:
98 FTPSClientSession* _pSession;
99};
100
101
102std::string FTPSStreamFactory::_anonymousPassword("poco@localhost");
103FTPPasswordProvider* FTPSStreamFactory::_pPasswordProvider(0);
104
105FTPSStreamFactory::FTPSStreamFactory()
106{
107}
108
109
110FTPSStreamFactory::~FTPSStreamFactory()
111{
112}
113
114
115std::istream* FTPSStreamFactory::open(const URI& uri)
116{
117 poco_assert (uri.getScheme() == "ftps");
118
119 FTPSClientSession* pSession = new FTPSClientSession(uri.getHost(), uri.getPort());
120 try
121 {
122 std::string username;
123 std::string password;
124 getUserInfo(uri, username, password);
125
126 std::string path;
127 char type;
128 getPathAndType(uri, path, type);
129
130 pSession->login(username, password);
131 if (type == 'a')
132 pSession->setFileType(FTPClientSession::TYPE_TEXT);
133
134 Path p(path, Path::PATH_UNIX);
135 p.makeFile();
136 for (int i = 0; i < p.depth(); ++i)
137 pSession->setWorkingDirectory(p[i]);
138 std::string file(p.getFileName());
139 std::istream& istr = (type == 'd' ? pSession->beginList(file) : pSession->beginDownload(file));
140 return new FTPSStream(istr, pSession);
141 }
142 catch (...)
143 {
144 delete pSession;
145 throw;
146 }
147}
148
149
150void FTPSStreamFactory::setAnonymousPassword(const std::string& password)
151{
152 _anonymousPassword = password;
153}
154
155
156const std::string& FTPSStreamFactory::getAnonymousPassword()
157{
158 return _anonymousPassword;
159}
160
161
162void FTPSStreamFactory::setPasswordProvider(FTPPasswordProvider* pProvider)
163{
164 _pPasswordProvider = pProvider;
165}
166
167
168FTPPasswordProvider* FTPSStreamFactory::getPasswordProvider()
169{
170 return _pPasswordProvider;
171}
172
173
174void FTPSStreamFactory::splitUserInfo(const std::string& userInfo, std::string& username, std::string& password)
175{
176 std::string::size_type pos = userInfo.find(':');
177 if (pos != std::string::npos)
178 {
179 username.assign(userInfo, 0, pos++);
180 password.assign(userInfo, pos, userInfo.size() - pos);
181 }
182 else username = userInfo;
183}
184
185
186void FTPSStreamFactory::getUserInfo(const URI& uri, std::string& username, std::string& password)
187{
188 splitUserInfo(uri.getUserInfo(), username, password);
189 if (username.empty())
190 {
191 username = "anonymous";
192 password = _anonymousPassword;
193 }
194 else if (password.empty())
195 {
196 if (_pPasswordProvider)
197 password = _pPasswordProvider->password(username, uri.getHost());
198 else
199 throw FTPException(std::string("Password required for ") + username + "@" + uri.getHost());
200 }
201}
202
203
204void FTPSStreamFactory::getPathAndType(const Poco::URI& uri, std::string& path, char& type)
205{
206 path = uri.getPath();
207 type = 'i';
208 std::string::size_type pos = path.rfind(';');
209 if (pos != std::string::npos)
210 {
211 if (path.length() == pos + 7 && path.compare(pos + 1, 5, "type=") == 0)
212 {
213 type = path[pos + 6];
214 path.resize(pos);
215 }
216 }
217}
218
219
220void FTPSStreamFactory::registerFactory()
221{
222 URIStreamOpener::defaultOpener().registerStreamFactory("ftps", new FTPSStreamFactory);
223}
224
225
226void FTPSStreamFactory::unregisterFactory()
227{
228 URIStreamOpener::defaultOpener().unregisterStreamFactory("ftps");
229}
230
231
232} } // namespace Poco::Net