mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 23:30:55 +03:00
Added charset support, centralized UTF-8 usage (#305)
* Added charset support, centralized UTF-8 usage * Code style, buffer methods with charsets * assure remote charset isn't null
This commit is contained in:
@@ -18,7 +18,8 @@ package com.hierynomus.sshj.backport;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
|
|
||||||
public class Jdk7HttpProxySocket extends Socket {
|
public class Jdk7HttpProxySocket extends Socket {
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ public class Jdk7HttpProxySocket extends Socket {
|
|||||||
}
|
}
|
||||||
InetSocketAddress isa = (InetSocketAddress) endpoint;
|
InetSocketAddress isa = (InetSocketAddress) endpoint;
|
||||||
String httpConnect = "CONNECT " + isa.getHostName() + ":" + isa.getPort() + " HTTP/1.0\n\n";
|
String httpConnect = "CONNECT " + isa.getHostName() + ":" + isa.getPort() + " HTTP/1.0\n\n";
|
||||||
getOutputStream().write(httpConnect.getBytes(Charset.forName("UTF-8")));
|
getOutputStream().write(httpConnect.getBytes(IOUtils.UTF8));
|
||||||
checkAndFlushProxyResponse();
|
checkAndFlushProxyResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +62,7 @@ public class Jdk7HttpProxySocket extends Socket {
|
|||||||
throw new SocketException("Empty response from proxy");
|
throw new SocketException("Empty response from proxy");
|
||||||
}
|
}
|
||||||
|
|
||||||
String proxyResponse = new String(tmpBuffer, 0, len, "UTF-8");
|
String proxyResponse = new String(tmpBuffer, 0, len, IOUtils.UTF8);
|
||||||
|
|
||||||
// Expecting HTTP/1.x 200 OK
|
// Expecting HTTP/1.x 200 OK
|
||||||
if (proxyResponse.contains("200")) {
|
if (proxyResponse.contains("200")) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package net.schmizz.sshj;
|
package net.schmizz.sshj;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.Factory;
|
import net.schmizz.sshj.common.Factory;
|
||||||
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
import net.schmizz.sshj.common.LoggerFactory;
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
import net.schmizz.sshj.common.SSHException;
|
import net.schmizz.sshj.common.SSHException;
|
||||||
import net.schmizz.sshj.common.SecurityUtils;
|
import net.schmizz.sshj.common.SecurityUtils;
|
||||||
@@ -61,6 +62,7 @@ import java.io.Closeable;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -128,6 +130,9 @@ public class SSHClient
|
|||||||
|
|
||||||
private final List<LocalPortForwarder> forwarders = new ArrayList<LocalPortForwarder>();
|
private final List<LocalPortForwarder> forwarders = new ArrayList<LocalPortForwarder>();
|
||||||
|
|
||||||
|
/** character set of the remote machine */
|
||||||
|
protected Charset remoteCharset = IOUtils.UTF8;
|
||||||
|
|
||||||
/** Default constructor. Initializes this object using {@link DefaultConfig}. */
|
/** Default constructor. Initializes this object using {@link DefaultConfig}. */
|
||||||
public SSHClient() {
|
public SSHClient() {
|
||||||
this(new DefaultConfig());
|
this(new DefaultConfig());
|
||||||
@@ -440,6 +445,15 @@ public class SSHClient
|
|||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the character set used to communicate with the remote machine for certain strings (like paths).
|
||||||
|
*
|
||||||
|
* @return remote character set
|
||||||
|
*/
|
||||||
|
public Charset getRemoteCharset() {
|
||||||
|
return remoteCharset;
|
||||||
|
}
|
||||||
|
|
||||||
/** @return a {@link RemotePortForwarder} that allows requesting remote forwarding over this connection. */
|
/** @return a {@link RemotePortForwarder} that allows requesting remote forwarding over this connection. */
|
||||||
public RemotePortForwarder getRemotePortForwarder() {
|
public RemotePortForwarder getRemotePortForwarder() {
|
||||||
synchronized (conn) {
|
synchronized (conn) {
|
||||||
@@ -708,12 +722,22 @@ public class SSHClient
|
|||||||
doKex();
|
doKex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the character set used to communicate with the remote machine for certain strings (like paths)
|
||||||
|
*
|
||||||
|
* @param remoteCharset
|
||||||
|
* remote character set or {@code null} for default
|
||||||
|
*/
|
||||||
|
public void setRemoteCharset(Charset remoteCharset) {
|
||||||
|
this.remoteCharset = remoteCharset != null ? remoteCharset : IOUtils.UTF8;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Session startSession()
|
public Session startSession()
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
checkConnected();
|
checkConnected();
|
||||||
checkAuthenticated();
|
checkAuthenticated();
|
||||||
final SessionChannel sess = new SessionChannel(conn);
|
final SessionChannel sess = new SessionChannel(conn, remoteCharset);
|
||||||
sess.open();
|
sess.open();
|
||||||
return sess;
|
return sess;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.common;
|
package net.schmizz.sshj.common;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -361,24 +361,31 @@ public class Buffer<T extends Buffer<T>> {
|
|||||||
/**
|
/**
|
||||||
* Reads an SSH string
|
* Reads an SSH string
|
||||||
*
|
*
|
||||||
|
* @param cs the charset to use for decoding
|
||||||
|
*
|
||||||
* @return the string as a Java {@code String}
|
* @return the string as a Java {@code String}
|
||||||
*/
|
*/
|
||||||
public String readString()
|
public String readString(Charset cs)
|
||||||
throws BufferException {
|
throws BufferException {
|
||||||
int len = readUInt32AsInt();
|
int len = readUInt32AsInt();
|
||||||
if (len < 0 || len > 32768)
|
if (len < 0 || len > 32768)
|
||||||
throw new BufferException("Bad item length: " + len);
|
throw new BufferException("Bad item length: " + len);
|
||||||
ensureAvailable(len);
|
ensureAvailable(len);
|
||||||
String s;
|
String s = new String(data, rpos, len, cs);
|
||||||
try {
|
|
||||||
s = new String(data, rpos, len, "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new SSHRuntimeException(e);
|
|
||||||
}
|
|
||||||
rpos += len;
|
rpos += len;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads an SSH string using {@code UTF8}
|
||||||
|
*
|
||||||
|
* @return the string as a Java {@code String}
|
||||||
|
*/
|
||||||
|
public String readString()
|
||||||
|
throws BufferException {
|
||||||
|
return readString(IOUtils.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads an SSH string
|
* Reads an SSH string
|
||||||
*
|
*
|
||||||
@@ -397,8 +404,12 @@ public class Buffer<T extends Buffer<T>> {
|
|||||||
return putBytes(str, offset, len);
|
return putBytes(str, offset, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T putString(String string, Charset cs) {
|
||||||
|
return putString(string.getBytes(cs));
|
||||||
|
}
|
||||||
|
|
||||||
public T putString(String string) {
|
public T putString(String string) {
|
||||||
return putString(string.getBytes(IOUtils.UTF8));
|
return putString(string, IOUtils.UTF8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.slf4j.Logger;
|
|||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -51,6 +52,8 @@ public abstract class AbstractChannel
|
|||||||
private final int id;
|
private final int id;
|
||||||
/** Remote recipient ID */
|
/** Remote recipient ID */
|
||||||
private int recipient;
|
private int recipient;
|
||||||
|
/** Remote character set */
|
||||||
|
private final Charset remoteCharset;
|
||||||
|
|
||||||
private boolean eof = false;
|
private boolean eof = false;
|
||||||
|
|
||||||
@@ -78,12 +81,16 @@ public abstract class AbstractChannel
|
|||||||
private volatile boolean autoExpand = false;
|
private volatile boolean autoExpand = false;
|
||||||
|
|
||||||
protected AbstractChannel(Connection conn, String type) {
|
protected AbstractChannel(Connection conn, String type) {
|
||||||
|
this(conn, type, null);
|
||||||
|
}
|
||||||
|
protected AbstractChannel(Connection conn, String type, Charset remoteCharset) {
|
||||||
this.conn = conn;
|
this.conn = conn;
|
||||||
this.loggerFactory = conn.getTransport().getConfig().getLoggerFactory();
|
this.loggerFactory = conn.getTransport().getConfig().getLoggerFactory();
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.log = loggerFactory.getLogger(getClass());
|
this.log = loggerFactory.getLogger(getClass());
|
||||||
this.trans = conn.getTransport();
|
this.trans = conn.getTransport();
|
||||||
|
|
||||||
|
this.remoteCharset = remoteCharset != null ? remoteCharset : IOUtils.UTF8;
|
||||||
id = conn.nextID();
|
id = conn.nextID();
|
||||||
|
|
||||||
lwin = new Window.Local(conn.getWindowSize(), conn.getMaxPacketSize(), loggerFactory);
|
lwin = new Window.Local(conn.getWindowSize(), conn.getMaxPacketSize(), loggerFactory);
|
||||||
@@ -135,6 +142,11 @@ public abstract class AbstractChannel
|
|||||||
return recipient;
|
return recipient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Charset getRemoteCharset() {
|
||||||
|
return remoteCharset;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRemoteMaxPacketSize() {
|
public int getRemoteMaxPacketSize() {
|
||||||
return rwin.getMaxPacketSize();
|
return rwin.getMaxPacketSize();
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import net.schmizz.sshj.transport.TransportException;
|
|||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,6 +124,9 @@ public interface Channel extends Closeable, SSHPacketHandler, ErrorNotifiable {
|
|||||||
*/
|
*/
|
||||||
int getRecipient();
|
int getRecipient();
|
||||||
|
|
||||||
|
/** @return the character set used to communicate with the remote machine for certain strings (like paths). */
|
||||||
|
Charset getRemoteCharset();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the maximum packet size as specified by the remote end.
|
* @return the maximum packet size as specified by the remote end.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import net.schmizz.sshj.connection.channel.Channel;
|
|||||||
import net.schmizz.sshj.connection.channel.OpenFailException;
|
import net.schmizz.sshj.connection.channel.OpenFailException;
|
||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/** Base class for direct channels whose open is initated by the client. */
|
/** Base class for direct channels whose open is initated by the client. */
|
||||||
@@ -41,6 +42,15 @@ public abstract class AbstractDirectChannel
|
|||||||
conn.attach(this);
|
conn.attach(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected AbstractDirectChannel(Connection conn, String type, Charset remoteCharset) {
|
||||||
|
super(conn, type, remoteCharset);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We expect to receive channel open confirmation/rejection and want to be able to next this packet.
|
||||||
|
*/
|
||||||
|
conn.attach(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void open()
|
public void open()
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import net.schmizz.sshj.connection.channel.ChannelInputStream;
|
|||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -47,6 +48,10 @@ public class SessionChannel
|
|||||||
super(conn, "session");
|
super(conn, "session");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SessionChannel(Connection conn, Charset remoteCharset) {
|
||||||
|
super(conn, "session", remoteCharset);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void allocateDefaultPTY()
|
public void allocateDefaultPTY()
|
||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
@@ -93,7 +98,7 @@ public class SessionChannel
|
|||||||
throws ConnectionException, TransportException {
|
throws ConnectionException, TransportException {
|
||||||
checkReuse();
|
checkReuse();
|
||||||
log.debug("Will request to exec `{}`", command);
|
log.debug("Will request to exec `{}`", command);
|
||||||
sendChannelRequest("exec", true, new Buffer.PlainBuffer().putString(command))
|
sendChannelRequest("exec", true, new Buffer.PlainBuffer().putString(command, getRemoteCharset()))
|
||||||
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
.await(conn.getTimeoutMs(), TimeUnit.MILLISECONDS);
|
||||||
usedUp = true;
|
usedUp = true;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public class RemoteDirectory
|
|||||||
case NAME:
|
case NAME:
|
||||||
final int count = res.readUInt32AsInt();
|
final int count = res.readUInt32AsInt();
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
final String name = res.readString();
|
final String name = res.readString(requester.sub.getRemoteCharset());
|
||||||
res.readString(); // long name - IGNORED - shdve never been in the protocol
|
res.readString(); // long name - IGNORED - shdve never been in the protocol
|
||||||
final FileAttributes attrs = res.readFileAttributes();
|
final FileAttributes attrs = res.readFileAttributes();
|
||||||
final PathComponents comps = requester.getPathHelper().getComponents(path, name);
|
final PathComponents comps = requester.getPathHelper().getComponents(path, name);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package net.schmizz.sshj.sftp;
|
package net.schmizz.sshj.sftp;
|
||||||
|
|
||||||
import net.schmizz.concurrent.Promise;
|
import net.schmizz.concurrent.Promise;
|
||||||
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
import net.schmizz.sshj.common.LoggerFactory;
|
import net.schmizz.sshj.common.LoggerFactory;
|
||||||
import net.schmizz.sshj.common.SSHException;
|
import net.schmizz.sshj.common.SSHException;
|
||||||
import net.schmizz.sshj.connection.channel.direct.Session;
|
import net.schmizz.sshj.connection.channel.direct.Session;
|
||||||
@@ -25,6 +26,7 @@ import org.slf4j.Logger;
|
|||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -137,7 +139,7 @@ public class SFTPEngine
|
|||||||
public RemoteFile open(String path, Set<OpenMode> modes, FileAttributes fa)
|
public RemoteFile open(String path, Set<OpenMode> modes, FileAttributes fa)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final byte[] handle = doRequest(
|
final byte[] handle = doRequest(
|
||||||
newRequest(PacketType.OPEN).putString(path).putUInt32(OpenMode.toMask(modes)).putFileAttributes(fa)
|
newRequest(PacketType.OPEN).putString(path, sub.getRemoteCharset()).putUInt32(OpenMode.toMask(modes)).putFileAttributes(fa)
|
||||||
).ensurePacketTypeIs(PacketType.HANDLE).readBytes();
|
).ensurePacketTypeIs(PacketType.HANDLE).readBytes();
|
||||||
return new RemoteFile(this, path, handle);
|
return new RemoteFile(this, path, handle);
|
||||||
}
|
}
|
||||||
@@ -155,7 +157,7 @@ public class SFTPEngine
|
|||||||
public RemoteDirectory openDir(String path)
|
public RemoteDirectory openDir(String path)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final byte[] handle = doRequest(
|
final byte[] handle = doRequest(
|
||||||
newRequest(PacketType.OPENDIR).putString(path)
|
newRequest(PacketType.OPENDIR).putString(path, sub.getRemoteCharset())
|
||||||
).ensurePacketTypeIs(PacketType.HANDLE).readBytes();
|
).ensurePacketTypeIs(PacketType.HANDLE).readBytes();
|
||||||
return new RemoteDirectory(this, path, handle);
|
return new RemoteDirectory(this, path, handle);
|
||||||
}
|
}
|
||||||
@@ -163,7 +165,7 @@ public class SFTPEngine
|
|||||||
public void setAttributes(String path, FileAttributes attrs)
|
public void setAttributes(String path, FileAttributes attrs)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
doRequest(
|
doRequest(
|
||||||
newRequest(PacketType.SETSTAT).putString(path).putFileAttributes(attrs)
|
newRequest(PacketType.SETSTAT).putString(path, sub.getRemoteCharset()).putFileAttributes(attrs)
|
||||||
).ensureStatusPacketIsOK();
|
).ensureStatusPacketIsOK();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,13 +175,13 @@ public class SFTPEngine
|
|||||||
throw new SFTPException("READLINK is not supported in SFTPv" + operativeVersion);
|
throw new SFTPException("READLINK is not supported in SFTPv" + operativeVersion);
|
||||||
return readSingleName(
|
return readSingleName(
|
||||||
doRequest(
|
doRequest(
|
||||||
newRequest(PacketType.READLINK).putString(path)
|
newRequest(PacketType.READLINK).putString(path, sub.getRemoteCharset())
|
||||||
));
|
), sub.getRemoteCharset());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void makeDir(String path, FileAttributes attrs)
|
public void makeDir(String path, FileAttributes attrs)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
doRequest(newRequest(PacketType.MKDIR).putString(path).putFileAttributes(attrs)).ensureStatusPacketIsOK();
|
doRequest(newRequest(PacketType.MKDIR).putString(path, sub.getRemoteCharset()).putFileAttributes(attrs)).ensureStatusPacketIsOK();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void makeDir(String path)
|
public void makeDir(String path)
|
||||||
@@ -192,21 +194,21 @@ public class SFTPEngine
|
|||||||
if (operativeVersion < 3)
|
if (operativeVersion < 3)
|
||||||
throw new SFTPException("SYMLINK is not supported in SFTPv" + operativeVersion);
|
throw new SFTPException("SYMLINK is not supported in SFTPv" + operativeVersion);
|
||||||
doRequest(
|
doRequest(
|
||||||
newRequest(PacketType.SYMLINK).putString(linkpath).putString(targetpath)
|
newRequest(PacketType.SYMLINK).putString(linkpath, sub.getRemoteCharset()).putString(targetpath, sub.getRemoteCharset())
|
||||||
).ensureStatusPacketIsOK();
|
).ensureStatusPacketIsOK();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(String filename)
|
public void remove(String filename)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
doRequest(
|
doRequest(
|
||||||
newRequest(PacketType.REMOVE).putString(filename)
|
newRequest(PacketType.REMOVE).putString(filename, sub.getRemoteCharset())
|
||||||
).ensureStatusPacketIsOK();
|
).ensureStatusPacketIsOK();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeDir(String path)
|
public void removeDir(String path)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
doRequest(
|
doRequest(
|
||||||
newRequest(PacketType.RMDIR).putString(path)
|
newRequest(PacketType.RMDIR).putString(path, sub.getRemoteCharset())
|
||||||
).ensureStatusIs(Response.StatusCode.OK);
|
).ensureStatusIs(Response.StatusCode.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +227,7 @@ public class SFTPEngine
|
|||||||
if (operativeVersion < 1)
|
if (operativeVersion < 1)
|
||||||
throw new SFTPException("RENAME is not supported in SFTPv" + operativeVersion);
|
throw new SFTPException("RENAME is not supported in SFTPv" + operativeVersion);
|
||||||
doRequest(
|
doRequest(
|
||||||
newRequest(PacketType.RENAME).putString(oldPath).putString(newPath)
|
newRequest(PacketType.RENAME).putString(oldPath, sub.getRemoteCharset()).putString(newPath, sub.getRemoteCharset())
|
||||||
).ensureStatusPacketIsOK();
|
).ensureStatusPacketIsOK();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,8 +235,8 @@ public class SFTPEngine
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
return readSingleName(
|
return readSingleName(
|
||||||
doRequest(
|
doRequest(
|
||||||
newRequest(PacketType.REALPATH).putString(path)
|
newRequest(PacketType.REALPATH).putString(path, sub.getRemoteCharset())
|
||||||
));
|
), sub.getRemoteCharset());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTimeoutMs(int timeoutMs) {
|
public void setTimeoutMs(int timeoutMs) {
|
||||||
@@ -258,20 +260,32 @@ public class SFTPEngine
|
|||||||
|
|
||||||
protected FileAttributes stat(PacketType pt, String path)
|
protected FileAttributes stat(PacketType pt, String path)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return doRequest(newRequest(pt).putString(path))
|
return doRequest(newRequest(pt).putString(path, sub.getRemoteCharset()))
|
||||||
.ensurePacketTypeIs(PacketType.ATTRS)
|
.ensurePacketTypeIs(PacketType.ATTRS)
|
||||||
.readFileAttributes();
|
.readFileAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static String readSingleName(Response res)
|
private static byte[] readSingleNameAsBytes(Response res)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
res.ensurePacketTypeIs(PacketType.NAME);
|
res.ensurePacketTypeIs(PacketType.NAME);
|
||||||
if (res.readUInt32AsInt() == 1)
|
if (res.readUInt32AsInt() == 1)
|
||||||
return res.readString();
|
return res.readStringAsBytes();
|
||||||
else
|
else
|
||||||
throw new SFTPException("Unexpected data in " + res.getType() + " packet");
|
throw new SFTPException("Unexpected data in " + res.getType() + " packet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Using UTF-8 */
|
||||||
|
protected static String readSingleName(Response res)
|
||||||
|
throws IOException {
|
||||||
|
return readSingleName(res, IOUtils.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Using any character set */
|
||||||
|
protected static String readSingleName(Response res, Charset charset)
|
||||||
|
throws IOException {
|
||||||
|
return new String(readSingleNameAsBytes(res), charset);
|
||||||
|
}
|
||||||
|
|
||||||
protected synchronized void transmit(SFTPPacket<Request> payload)
|
protected synchronized void transmit(SFTPPacket<Request> payload)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final int len = payload.available();
|
final int len = payload.available();
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
/** @see <a href="http://blogs.sun.com/janp/entry/how_the_scp_protocol_works">SCP Protocol</a> */
|
/** @see <a href="https://blogs.oracle.com/janp/entry/how_the_scp_protocol_works">SCP Protocol</a> */
|
||||||
class SCPEngine {
|
class SCPEngine {
|
||||||
|
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ class SCPEngine {
|
|||||||
|
|
||||||
void sendMessage(String msg) throws IOException {
|
void sendMessage(String msg) throws IOException {
|
||||||
log.debug("Sending message: {}", msg);
|
log.debug("Sending message: {}", msg);
|
||||||
scp.getOutputStream().write((msg + LF).getBytes(IOUtils.UTF8));
|
scp.getOutputStream().write((msg + LF).getBytes(scp.getRemoteCharset()));
|
||||||
scp.getOutputStream().flush();
|
scp.getOutputStream().flush();
|
||||||
check("Message ACK received");
|
check("Message ACK received");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class FileUtil {
|
|||||||
FileInputStream fileInputStream = new FileInputStream(f);
|
FileInputStream fileInputStream = new FileInputStream(f);
|
||||||
try {
|
try {
|
||||||
ByteArrayOutputStream byteArrayOutputStream = IOUtils.readFully(fileInputStream);
|
ByteArrayOutputStream byteArrayOutputStream = IOUtils.readFully(fileInputStream);
|
||||||
return byteArrayOutputStream.toString("UTF-8");
|
return byteArrayOutputStream.toString(IOUtils.UTF8.displayName());
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(fileInputStream);
|
IOUtils.closeQuietly(fileInputStream);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@
|
|||||||
package net.schmizz.sshj.util;
|
package net.schmizz.sshj.util;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.Buffer;
|
import net.schmizz.sshj.common.Buffer;
|
||||||
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -51,7 +53,7 @@ public class BufferTest {
|
|||||||
public void setUp()
|
public void setUp()
|
||||||
throws UnsupportedEncodingException, GeneralSecurityException {
|
throws UnsupportedEncodingException, GeneralSecurityException {
|
||||||
// for position test
|
// for position test
|
||||||
byte[] data = "Hello".getBytes("UTF-8");
|
byte[] data = "Hello".getBytes(IOUtils.UTF8);
|
||||||
posBuf = new Buffer.PlainBuffer(data);
|
posBuf = new Buffer.PlainBuffer(data);
|
||||||
handyBuf = new Buffer.PlainBuffer();
|
handyBuf = new Buffer.PlainBuffer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,12 @@ package net.schmizz.sshj.util.gss;
|
|||||||
|
|
||||||
import org.ietf.jgss.*;
|
import org.ietf.jgss.*;
|
||||||
|
|
||||||
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static net.schmizz.sshj.util.gss.BogusGSSManager.unavailable;
|
import static net.schmizz.sshj.util.gss.BogusGSSManager.unavailable;
|
||||||
@@ -34,7 +35,7 @@ public class BogusGSSContext
|
|||||||
private static final byte[] MIC = fromString("LGTM");
|
private static final byte[] MIC = fromString("LGTM");
|
||||||
|
|
||||||
private static byte[] fromString(String s) {
|
private static byte[] fromString(String s) {
|
||||||
return s.getBytes(Charset.forName("UTF-8"));
|
return s.getBytes(IOUtils.UTF8);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean initialized = false;
|
private boolean initialized = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user