You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/07/07 11:12:34 UTC
mina-sshd git commit: [SSHD-531] Re-use incoming Buffer to send SFTP
response
Repository: mina-sshd
Updated Branches:
refs/heads/master f60fb919c -> 1806ac970
[SSHD-531] Re-use incoming Buffer to send SFTP response
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/1806ac97
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/1806ac97
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/1806ac97
Branch: refs/heads/master
Commit: 1806ac9701f09d010a952c5a8bd72db02d0f4b1b
Parents: f60fb91
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Tue Jul 7 12:12:22 2015 +0300
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Tue Jul 7 12:12:22 2015 +0300
----------------------------------------------------------------------
.../subsystem/sftp/AbstractSftpClient.java | 6 +-
.../sshd/common/util/Int2IntFunction.java | 91 ++++++++
.../apache/sshd/common/util/buffer/Buffer.java | 15 +-
.../sshd/common/util/buffer/BufferUtils.java | 22 ++
.../common/util/buffer/ByteArrayBuffer.java | 17 +-
.../server/subsystem/sftp/SftpSubsystem.java | 213 +++++++++----------
.../sshd/client/subsystem/sftp/SftpTest.java | 19 +-
7 files changed, 254 insertions(+), 129 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1806ac97/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
index 2461fbd..8d9705a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
@@ -498,8 +498,8 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
buffer.putLong(attributes.size);
}
if ((flags & SSH_FILEXFER_ATTR_OWNERGROUP) != 0) {
- buffer.putString(attributes.owner != null ? attributes.owner : "OWNER@", StandardCharsets.UTF_8);
- buffer.putString(attributes.group != null ? attributes.group : "GROUP@", StandardCharsets.UTF_8);
+ buffer.putString(attributes.owner != null ? attributes.owner : "OWNER@");
+ buffer.putString(attributes.group != null ? attributes.group : "GROUP@");
}
if ((flags & SSH_FILEXFER_ATTR_PERMISSIONS) != 0) {
buffer.putInt(attributes.perms);
@@ -739,7 +739,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
}
Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */);
- buffer.putString(path, StandardCharsets.UTF_8);
+ buffer.putString(path);
buffer.putInt(0);
int version = getVersion();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1806ac97/sshd-core/src/main/java/org/apache/sshd/common/util/Int2IntFunction.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/Int2IntFunction.java b/sshd-core/src/main/java/org/apache/sshd/common/util/Int2IntFunction.java
new file mode 100644
index 0000000..06a6070
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/Int2IntFunction.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sshd.common.util;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface Int2IntFunction {
+ /**
+ * @param value Argument
+ * @return Function result
+ */
+ int apply(int value);
+
+ /**
+ * An {@link Int2IntFunction} that returns same value as input
+ */
+ Int2IntFunction IDENTITY = new Int2IntFunction() {
+ @Override
+ public int apply(int value) {
+ return value;
+ }
+ };
+
+ public static final class Utils {
+ private Utils() {
+ throw new UnsupportedOperationException("No instance");
+ }
+
+ public static Int2IntFunction sub(int delta) {
+ return add(0 - delta);
+ }
+
+ public static Int2IntFunction add(final int delta) {
+ if (delta == 0) {
+ return IDENTITY;
+ } else {
+ return new Int2IntFunction() {
+ @Override
+ public int apply(int value) {
+ return value + delta;
+ }
+ };
+ }
+ }
+
+ public static Int2IntFunction mul(final int factor) {
+ if (factor == 1) {
+ return IDENTITY;
+ } else {
+ return new Int2IntFunction() {
+ @Override
+ public int apply(int value) {
+ return value * factor;
+ }
+ };
+ }
+ }
+
+ public static Int2IntFunction div(final int factor) {
+ if (factor == 1) {
+ return IDENTITY;
+ } else {
+ ValidateUtils.checkTrue(factor != 0, "Zero division factor", GenericUtils.EMPTY_OBJECT_ARRAY);
+ return new Int2IntFunction() {
+ @Override
+ public int apply(int value) {
+ return value / factor;
+ }
+ };
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1806ac97/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
index bada2de..b68a4a3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
@@ -55,6 +55,7 @@ import org.apache.sshd.common.cipher.ECCurves;
import org.apache.sshd.common.config.keys.ECDSAPublicKeyEntryDecoder;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Int2IntFunction;
import org.apache.sshd.common.util.Readable;
import org.apache.sshd.common.util.SecurityUtils;
@@ -636,7 +637,19 @@ public abstract class Buffer implements Readable {
}
}
- protected abstract void ensureCapacity(int capacity);
+ protected void ensureCapacity(int capacity) {
+ ensureCapacity(capacity, BufferUtils.DEFAULT_BUFFER_GROWTH_FACTOR);
+ }
+
+ /**
+ * @param capacity The requires capacity
+ * @param growthFactor An {@link Int2IntFunction} that is invoked
+ * if the current capacity is insufficient. The argument is the minimum
+ * required new data length, the function result should be the
+ * effective new data length to be allocated - if less than minimum
+ * then an exception is thrown
+ */
+ public abstract void ensureCapacity(int capacity, Int2IntFunction growthFactor);
protected abstract int size();
@Override
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1806ac97/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java
index 4991ebb..4a0ca1f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java
@@ -24,6 +24,7 @@ import java.io.OutputStream;
import java.io.StreamCorruptedException;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Int2IntFunction;
import org.apache.sshd.common.util.io.IoUtils;
/**
@@ -277,6 +278,14 @@ public class BufferUtils {
return true;
}
+ public static final Int2IntFunction DEFAULT_BUFFER_GROWTH_FACTOR =
+ new Int2IntFunction() {
+ @Override
+ public int apply(int value) {
+ return getNextPowerOf2(value);
+ }
+ };
+
public static final int getNextPowerOf2(int i) {
int j = 1;
while (j < i) {
@@ -324,4 +333,17 @@ public class BufferUtils {
buffer.putInt(dataLength);
buffer.wpos(curPos);
}
+
+ /**
+ * Invokes {@link Buffer#clear()}
+ * @param buffer A {@link Buffer} instance - ignored if {@code null}
+ * @return The same as the input instance
+ */
+ public static <B extends Buffer> B clear(B buffer) {
+ if (buffer != null) {
+ buffer.clear();
+ }
+
+ return buffer;
+ }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1806ac97/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
index da05aef..e41447c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/ByteArrayBuffer.java
@@ -19,8 +19,10 @@
package org.apache.sshd.common.util.buffer;
+import java.nio.BufferUnderflowException;
import java.nio.charset.Charset;
+import org.apache.sshd.common.util.Int2IntFunction;
import org.apache.sshd.common.util.Readable;
/**
@@ -162,10 +164,17 @@ public final class ByteArrayBuffer extends Buffer {
}
@Override
- protected void ensureCapacity(int capacity) {
- if (data.length - wpos < capacity) {
- int cw = wpos + capacity;
- byte[] tmp = new byte[BufferUtils.getNextPowerOf2(cw)];
+ public void ensureCapacity(int capacity, Int2IntFunction growthFactor) {
+ int maxSize = size();
+ int curPos = wpos();
+ int remaining = maxSize - curPos;
+ if (remaining < capacity) {
+ int minimum = curPos + capacity;
+ int actual = growthFactor.apply(minimum);
+ if (actual < minimum) {
+ throw new IllegalStateException("ensureCapacity(" + capacity + ") actual (" + actual + ") below min. (" + minimum + ")");
+ }
+ byte[] tmp = new byte[actual];
System.arraycopy(data, 0, tmp, 0, data.length);
data = tmp;
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1806ac97/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
index eaf5f43..d2a8ce4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
@@ -31,7 +31,6 @@ import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
-import java.nio.charset.StandardCharsets;
import java.nio.file.AccessDeniedException;
import java.nio.file.CopyOption;
import java.nio.file.DirectoryNotEmptyException;
@@ -88,6 +87,7 @@ import org.apache.sshd.common.file.FileSystemAware;
import org.apache.sshd.common.random.Random;
import org.apache.sshd.common.subsystem.sftp.SftpConstants;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Int2IntFunction;
import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.common.util.SelectorUtils;
import org.apache.sshd.common.util.ValidateUtils;
@@ -264,6 +264,8 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
public void markDone() {
this.done = true;
+ // allow the garbage collector to do the job
+ this.fileList = null;
}
public boolean isSendDot() {
@@ -297,13 +299,9 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
throw new UnsupportedOperationException("Not allowed to remove " + toString());
}
- public void clearFileList() {
- // allow the garbage collector to do the job
- fileList = null;
- }
-
@Override
public void close() throws IOException {
+ markDone(); // just making sure
ds.close();
}
}
@@ -660,7 +658,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
break;
default:
log.warn("Unknown command type received: {}", Integer.valueOf(type));
- sendStatus(id, SSH_FX_OP_UNSUPPORTED, "Command " + type + " is unsupported or not implemented");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OP_UNSUPPORTED, "Command " + type + " is unsupported or not implemented");
}
if (type != SSH_FXP_INIT) {
@@ -695,7 +693,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
break;
default:
log.info("Received unsupported SSH_FXP_EXTENDED({})", extension);
- sendStatus(id, SSH_FX_OP_UNSUPPORTED, "Command SSH_FXP_EXTENDED(" + extension + ") is unsupported or not implemented");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OP_UNSUPPORTED, "Command SSH_FXP_EXTENDED(" + extension + ") is unsupported or not implemented");
break;
}
}
@@ -707,11 +705,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
// TODO : implement text-seek - see https://tools.ietf.org/html/draft-ietf-secsh-filexfer-03#section-6.3
doTextSeek(id, handle, line);
} catch(IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, SSH_FX_OK, "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
}
protected void doTextSeek(int id, String handle, long line) throws IOException {
@@ -728,20 +726,21 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
String target = buffer.getString();
long startOffset = buffer.getLong();
long length = buffer.getLong();
- byte[] quickCheckHash = buffer.getBytes();
+ byte[] quickCheckHash = buffer.getBytes(), hashValue;
try {
- byte[] hashValue = doMD5Hash(id, targetType, target, startOffset, length, quickCheckHash);
- buffer.clear();
-
- buffer.putByte((byte) SSH_FXP_EXTENDED_REPLY);
- buffer.putInt(id);
- buffer.putString(targetType);
- buffer.putBytes(hashValue);
- send(buffer);
+ hashValue = doMD5Hash(id, targetType, target, startOffset, length, quickCheckHash);
} catch(Exception e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
+ return;
}
+
+ buffer.clear();
+ buffer.putByte((byte) SSH_FXP_EXTENDED_REPLY);
+ buffer.putInt(id);
+ buffer.putString(targetType);
+ buffer.putBytes(hashValue);
+ send(buffer);
}
protected byte[] doMD5Hash(int id, String targetType, String target, long startOffset, long length, byte[] quickCheckHash) throws Exception {
@@ -869,12 +868,12 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
* channel.
*/
if (requestsCount > 0L) {
- sendStatus(id, SSH_FX_FAILURE, "Version selection not the 1st request for proposal = " + proposed);
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_FAILURE, "Version selection not the 1st request for proposal = " + proposed);
session.close(true);
return;
}
- Boolean result = validateProposedVersion(id, proposed);
+ Boolean result = validateProposedVersion(buffer, id, proposed);
/*
* "MUST then close the channel without processing any further requests"
*/
@@ -883,14 +882,15 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
return;
} if (result.booleanValue()) {
version = Integer.parseInt(proposed);
- sendStatus(id, SSH_FX_OK, "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
} else {
- sendStatus(id, SSH_FX_FAILURE, "Unsupported version " + proposed);
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_FAILURE, "Unsupported version " + proposed);
session.close(true);
}
}
/**
+ * @param buffer The {@link Buffer} holding the request
* @param id The request id
* @param proposed The proposed value
* @return A {@link Boolean} indicating whether to accept/reject the proposal.
@@ -898,7 +898,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
* appropriate response is generated
* @throws IOException If failed send an independent rejection response
*/
- protected Boolean validateProposedVersion(int id, String proposed) throws IOException {
+ protected Boolean validateProposedVersion(Buffer buffer, int id, String proposed) throws IOException {
if (log.isDebugEnabled()) {
log.debug("Received SSH_FXP_EXTENDED(version-select) (version={})", proposed);
}
@@ -913,7 +913,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
}
int value = digit - '0';
- String all = checkVersionCompatibility(id, value, SSH_FX_FAILURE);
+ String all = checkVersionCompatibility(buffer, id, value, SSH_FX_FAILURE);
if (GenericUtils.isEmpty(all)) { // validation failed
return null;
} else {
@@ -925,6 +925,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
* Checks if a proposed version is within supported range. <B>Note:</B>
* if the user forced a specific value via the {@link #SFTP_VERSION}
* property, then it is used to validate the proposed value
+ * @param buffer The {@link Buffer} containing the request
* @param id The SSH message ID to be used to send the failure message
* if required
* @param proposed The proposed version value
@@ -934,7 +935,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
* appropriate status message was sent
* @throws IOException If failed to send the failure status message
*/
- protected String checkVersionCompatibility(int id, int proposed, int failureOpcode) throws IOException {
+ protected String checkVersionCompatibility(Buffer buffer, int id, int proposed, int failureOpcode) throws IOException {
int low = LOWER_SFTP_IMPL;
int hig = HIGHER_SFTP_IMPL;
String available = ALL_SFTP_IMPL;
@@ -955,7 +956,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
}
if ((proposed < low) || (proposed > hig)) {
- sendStatus(id, failureOpcode, "Proposed version (" + proposed + ") not in supported range: " + available);
+ sendStatus(BufferUtils.clear(buffer), id, failureOpcode, "Proposed version (" + proposed + ") not in supported range: " + available);
return null;
}
@@ -971,11 +972,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
doBlock(id, handle, offset, length, mask);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, SSH_FX_OK, "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
}
protected void doBlock(int id, String handle, long offset, long length, int mask) throws IOException {
@@ -997,11 +998,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
found = doUnblock(id, handle, offset, length);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, found ? SSH_FX_OK : SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK, "");
+ sendStatus(BufferUtils.clear(buffer), id, found ? SSH_FX_OK : SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK, "");
}
protected boolean doUnblock(int id, String handle, long offset, long length) throws IOException {
@@ -1023,11 +1024,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
doLink(id, targetPath, linkPath, symLink);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, SSH_FX_OK, "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
}
protected void doLink(int id, String targetPath, String linkPath, boolean symLink) throws IOException {
@@ -1051,11 +1052,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
doSymLink(id, targetPath, linkPath);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, SSH_FX_OK, "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
}
protected void doSymLink(int id, String targetPath, String linkPath) throws IOException {
@@ -1070,11 +1071,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
l = doReadLink(id, path);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendLink(id, l);
+ sendLink(BufferUtils.clear(buffer), id, l);
}
protected String doReadLink(int id, String path) throws IOException {
@@ -1095,11 +1096,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
doRename(id, oldPath, newPath, flags);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, SSH_FX_OK, "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
}
protected void doRename(int id, String oldPath, String newPath, int flags) throws IOException {
@@ -1137,11 +1138,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
doCopyFile(id, srcFile, dstFile, overwriteDestination);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, SSH_FX_OK, "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
}
protected void doCopyFile(int id, String srcFile, String dstFile, boolean overwriteDestination) throws IOException {
@@ -1173,11 +1174,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
attrs = doStat(id, path, flags);
} catch(IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendAttrs(id, attrs);
+ sendAttrs(BufferUtils.clear(buffer), id, attrs);
}
protected Map<String,Object> doStat(int id, String path, int flags) throws IOException {
@@ -1228,11 +1229,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
}
}
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendPath(id, p, attrs);
+ sendPath(BufferUtils.clear(buffer), id, p, attrs);
}
protected Path doRealPathV345(int id, String path, Collection<String> extraPaths) throws IOException {
@@ -1285,11 +1286,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
doRemoveDirectory(id, path, IoUtils.getLinkOptions(false));
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, SSH_FX_OK, "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
}
protected void doRemoveDirectory(int id, String path, LinkOption ... options) throws IOException {
@@ -1308,11 +1309,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
doMakeDirectory(id, path, attrs, IoUtils.getLinkOptions(false));
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, SSH_FX_OK, "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
}
protected void doMakeDirectory(int id, String path, Map<String,?> attrs, LinkOption ... options) throws IOException {
@@ -1343,11 +1344,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
doRemove(id, path, IoUtils.getLinkOptions(false));
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, SSH_FX_OK, "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
}
protected void doRemove(int id, String path, LinkOption ... options) throws IOException {
@@ -1396,12 +1397,12 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
throw new AccessDeniedException("Not readable: " + file.toString());
}
- if (dh.isSendDotDot() || dh.hasNext()) {
+ if (dh.isSendDot() || dh.isSendDotDot() || dh.hasNext()) {
// There is at least one file in the directory or we need to send the "..".
// Send only a few files at a time to not create packets of a too
// large size or have a timeout to occur.
- reply = new ByteArrayBuffer();
+ reply = BufferUtils.clear(buffer);
reply.putByte((byte) SSH_FXP_NAME);
reply.putInt(id);
int lenPos = reply.wpos();
@@ -1415,18 +1416,16 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
if ((!dh.isSendDot()) && (!dh.isSendDotDot()) && (!dh.hasNext())) {
// if no more files to send
dh.markDone();
- dh.clearFileList();
}
} else {
// empty directory
dh.markDone();
- dh.clearFileList();
throw new EOFException("Empty directory");
}
ValidateUtils.checkNotNull(reply, "No reply buffer created", GenericUtils.EMPTY_OBJECT_ARRAY);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
@@ -1439,11 +1438,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
handle = doOpenDir(id, path, IoUtils.getLinkOptions(false));
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendHandle(id, handle);
+ sendHandle(BufferUtils.clear(buffer), id, handle);
}
protected String doOpenDir(int id, String path, LinkOption ... options) throws IOException {
@@ -1476,11 +1475,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
doFSetStat(id, handle, attrs);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, SSH_FX_OK, "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
}
protected void doFSetStat(int id, String handle, Map<String,?> attrs) throws IOException {
@@ -1498,11 +1497,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
doSetStat(id, path, attrs);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, SSH_FX_OK, "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
}
protected void doSetStat(int id, String path, Map<String,?> attrs) throws IOException {
@@ -1522,11 +1521,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
attrs = doFStat(id, handle, flags);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendAttrs(id, attrs);
+ sendAttrs(BufferUtils.clear(buffer), id, attrs);
}
protected Map<String,Object> doFStat(int id, String handle, int flags) throws IOException {
@@ -1549,11 +1548,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
attrs = doLStat(id, path, flags);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendAttrs(id, attrs);
+ sendAttrs(BufferUtils.clear(buffer), id, attrs);
}
protected Map<String,Object> doLStat(int id, String path, int flags) throws IOException {
@@ -1572,11 +1571,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
doWrite(id, handle, offset, length, buffer.array(), buffer.rpos(), buffer.available());
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, SSH_FX_OK, "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "");
}
protected void doWrite(int id, String handle, long offset, int length, byte[] data, int doff, int remaining) throws IOException {
@@ -1602,26 +1601,28 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
String handle = buffer.getString();
long offset = buffer.getLong();
int readLen = buffer.getInt();
- Buffer buf = new ByteArrayBuffer(readLen + Short.SIZE /* some extra */);
try {
- buf.putByte((byte) SSH_FXP_DATA);
- buf.putInt(id);
- int lenPos = buf.wpos();
- buf.putInt(0);
+ buffer.clear();
+ buffer.ensureCapacity(readLen + Long.SIZE, Int2IntFunction.IDENTITY);
- int startPos = buf.wpos();
- int len = doRead(id, handle, offset, readLen, buf.array(), startPos);
+ buffer.putByte((byte) SSH_FXP_DATA);
+ buffer.putInt(id);
+ int lenPos = buffer.wpos();
+ buffer.putInt(0);
+
+ int startPos = buffer.wpos();
+ int len = doRead(id, handle, offset, readLen, buffer.array(), startPos);
if (len < 0) {
throw new EOFException("Unable to read " + readLen + " bytes from offset=" + offset + " of " + handle);
}
- buf.wpos(startPos + len);
- BufferUtils.updateLengthPlaceholder(buf, lenPos, len);
+ buffer.wpos(startPos + len);
+ BufferUtils.updateLengthPlaceholder(buffer, lenPos, len);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- send(buf);
+ send(buffer);
}
protected int doRead(int id, String handle, long offset, int length, byte[] data, int doff) throws IOException {
@@ -1641,11 +1642,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
doClose(id, handle);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendStatus(id, SSH_FX_OK, "", "");
+ sendStatus(BufferUtils.clear(buffer), id, SSH_FX_OK, "", "");
}
protected void doClose(int id, String handle) throws IOException {
@@ -1712,11 +1713,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
try {
handle = doOpen(id, path, pflags, access, attrs);
} catch (IOException | RuntimeException e) {
- sendStatus(id, e);
+ sendStatus(BufferUtils.clear(buffer), id, e);
return;
}
- sendHandle(id, handle);
+ sendHandle(BufferUtils.clear(buffer), id, handle);
}
/**
@@ -1772,7 +1773,7 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
log.debug("Received SSH_FXP_INIT (version={})", Integer.valueOf(id));
}
- String all = checkVersionCompatibility(id, id, SSH_FX_OP_UNSUPPORTED);
+ String all = checkVersionCompatibility(buffer, id, id, SSH_FX_OP_UNSUPPORTED);
if (GenericUtils.isEmpty(all)) { // i.e. validation failed
return;
}
@@ -1943,10 +1944,6 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
BufferUtils.updateLengthPlaceholder(buffer, lenPos);
}
- protected void sendHandle(int id, String handle) throws IOException {
- sendHandle(new ByteArrayBuffer(GenericUtils.length(handle) + Long.SIZE), id, handle);
- }
-
protected void sendHandle(Buffer buffer, int id, String handle) throws IOException {
buffer.putByte((byte) SSH_FXP_HANDLE);
buffer.putInt(id);
@@ -1954,10 +1951,6 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
send(buffer);
}
- protected void sendAttrs(int id, Map<String,?> attributes) throws IOException {
- sendAttrs(new ByteArrayBuffer(), id, attributes);
- }
-
protected void sendAttrs(Buffer buffer, int id, Map<String,?> attributes) throws IOException {
buffer.putByte((byte) SSH_FXP_ATTRS);
buffer.putInt(id);
@@ -1965,14 +1958,10 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
send(buffer);
}
- protected void sendPath(int id, Path f, Map<String,?> attrs) throws IOException {
- sendPath(new ByteArrayBuffer(), id, f, attrs);
- }
-
protected void sendPath(Buffer buffer, int id, Path f, Map<String,?> attrs) throws IOException {
buffer.putByte((byte) SSH_FXP_NAME);
buffer.putInt(id);
- buffer.putInt(1);
+ buffer.putInt(1); // one reply
String originalPath = f.toString();
//in case we are running on Windows
@@ -1982,12 +1971,12 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
if (normalizedPath.length() == 0) {
normalizedPath = "/";
}
- buffer.putString(normalizedPath, StandardCharsets.UTF_8);
+ buffer.putString(normalizedPath);
if (version == SFTP_V3) {
f = resolveFile(normalizedPath);
- buffer.putString(getLongName(f, attrs), StandardCharsets.UTF_8); // Format specified in the specs
- buffer.putInt(0);
+ buffer.putString(getLongName(f, attrs));
+ buffer.putInt(0); // no flags
} else if (version >= SFTP_V4) {
writeAttrs(buffer, attrs);
} else {
@@ -1996,11 +1985,6 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
send(buffer);
}
- protected void sendLink(int id, String link) throws IOException {
- int linkSize = GenericUtils.length(link);
- sendLink(new ByteArrayBuffer((2 * linkSize) + Long.SIZE), id , link);
- }
-
protected void sendLink(Buffer buffer, int id, String link) throws IOException {
buffer.putByte((byte) SSH_FXP_NAME);
buffer.putInt(id);
@@ -2271,8 +2255,8 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
buffer.putLong(size.longValue());
}
if ((flags & SSH_FILEXFER_ATTR_OWNERGROUP) != 0) {
- buffer.putString(attributes.get("owner").toString(), StandardCharsets.UTF_8);
- buffer.putString(attributes.get("group").toString(), StandardCharsets.UTF_8);
+ buffer.putString(Objects.toString(attributes.get("owner")));
+ buffer.putString(Objects.toString(attributes.get("group")));
}
if ((flags & SSH_FILEXFER_ATTR_PERMISSIONS) != 0) {
buffer.putInt(attributesToPermissions(isReg, isDir, isLnk, perms));
@@ -2774,9 +2758,9 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
return type.cast(h);
}
- protected void sendStatus(int id, Exception e) throws IOException {
+ protected void sendStatus(Buffer buffer, int id, Exception e) throws IOException {
int substatus = resolveSubstatus(e);
- sendStatus(id, substatus, e.toString());
+ sendStatus(buffer, id, substatus, e.toString());
}
protected int resolveSubstatus(Exception e) {
@@ -2803,17 +2787,16 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
}
}
- protected void sendStatus(int id, int substatus, String msg) throws IOException {
- sendStatus(id, substatus, (msg != null) ? msg : "", "");
+ protected void sendStatus(Buffer buffer, int id, int substatus, String msg) throws IOException {
+ sendStatus(buffer, id, substatus, (msg != null) ? msg : "", "");
}
- protected void sendStatus(int id, int substatus, String msg, String lang) throws IOException {
+ protected void sendStatus(Buffer buffer, int id, int substatus, String msg, String lang) throws IOException {
if (log.isDebugEnabled()) {
log.debug("Send SSH_FXP_STATUS (substatus={}, lang={}, msg={})",
- new Object[] { Integer.valueOf(substatus), lang, msg });
+ Integer.valueOf(substatus), lang, msg);
}
- Buffer buffer = new ByteArrayBuffer();
buffer.putByte((byte) SSH_FXP_STATUS);
buffer.putInt(id);
buffer.putInt(substatus);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/1806ac97/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
index 6b41093..f7ec553 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
@@ -42,7 +42,6 @@ import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Random;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
@@ -57,11 +56,14 @@ import org.apache.sshd.client.subsystem.sftp.extensions.CopyFileExtension;
import org.apache.sshd.client.subsystem.sftp.extensions.MD5FileExtension;
import org.apache.sshd.client.subsystem.sftp.extensions.MD5HandleExtension;
import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtension;
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.digest.BuiltinDigests;
import org.apache.sshd.common.digest.Digest;
import org.apache.sshd.common.file.FileSystemFactory;
import org.apache.sshd.common.file.root.RootedFileSystemProvider;
+import org.apache.sshd.common.random.Random;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.subsystem.sftp.SftpConstants;
import org.apache.sshd.common.subsystem.sftp.extensions.ParserUtils;
@@ -262,7 +264,7 @@ public class SftpTest extends BaseTestSupport {
session.auth().verify(5L, TimeUnit.SECONDS);
try (SftpClient sftp = session.createSftpClient()) {
- testClient(sftp);
+ testClient(client, sftp);
}
} finally {
client.stop();
@@ -777,7 +779,7 @@ public class SftpTest extends BaseTestSupport {
try(SftpClient sftp = session.createSftpClient(selector)) {
assertEquals("Mismatched negotiated version", selected.get(), sftp.getVersion());
- testClient(sftp);
+ testClient(client, sftp);
}
} finally {
client.stop();
@@ -785,7 +787,7 @@ public class SftpTest extends BaseTestSupport {
}
}
- private void testClient(SftpClient sftp) throws Exception {
+ private void testClient(FactoryManager manager, SftpClient sftp) throws Exception {
Path targetPath = detectTargetFolder().toPath();
Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName());
Utils.deleteRecursive(lclSftp);
@@ -832,13 +834,18 @@ public class SftpTest extends BaseTestSupport {
sftp.remove(file);
+ final int SIZE_FACTOR = Short.SIZE;
byte[] workBuf = new byte[IoUtils.DEFAULT_COPY_SIZE * Short.SIZE];
- new Random(System.currentTimeMillis()).nextBytes(workBuf);
+ Factory<? extends Random> factory = manager.getRandomFactory();
+ Random random = factory.create();
+ random.fill(workBuf);
+
try (OutputStream os = sftp.write(file)) {
os.write(workBuf);
}
- try (InputStream is = sftp.read(file, IoUtils.DEFAULT_COPY_SIZE)) {
+ // force several internal read cycles to satisfy the full read
+ try (InputStream is = sftp.read(file, workBuf.length / SIZE_FACTOR)) {
int readLen = is.read(workBuf);
assertEquals("Mismatched read data length", workBuf.length, readLen);