Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added charset support, centralized UTF-8 usage #305

Merged
merged 3 commits into from
Mar 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.nio.charset.Charset;

import net.schmizz.sshj.common.IOUtils;

public class Jdk7HttpProxySocket extends Socket {

Expand Down Expand Up @@ -48,7 +49,7 @@ private void connectHttpProxy(SocketAddress endpoint, int timeout) throws IOExce
}
InetSocketAddress isa = (InetSocketAddress) endpoint;
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();
}

Expand All @@ -61,7 +62,7 @@ private void checkAndFlushProxyResponse()throws IOException {
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
if (proxyResponse.contains("200")) {
Expand Down
26 changes: 25 additions & 1 deletion src/main/java/net/schmizz/sshj/SSHClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package net.schmizz.sshj;

import net.schmizz.sshj.common.Factory;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.common.LoggerFactory;
import net.schmizz.sshj.common.SSHException;
import net.schmizz.sshj.common.SecurityUtils;
Expand Down Expand Up @@ -61,6 +62,7 @@
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.nio.charset.Charset;
import java.security.KeyPair;
import java.security.PublicKey;
import java.util.*;
Expand Down Expand Up @@ -128,6 +130,9 @@ public class SSHClient

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}. */
public SSHClient() {
this(new DefaultConfig());
Expand Down Expand Up @@ -440,6 +445,15 @@ public Connection getConnection() {
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. */
public RemotePortForwarder getRemotePortForwarder() {
synchronized (conn) {
Expand Down Expand Up @@ -708,12 +722,22 @@ public void rekey()
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
public Session startSession()
throws ConnectionException, TransportException {
checkConnected();
checkAuthenticated();
final SessionChannel sess = new SessionChannel(conn);
final SessionChannel sess = new SessionChannel(conn, remoteCharset);
sess.open();
return sess;
}
Expand Down
29 changes: 20 additions & 9 deletions src/main/java/net/schmizz/sshj/common/Buffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
*/
package net.schmizz.sshj.common;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
import java.util.Arrays;
Expand Down Expand Up @@ -361,24 +361,31 @@ public T putUInt64(long uint64) {
/**
* Reads an SSH string
*
* @param cs the charset to use for decoding
*
* @return the string as a Java {@code String}
*/
public String readString()
public String readString(Charset cs)
throws BufferException {
int len = readUInt32AsInt();
if (len < 0 || len > 32768)
throw new BufferException("Bad item length: " + len);
ensureAvailable(len);
String s;
try {
s = new String(data, rpos, len, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new SSHRuntimeException(e);
}
String s = new String(data, rpos, len, cs);
rpos += len;
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
*
Expand All @@ -397,8 +404,12 @@ public T putString(byte[] str, int offset, int len) {
return putBytes(str, offset, len);
}

public T putString(String string, Charset cs) {
return putString(string.getBytes(cs));
}

public T putString(String string) {
return putString(string.getBytes(IOUtils.UTF8));
return putString(string, IOUtils.UTF8);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
Expand All @@ -51,6 +52,8 @@ public abstract class AbstractChannel
private final int id;
/** Remote recipient ID */
private int recipient;
/** Remote character set */
private final Charset remoteCharset;

private boolean eof = false;

Expand Down Expand Up @@ -78,12 +81,16 @@ public abstract class AbstractChannel
private volatile boolean autoExpand = false;

protected AbstractChannel(Connection conn, String type) {
this(conn, type, null);
}
protected AbstractChannel(Connection conn, String type, Charset remoteCharset) {
this.conn = conn;
this.loggerFactory = conn.getTransport().getConfig().getLoggerFactory();
this.type = type;
this.log = loggerFactory.getLogger(getClass());
this.trans = conn.getTransport();

this.remoteCharset = remoteCharset != null ? remoteCharset : IOUtils.UTF8;
id = conn.nextID();

lwin = new Window.Local(conn.getWindowSize(), conn.getMaxPacketSize(), loggerFactory);
Expand Down Expand Up @@ -135,6 +142,11 @@ public int getRecipient() {
return recipient;
}

@Override
public Charset getRemoteCharset() {
return remoteCharset;
}

@Override
public int getRemoteMaxPacketSize() {
return rwin.getMaxPacketSize();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.io.Closeable;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;

/**
Expand Down Expand Up @@ -123,6 +124,9 @@ interface Forwarded extends Channel {
*/
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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import net.schmizz.sshj.connection.channel.OpenFailException;
import net.schmizz.sshj.transport.TransportException;

import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;

/** Base class for direct channels whose open is initated by the client. */
Expand All @@ -41,6 +42,15 @@ protected AbstractDirectChannel(Connection conn, String type) {
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
public void open()
throws ConnectionException, TransportException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import net.schmizz.sshj.transport.TransportException;

import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;
Expand All @@ -47,6 +48,10 @@ public SessionChannel(Connection conn) {
super(conn, "session");
}

public SessionChannel(Connection conn, Charset remoteCharset) {
super(conn, "session", remoteCharset);
}

@Override
public void allocateDefaultPTY()
throws ConnectionException, TransportException {
Expand Down Expand Up @@ -93,7 +98,7 @@ public Command exec(String command)
throws ConnectionException, TransportException {
checkReuse();
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);
usedUp = true;
return this;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/net/schmizz/sshj/sftp/RemoteDirectory.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public List<RemoteResourceInfo> scan(RemoteResourceFilter filter)
case NAME:
final int count = res.readUInt32AsInt();
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
final FileAttributes attrs = res.readFileAttributes();
final PathComponents comps = requester.getPathHelper().getComponents(path, name);
Expand Down
Loading