mirror of
https://github.com/iterate-ch/cyberduck.git
synced 2026-05-26 19:10:49 +00:00
Overriding conditional FEAT caching to workaround issue #7427.
Former-commit-id: f803b628548398bb17bd8c47cb50bee0dc7ad421
This commit is contained in:
@@ -38,6 +38,7 @@ Changelog. Last modified: $Date$
|
||||
- [Bugfix] Changing permissions resets extended access rights flags (SFTP, FTP) (#3790)
|
||||
- [Bugfix] Remember browser column widths (#6034)
|
||||
- [Bugfix] Refresh list of thirdparty application bookmarks to import (#6141)
|
||||
- [Bugfix] PRET support not working anymore (#7427)
|
||||
|
||||
4.3.1 [http://trac.cyberduck.ch/milestone/4.3.1]
|
||||
- [Bugfix] Modification date shown as 01.01.1970 (Windows) (#7177)
|
||||
|
||||
@@ -44,8 +44,11 @@ import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @version $Id$
|
||||
@@ -55,6 +58,12 @@ public class FTPClient extends FTPSClient {
|
||||
|
||||
private SSLSocketFactory sslSocketFactory;
|
||||
|
||||
/**
|
||||
* Map of FEAT responses. If null, has not been initialised.
|
||||
*/
|
||||
private HashMap<String, Set<String>> features;
|
||||
|
||||
|
||||
public FTPClient(final SSLSocketFactory f, final SSLContext c) {
|
||||
super(false, c);
|
||||
this.sslSocketFactory = f;
|
||||
@@ -173,6 +182,131 @@ public class FTPClient extends FTPSClient {
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the server for a supported feature, and returns its values (if any).
|
||||
* Caches the parsed response to avoid resending the command repeatedly.
|
||||
*
|
||||
* @return if the feature is present, returns the feature values (empty array if none)
|
||||
* Returns {@code null} if the feature is not found or the command failed.
|
||||
* Check {@link #getReplyCode()} or {@link #getReplyString()} if so.
|
||||
* @throws IOException
|
||||
* @since 3.0
|
||||
*/
|
||||
public String[] featureValues(String feature) throws IOException {
|
||||
if(!initFeatureMap()) {
|
||||
return null;
|
||||
}
|
||||
Set<String> entries = features.get(feature.toUpperCase(Locale.ROOT));
|
||||
if(entries != null) {
|
||||
return entries.toArray(new String[entries.size()]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the server for a supported feature, and returns the its value (if any).
|
||||
* Caches the parsed response to avoid resending the command repeatedly.
|
||||
*
|
||||
* @return if the feature is present, returns the feature value or the empty string
|
||||
* if the feature exists but has no value.
|
||||
* Returns {@code null} if the feature is not found or the command failed.
|
||||
* Check {@link #getReplyCode()} or {@link #getReplyString()} if so.
|
||||
* @throws IOException
|
||||
* @since 3.0
|
||||
*/
|
||||
public String featureValue(String feature) throws IOException {
|
||||
String[] values = featureValues(feature);
|
||||
if(values != null) {
|
||||
return values[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the server for a supported feature.
|
||||
* Caches the parsed response to avoid resending the command repeatedly.
|
||||
*
|
||||
* @param feature the name of the feature; it is converted to upper case.
|
||||
* @return {@code true} if the feature is present, {@code false} if the feature is not present
|
||||
* or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link #getReplyString()}
|
||||
* if it is necessary to distinguish these cases.
|
||||
* @throws IOException
|
||||
* @since 3.0
|
||||
*/
|
||||
public boolean hasFeature(String feature) throws IOException {
|
||||
if(!initFeatureMap()) {
|
||||
return false;
|
||||
}
|
||||
return features.containsKey(feature.toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the server for a supported feature with particular value,
|
||||
* for example "AUTH SSL" or "AUTH TLS".
|
||||
* Caches the parsed response to avoid resending the command repeatedly.
|
||||
*
|
||||
* @param feature the name of the feature; it is converted to upper case.
|
||||
* @param value the value to find.
|
||||
* @return {@code true} if the feature is present, {@code false} if the feature is not present
|
||||
* or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link #getReplyString()}
|
||||
* if it is necessary to distinguish these cases.
|
||||
* @throws IOException
|
||||
* @since 3.0
|
||||
*/
|
||||
public boolean hasFeature(String feature, String value) throws IOException {
|
||||
if(!initFeatureMap()) {
|
||||
return false;
|
||||
}
|
||||
Set<String> entries = features.get(feature.toUpperCase(Locale.ROOT));
|
||||
if(entries != null) {
|
||||
return entries.contains(value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the feature map if not already created.
|
||||
*/
|
||||
private boolean initFeatureMap() throws IOException {
|
||||
if(features == null) {
|
||||
// Don't create map here, because next line may throw exception
|
||||
final int reply = feat();
|
||||
if(FTPReply.NOT_LOGGED_IN == reply) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// we init the map here, so we don't keep trying if we know the command will fail
|
||||
features = new HashMap<String, Set<String>>();
|
||||
}
|
||||
boolean success = FTPReply.isPositiveCompletion(reply);
|
||||
if(!success) {
|
||||
return false;
|
||||
}
|
||||
for(String l : getReplyStrings()) {
|
||||
if(l.startsWith(" ")) { // it's a FEAT entry
|
||||
String key;
|
||||
String value = "";
|
||||
int varsep = l.indexOf(' ', 1);
|
||||
if(varsep > 0) {
|
||||
key = l.substring(1, varsep);
|
||||
value = l.substring(varsep + 1);
|
||||
}
|
||||
else {
|
||||
key = l.substring(1);
|
||||
}
|
||||
key = key.toUpperCase(Locale.ROOT);
|
||||
Set<String> entries = features.get(key);
|
||||
if(entries == null) {
|
||||
entries = new HashSet<String>();
|
||||
features.put(key, entries);
|
||||
}
|
||||
entries.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retrieveFile(String remote, OutputStream local) throws IOException {
|
||||
this.pret(FTPCmd.RETR, remote);
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
<li>[Bugfix] Changing permissions resets extended access rights flags (SFTP, FTP) (<a href="http://trac.cyberduck.ch/ticket/3790">#3790</a>)</li>
|
||||
<li>[Bugfix] Remember browser column widths (<a href="http://trac.cyberduck.ch/ticket/6034">#6034</a>)</li>
|
||||
<li>[Bugfix] Refresh list of thirdparty application bookmarks to import (<a href="http://trac.cyberduck.ch/ticket/6141">#6141</a>)</li>
|
||||
<li>[Bugfix] PRET support not working anymore (<a href="http://trac.cyberduck.ch/ticket/7427">#7427</a>)</li>
|
||||
</ul>
|
||||
|
||||
<p>Release notes for previous versions can be found at <a
|
||||
|
||||
@@ -25,3 +25,4 @@
|
||||
- [Bugfix] Directory placeholder not displayed if same name as object (OpenStack) (#6988)
|
||||
- [Bugfix] Changing permissions resets extended access rights flags (SFTP, FTP) (#3790)
|
||||
- [Bugfix] Refresh list of thirdparty application bookmarks to import (#6141)
|
||||
- [Bugfix] PRET support not working anymore (#7427)
|
||||
|
||||
Reference in New Issue
Block a user