Details
Description
The code for resolving encoding from LC_CTYPE is not correct.
For instance I have LC_CTYPE=fr_FR@euro and karaf ssh connection is not working. I have found the following exception in the log:
java.lang.RuntimeException: Error opening console reader at org.apache.karaf.shell.console.impl.jline.ConsoleImpl.<init>(ConsoleImpl.java:116) at org.apache.karaf.shell.console.impl.jline.ConsoleFactoryService.create(ConsoleFactoryService.java:72) at Proxy282c46ee_31a7_4e49_9bec_93cb7b913686.create(Unknown Source) at Proxy8c51f02f_b7a1_49de_a5fd_3d68070575b3.create(Unknown Source) at org.apache.karaf.shell.ssh.ShellFactoryImpl$ShellImpl$1.runConsole(ShellFactoryImpl.java:136)[57:org.apache.karaf.shell.ssh:3.0.2] at org.apache.karaf.shell.ssh.ShellFactoryImpl$ShellImpl$1$1.run(ShellFactoryImpl.java:115) at java.security.AccessController.doPrivileged(Native Method)[:1.7.0_65] at org.apache.karaf.jaas.modules.JaasHelper.doAs(JaasHelper.java:57)[26:org.apache.karaf.jaas.modules:3.0.2] at org.apache.karaf.shell.ssh.ShellFactoryImpl$ShellImpl$1.run(ShellFactoryImpl.java:111)[57:org.apache.karaf.shell.ssh:3.0.2] Caused by: java.io.UnsupportedEncodingException: fr_FR@euro at sun.nio.cs.StreamEncoder.forOutputStreamWriter(StreamEncoder.java:61)[:1.7.0_65] at java.io.OutputStreamWriter.<init>(OutputStreamWriter.java:100)[:1.7.0_65] at jline.console.ConsoleReader.<init>(ConsoleReader.java:231) at org.apache.karaf.shell.console.impl.jline.ConsoleImpl.<init>(ConsoleImpl.java:110) ... 8 more
The issue is in the classes org.apache.karaf.shell.ssh.ShellFactoryImpl and org.apache.karaf.shell.console.impl.jline.LocalConsoleManager. The following code is erroneous:
String encoding = env.getEnv().get("LC_CTYPE"); if (encoding != null && encoding.indexOf('.') > 0) { encoding = encoding.substring(encoding.indexOf('.') + 1); }
You should instead use this kind of code (extracted from jline) :
/** * Get the default encoding. Will first look at the LC_CTYPE environment variable, then the input.encoding * system property, then the default charset according to the JVM. * * @return The default encoding to use when none is specified. */ public static String getEncoding() { // LC_CTYPE is usually in the form en_US.UTF-8 String envEncoding = extractEncodingFromCtype(System.getenv("LC_CTYPE")); if (envEncoding != null) { return envEncoding; } return System.getProperty("input.encoding", Charset.defaultCharset().name()); } /** * Parses the LC_CTYPE value to extract the encoding according to the POSIX standard, which says that the LC_CTYPE * environment variable may be of the format <code>[language[_territory][.codeset][@modifier]]</code> * * @param ctype The ctype to parse, may be null * @return The encoding, if one was present, otherwise null */ static String extractEncodingFromCtype(String ctype) { if (ctype != null && ctype.indexOf('.') > 0) { String encodingAndModifier = ctype.substring(ctype.indexOf('.') + 1); if (encodingAndModifier.indexOf('@') > 0) { return encodingAndModifier.substring(0, encodingAndModifier.indexOf('@')); } else { return encodingAndModifier; } } return null; }