src/eric7/EricNetwork/EricFtp.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9324
7f7f3e47b238
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
7 Module implementing an extension to the Python FTP class to support FTP 7 Module implementing an extension to the Python FTP class to support FTP
8 proxies. 8 proxies.
9 """ 9 """
10 10
11 import enum 11 import enum
12 import ftplib # secok 12 import ftplib # secok
13 from socket import _GLOBAL_DEFAULT_TIMEOUT 13 from socket import _GLOBAL_DEFAULT_TIMEOUT
14 14
15 15
16 class EricFtpProxyError(ftplib.Error): 16 class EricFtpProxyError(ftplib.Error):
17 """ 17 """
18 Class to signal an error related to proxy configuration. 18 Class to signal an error related to proxy configuration.
19 19
20 The error message starts with a three digit error code followed by a 20 The error message starts with a three digit error code followed by a
21 space and the error string. Supported error codes are: 21 space and the error string. Supported error codes are:
22 <ul> 22 <ul>
23 <li>910: proxy error; the second number gives the category of the proxy 23 <li>910: proxy error; the second number gives the category of the proxy
24 error. The original response from the proxy is appended in the next 24 error. The original response from the proxy is appended in the next
35 <li>990: proxy usage is enabled but no proxy host given</li> 35 <li>990: proxy usage is enabled but no proxy host given</li>
36 <li>991: proxy usage is enabled but no proxy user given</li> 36 <li>991: proxy usage is enabled but no proxy user given</li>
37 <li>992: proxy usage is enabled but no proxy password given</li> 37 <li>992: proxy usage is enabled but no proxy password given</li>
38 </ul> 38 </ul>
39 """ 39 """
40
40 pass 41 pass
41 42
42 43
43 class EricFtpProxyType(enum.Enum): 44 class EricFtpProxyType(enum.Enum):
44 """ 45 """
45 Class defining the supported FTP proxy types. 46 Class defining the supported FTP proxy types.
46 """ 47 """
47 NO_PROXY = 0 # no proxy 48
48 NON_AUTHORIZING = 1 # non authorizing proxy 49 NO_PROXY = 0 # no proxy
49 USER_SERVER = 2 # proxy login first, than user@remote.host 50 NON_AUTHORIZING = 1 # non authorizing proxy
50 SITE = 3 # proxy login first, than use SITE command 51 USER_SERVER = 2 # proxy login first, than user@remote.host
51 OPEN = 4 # proxy login first, than use OPEN command 52 SITE = 3 # proxy login first, than use SITE command
52 USER_PROXYUSER_SERVER = 5 # one login for both 53 OPEN = 4 # proxy login first, than use OPEN command
54 USER_PROXYUSER_SERVER = 5 # one login for both
53 PROXYUSER_SERVER = 6 55 PROXYUSER_SERVER = 6
54 # proxy login with remote host given, than normal remote login 56 # proxy login with remote host given, than normal remote login
55 AUTH_RESP = 7 # authenticate to proxy with AUTH and RESP commands 57 AUTH_RESP = 7 # authenticate to proxy with AUTH and RESP commands
56 BLUECOAT = 8 # bluecoat proxy 58 BLUECOAT = 8 # bluecoat proxy
57 59
58 60
59 class EricFtp(ftplib.FTP): 61 class EricFtp(ftplib.FTP):
60 """ 62 """
61 Class implementing an extension to the Python FTP class to support FTP 63 Class implementing an extension to the Python FTP class to support FTP
62 proxies. 64 proxies.
63 """ 65 """
64 def __init__(self, host="", user="", password="", acct="", # secok 66
65 proxyType=EricFtpProxyType.NO_PROXY, proxyHost="", 67 def __init__(
66 proxyPort=ftplib.FTP_PORT, proxyUser="", proxyPassword="", 68 self,
67 proxyAccount="", timeout=_GLOBAL_DEFAULT_TIMEOUT): 69 host="",
70 user="",
71 password="",
72 acct="", # secok
73 proxyType=EricFtpProxyType.NO_PROXY,
74 proxyHost="",
75 proxyPort=ftplib.FTP_PORT,
76 proxyUser="",
77 proxyPassword="",
78 proxyAccount="",
79 timeout=_GLOBAL_DEFAULT_TIMEOUT,
80 ):
68 """ 81 """
69 Constructor 82 Constructor
70 83
71 @param host name of the FTP host 84 @param host name of the FTP host
72 @type str 85 @type str
73 @param user user name for login to FTP host 86 @param user user name for login to FTP host
74 @type str 87 @type str
75 @param password password for login to FTP host 88 @param password password for login to FTP host
90 @type str 103 @type str
91 @param timeout timeout in seconds for blocking operations 104 @param timeout timeout in seconds for blocking operations
92 @type int 105 @type int
93 """ 106 """
94 super().__init__() 107 super().__init__()
95 108
96 self.__timeout = timeout 109 self.__timeout = timeout
97 110
98 self.__proxyType = proxyType 111 self.__proxyType = proxyType
99 self.__proxyHost = proxyHost 112 self.__proxyHost = proxyHost
100 self.__proxyPort = proxyPort 113 self.__proxyPort = proxyPort
101 self.__proxyUser = proxyUser 114 self.__proxyUser = proxyUser
102 self.__proxyPassword = proxyPassword 115 self.__proxyPassword = proxyPassword
103 self.__proxyAccount = proxyAccount 116 self.__proxyAccount = proxyAccount
104 117
105 self.__host = host 118 self.__host = host
106 self.__port = ftplib.FTP_PORT 119 self.__port = ftplib.FTP_PORT
107 self.__user = user 120 self.__user = user
108 self.__password = password 121 self.__password = password
109 self.__acct = acct 122 self.__acct = acct
110 123
111 if host: 124 if host:
112 self.connect(host) 125 self.connect(host)
113 if user: 126 if user:
114 self.login(user, password, acct) 127 self.login(user, password, acct)
115 128
116 def setProxy(self, proxyType=EricFtpProxyType.NO_PROXY, proxyHost="", 129 def setProxy(
117 proxyPort=ftplib.FTP_PORT, proxyUser="", proxyPassword="", 130 self,
118 proxyAccount=""): 131 proxyType=EricFtpProxyType.NO_PROXY,
132 proxyHost="",
133 proxyPort=ftplib.FTP_PORT,
134 proxyUser="",
135 proxyPassword="",
136 proxyAccount="",
137 ):
119 """ 138 """
120 Public method to set the proxy configuration. 139 Public method to set the proxy configuration.
121 140
122 @param proxyType type of the FTP proxy 141 @param proxyType type of the FTP proxy
123 @type EricFtpProxyType 142 @type EricFtpProxyType
124 @param proxyHost name of the FTP proxy 143 @param proxyHost name of the FTP proxy
125 @type str 144 @type str
126 @param proxyPort port of the FTP proxy 145 @param proxyPort port of the FTP proxy
136 self.__proxyHost = proxyHost 155 self.__proxyHost = proxyHost
137 self.__proxyPort = proxyPort 156 self.__proxyPort = proxyPort
138 self.__proxyUser = proxyUser 157 self.__proxyUser = proxyUser
139 self.__proxyPassword = proxyPassword 158 self.__proxyPassword = proxyPassword
140 self.__proxyAccount = proxyAccount 159 self.__proxyAccount = proxyAccount
141 160
142 def setProxyAuthentication(self, proxyUser="", proxyPassword="", 161 def setProxyAuthentication(self, proxyUser="", proxyPassword="", proxyAccount=""):
143 proxyAccount=""):
144 """ 162 """
145 Public method to set the proxy authentication info. 163 Public method to set the proxy authentication info.
146 164
147 @param proxyUser user name for login to the proxy 165 @param proxyUser user name for login to the proxy
148 @type str 166 @type str
149 @param proxyPassword password for login to the proxy 167 @param proxyPassword password for login to the proxy
150 @type str 168 @type str
151 @param proxyAccount accounting info for the proxy 169 @param proxyAccount accounting info for the proxy
152 @type str 170 @type str
153 """ 171 """
154 self.__proxyUser = proxyUser 172 self.__proxyUser = proxyUser
155 self.__proxyPassword = proxyPassword 173 self.__proxyPassword = proxyPassword
156 self.__proxyAccount = proxyAccount 174 self.__proxyAccount = proxyAccount
157 175
158 def connect(self, host="", port=0, timeout=-999): 176 def connect(self, host="", port=0, timeout=-999):
159 """ 177 """
160 Public method to connect to the given FTP server. 178 Public method to connect to the given FTP server.
161 179
162 This extended method connects to the proxy instead of the given host, 180 This extended method connects to the proxy instead of the given host,
163 if a proxy is to be used. It throws an exception, if the proxy data 181 if a proxy is to be used. It throws an exception, if the proxy data
164 is incomplete. 182 is incomplete.
165 183
166 @param host name of the FTP host 184 @param host name of the FTP host
167 @type str 185 @type str
168 @param port port of the FTP host 186 @param port port of the FTP host
169 @type int 187 @type int
170 @param timeout timeout in seconds for blocking operations 188 @param timeout timeout in seconds for blocking operations
177 self.__host = host 195 self.__host = host
178 if port: 196 if port:
179 self.__port = port 197 self.__port = port
180 if timeout != -999: 198 if timeout != -999:
181 self.__timeout = timeout 199 self.__timeout = timeout
182 200
183 if self.__proxyType != EricFtpProxyType.NO_PROXY: 201 if self.__proxyType != EricFtpProxyType.NO_PROXY:
184 if not self.__proxyHost: 202 if not self.__proxyHost:
185 raise EricFtpProxyError( 203 raise EricFtpProxyError(
186 "990 Proxy usage requested, but no proxy host given.") 204 "990 Proxy usage requested, but no proxy host given."
187 205 )
188 return super().connect( 206
189 self.__proxyHost, self.__proxyPort, self.__timeout) 207 return super().connect(self.__proxyHost, self.__proxyPort, self.__timeout)
190 else: 208 else:
191 return super().connect( 209 return super().connect(self.__host, self.__port, self.__timeout)
192 self.__host, self.__port, self.__timeout) 210
193 211 def login(self, user="", password="", acct=""): # secok
194 def login(self, user="", password="", acct=""): # secok
195 """ 212 """
196 Public method to login to the FTP server. 213 Public method to login to the FTP server.
197 214
198 This extended method respects the FTP proxy configuration. There are 215 This extended method respects the FTP proxy configuration. There are
199 many different FTP proxy products available. But unfortunately there 216 many different FTP proxy products available. But unfortunately there
200 is no standard for how o traverse a FTP proxy. The lis below shows 217 is no standard for how o traverse a FTP proxy. The lis below shows
201 the sequence of commands used. 218 the sequence of commands used.
202 219
203 <table> 220 <table>
204 <tr><td>user</td><td>Username for remote host</td></tr> 221 <tr><td>user</td><td>Username for remote host</td></tr>
205 <tr><td>pass</td><td>Password for remote host</td></tr> 222 <tr><td>pass</td><td>Password for remote host</td></tr>
206 <tr><td>pruser</td><td>Username for FTP proxy</td></tr> 223 <tr><td>pruser</td><td>Username for FTP proxy</td></tr>
207 <tr><td>prpass</td><td>Password for FTP proxy</td></tr> 224 <tr><td>prpass</td><td>Password for FTP proxy</td></tr>
208 <tr><td>remote.host</td><td>Hostname of the remote FTP server</td> 225 <tr><td>remote.host</td><td>Hostname of the remote FTP server</td>
209 </tr> 226 </tr>
210 </table> 227 </table>
211 228
212 <dl> 229 <dl>
213 <dt>EricFtpProxyType.NO_PROXY:</dt> 230 <dt>EricFtpProxyType.NO_PROXY:</dt>
214 <dd> 231 <dd>
215 USER user<br/> 232 USER user<br/>
216 PASS pass 233 PASS pass
267 USER user@remote.host pruser<br/> 284 USER user@remote.host pruser<br/>
268 PASS pass<br/> 285 PASS pass<br/>
269 ACCT prpass 286 ACCT prpass
270 </dd> 287 </dd>
271 </dl> 288 </dl>
272 289
273 @param user username for the remote host 290 @param user username for the remote host
274 @type str 291 @type str
275 @param password password for the remote host 292 @param password password for the remote host
276 @type str 293 @type str
277 @param acct accounting information for the remote host 294 @param acct accounting information for the remote host
283 """ 300 """
284 if not user: 301 if not user:
285 user = "anonymous" 302 user = "anonymous"
286 if not password: 303 if not password:
287 # make sure it is a string 304 # make sure it is a string
288 password = "" # secok 305 password = "" # secok
289 if not acct: 306 if not acct:
290 # make sure it is a string 307 # make sure it is a string
291 acct = "" 308 acct = ""
292 if user == "anonymous" and password in {'', '-'}: 309 if user == "anonymous" and password in {"", "-"}:
293 password += "anonymous@" 310 password += "anonymous@"
294 311
295 if self.__proxyType != EricFtpProxyType.NO_PROXY: 312 if self.__proxyType != EricFtpProxyType.NO_PROXY:
296 if self.__proxyType != EricFtpProxyType.NON_AUTHORIZING: 313 if self.__proxyType != EricFtpProxyType.NON_AUTHORIZING:
297 # check, if a valid proxy configuration is known 314 # check, if a valid proxy configuration is known
298 if not self.__proxyUser: 315 if not self.__proxyUser:
299 raise EricFtpProxyError( 316 raise EricFtpProxyError(
300 "991 Proxy usage requested, but no proxy user given") 317 "991 Proxy usage requested, but no proxy user given"
318 )
301 if not self.__proxyPassword: 319 if not self.__proxyPassword:
302 raise EricFtpProxyError( 320 raise EricFtpProxyError(
303 "992 Proxy usage requested, but no proxy password" 321 "992 Proxy usage requested, but no proxy password" " given"
304 " given") 322 )
305 323
306 if self.__proxyType in [EricFtpProxyType.NON_AUTHORIZING, 324 if self.__proxyType in [
307 EricFtpProxyType.AUTH_RESP, 325 EricFtpProxyType.NON_AUTHORIZING,
308 EricFtpProxyType.BLUECOAT]: 326 EricFtpProxyType.AUTH_RESP,
327 EricFtpProxyType.BLUECOAT,
328 ]:
309 user += "@" + self.__host 329 user += "@" + self.__host
310 if self.__proxyType == EricFtpProxyType.BLUECOAT: 330 if self.__proxyType == EricFtpProxyType.BLUECOAT:
311 user += " " + self.__proxyUser 331 user += " " + self.__proxyUser
312 acct = self.__proxyPassword 332 acct = self.__proxyPassword
313 elif self.__proxyType == EricFtpProxyType.USER_PROXYUSER_SERVER: 333 elif self.__proxyType == EricFtpProxyType.USER_PROXYUSER_SERVER:
314 user = "{0}@{1}@{2}".format( 334 user = "{0}@{1}@{2}".format(user, self.__proxyUser, self.__host)
315 user, self.__proxyUser, self.__host)
316 password = "{0}@{1}".format(password, self.__proxyPassword) 335 password = "{0}@{1}".format(password, self.__proxyPassword)
317 else: 336 else:
318 pruser = self.__proxyUser 337 pruser = self.__proxyUser
319 if self.__proxyType == EricFtpProxyType.USER_SERVER: 338 if self.__proxyType == EricFtpProxyType.USER_SERVER:
320 user += "@" + self.__host 339 user += "@" + self.__host
321 elif self.__proxyType == EricFtpProxyType.PROXYUSER_SERVER: 340 elif self.__proxyType == EricFtpProxyType.PROXYUSER_SERVER:
322 pruser += "@" + self.__host 341 pruser += "@" + self.__host
323 342
324 # authenticate to the proxy first 343 # authenticate to the proxy first
325 presp = self.sendcmd("USER " + pruser) 344 presp = self.sendcmd("USER " + pruser)
326 if presp[0] == "3": 345 if presp[0] == "3":
327 presp = self.sendcmd("PASS " + self.__proxyPassword) 346 presp = self.sendcmd("PASS " + self.__proxyPassword)
328 if presp[0] == "3" and self.__proxyAccount: 347 if presp[0] == "3" and self.__proxyAccount:
329 presp = self.sendcmd("ACCT " + self.__proxyAccount) 348 presp = self.sendcmd("ACCT " + self.__proxyAccount)
330 if presp[0] != "2": 349 if presp[0] != "2":
331 raise EricFtpProxyError( 350 raise EricFtpProxyError(
332 "9{0}0 Error authorizing at proxy\n{1}".format( 351 "9{0}0 Error authorizing at proxy\n{1}".format(presp[0], presp)
333 presp[0], presp)) 352 )
334 353
335 if self.__proxyType == EricFtpProxyType.SITE: 354 if self.__proxyType == EricFtpProxyType.SITE:
336 # send SITE command 355 # send SITE command
337 presp = self.sendcmd("SITE " + self.__host) 356 presp = self.sendcmd("SITE " + self.__host)
338 if presp[0] != "2": 357 if presp[0] != "2":
339 raise EricFtpProxyError( 358 raise EricFtpProxyError(
340 "9{0}0 Error sending SITE command\n{1}".format( 359 "9{0}0 Error sending SITE command\n{1}".format(
341 presp[0], presp)) 360 presp[0], presp
361 )
362 )
342 elif self.__proxyType == EricFtpProxyType.OPEN: 363 elif self.__proxyType == EricFtpProxyType.OPEN:
343 # send OPEN command 364 # send OPEN command
344 presp = self.sendcmd("OPEN " + self.__host) 365 presp = self.sendcmd("OPEN " + self.__host)
345 if presp[0] != "2": 366 if presp[0] != "2":
346 raise EricFtpProxyError( 367 raise EricFtpProxyError(
347 "9{0}0 Error sending OPEN command\n{1}".format( 368 "9{0}0 Error sending OPEN command\n{1}".format(
348 presp[0], presp)) 369 presp[0], presp
349 370 )
371 )
372
350 # authenticate to the remote host or combined to proxy and remote host 373 # authenticate to the remote host or combined to proxy and remote host
351 resp = self.sendcmd("USER " + user) 374 resp = self.sendcmd("USER " + user)
352 if resp[0] == "3": 375 if resp[0] == "3":
353 resp = self.sendcmd("PASS " + password) 376 resp = self.sendcmd("PASS " + password)
354 if resp[0] == "3": 377 if resp[0] == "3":
355 resp = self.sendcmd("ACCT " + acct) 378 resp = self.sendcmd("ACCT " + acct)
356 if resp[0] != "2": 379 if resp[0] != "2":
357 raise ftplib.error_reply(resp) # secok 380 raise ftplib.error_reply(resp) # secok
358 381
359 if self.__proxyType == EricFtpProxyType.AUTH_RESP: 382 if self.__proxyType == EricFtpProxyType.AUTH_RESP:
360 # authorize to the FTP proxy 383 # authorize to the FTP proxy
361 presp = self.sendcmd("AUTH " + self.__proxyUser) 384 presp = self.sendcmd("AUTH " + self.__proxyUser)
362 if presp[0] == "3": 385 if presp[0] == "3":
363 presp = self.sendcmd("RESP " + self.__proxyPassword) 386 presp = self.sendcmd("RESP " + self.__proxyPassword)
364 if presp[0] != "2": 387 if presp[0] != "2":
365 raise EricFtpProxyError( 388 raise EricFtpProxyError(
366 "9{0}0 Error authorizing at proxy\n{1}".format( 389 "9{0}0 Error authorizing at proxy\n{1}".format(presp[0], presp)
367 presp[0], presp)) 390 )
368 391
369 return resp 392 return resp

eric ide

mercurial