mirror of
https://github.com/corda/corda.git
synced 2024-12-20 05:28:21 +00:00
Filter zero bytes from CRaSH input stream. (#460)
* Work around JavaFX injecting 0 bytes into JediTerm's STDIN stream. * Add (disabled) unit tests for running JediTerm in both Swing and JavaFX. * Remove tests for running JediTerm under Swing and JavaFX.
This commit is contained in:
parent
78a0024e00
commit
ade9a7dba8
@ -29,6 +29,7 @@ buildscript {
|
|||||||
ext.typesafe_config_version = '1.3.1'
|
ext.typesafe_config_version = '1.3.1'
|
||||||
ext.fileupload_version = '1.3.2'
|
ext.fileupload_version = '1.3.2'
|
||||||
ext.junit_version = '4.12'
|
ext.junit_version = '4.12'
|
||||||
|
ext.mockito_version = '1.10.19'
|
||||||
ext.jopt_simple_version = '5.0.2'
|
ext.jopt_simple_version = '5.0.2'
|
||||||
ext.jansi_version = '1.14'
|
ext.jansi_version = '1.14'
|
||||||
ext.hibernate_version = '5.2.6.Final'
|
ext.hibernate_version = '5.2.6.Final'
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
<AppenderRef ref="RollingFile-Appender" />
|
<AppenderRef ref="RollingFile-Appender" />
|
||||||
</Logger>
|
</Logger>
|
||||||
<Logger name="org.apache.activemq.artemis.core.server" level="error" additivity="false">
|
<Logger name="org.apache.activemq.artemis.core.server" level="error" additivity="false">
|
||||||
<AppenderRef ref="RollingFile-Appender"/>
|
<AppenderRef ref="RollingFile-Appender"/>
|
||||||
</Logger>
|
</Logger>
|
||||||
</Loggers>
|
</Loggers>
|
||||||
</Configuration>
|
</Configuration>
|
@ -23,7 +23,10 @@ apply plugin: 'application'
|
|||||||
evaluationDependsOn(':tools:explorer:capsule')
|
evaluationDependsOn(':tools:explorer:capsule')
|
||||||
|
|
||||||
mainClassName = 'net.corda.demobench.DemoBench'
|
mainClassName = 'net.corda.demobench.DemoBench'
|
||||||
applicationDefaultJvmArgs = ['-Djava.util.logging.config.class=net.corda.demobench.config.LoggingConfig', '-Dorg.jboss.logging.provider=slf4j']
|
applicationDefaultJvmArgs = [
|
||||||
|
'-Djava.util.logging.config.class=net.corda.demobench.config.LoggingConfig',
|
||||||
|
'-Dorg.jboss.logging.provider=slf4j'
|
||||||
|
]
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
flatDir {
|
flatDir {
|
||||||
@ -66,6 +69,7 @@ dependencies {
|
|||||||
|
|
||||||
testCompile "junit:junit:$junit_version"
|
testCompile "junit:junit:$junit_version"
|
||||||
testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
testCompile "org.mockito:mockito-core:$mockito_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
package net.corda.demobench.pty;
|
|
||||||
|
|
||||||
import com.jediterm.terminal.ProcessTtyConnector;
|
|
||||||
import com.pty4j.PtyProcess;
|
|
||||||
import com.pty4j.WinSize;
|
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copied from JediTerm pty.
|
|
||||||
* JediTerm is not available in any Maven repository.
|
|
||||||
* @author traff
|
|
||||||
*/
|
|
||||||
public class PtyProcessTtyConnector extends ProcessTtyConnector {
|
|
||||||
private final PtyProcess myProcess;
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
PtyProcessTtyConnector(String name, PtyProcess process, Charset charset) {
|
|
||||||
super(process, charset);
|
|
||||||
myProcess = process;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void resizeImmediately() {
|
|
||||||
if (getPendingTermSize() != null && getPendingPixelSize() != null) {
|
|
||||||
myProcess.setWinSize(
|
|
||||||
new WinSize(getPendingTermSize().width, getPendingTermSize().height, getPendingPixelSize().width, getPendingPixelSize().height));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isConnected() {
|
|
||||||
return myProcess.isRunning();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,34 @@
|
|||||||
|
package net.corda.demobench.pty
|
||||||
|
|
||||||
|
import com.jediterm.terminal.ProcessTtyConnector
|
||||||
|
import com.pty4j.PtyProcess
|
||||||
|
import com.pty4j.WinSize
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copied from JediTerm pty.
|
||||||
|
* JediTerm is not available in any Maven repository.
|
||||||
|
* @author traff
|
||||||
|
*/
|
||||||
|
class PtyProcessTtyConnector(
|
||||||
|
private val name: String,
|
||||||
|
private val process: PtyProcess,
|
||||||
|
charset: Charset
|
||||||
|
) : ProcessTtyConnector(process.zeroFiltered(), charset) {
|
||||||
|
|
||||||
|
override fun getName() = name
|
||||||
|
|
||||||
|
override fun isConnected() = process.isRunning
|
||||||
|
|
||||||
|
override fun resizeImmediately() {
|
||||||
|
if (pendingTermSize != null && pendingPixelSize != null) {
|
||||||
|
process.winSize = WinSize(
|
||||||
|
pendingTermSize.width,
|
||||||
|
pendingTermSize.height,
|
||||||
|
pendingPixelSize.width,
|
||||||
|
pendingPixelSize.height
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -9,7 +9,6 @@ import net.corda.core.utilities.loggerFor
|
|||||||
import java.awt.*
|
import java.awt.*
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.charset.StandardCharsets.UTF_8
|
import java.nio.charset.StandardCharsets.UTF_8
|
||||||
import java.util.*
|
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@ -44,7 +43,7 @@ class R3Pty(val name: String, settings: SettingsProvider, dimension: Dimension,
|
|||||||
fun run(args: Array<String>, envs: Map<String, String>, workingDir: String?) {
|
fun run(args: Array<String>, envs: Map<String, String>, workingDir: String?) {
|
||||||
check(!terminal.isSessionRunning, { "${terminal.sessionName} is already running" })
|
check(!terminal.isSessionRunning, { "${terminal.sessionName} is already running" })
|
||||||
|
|
||||||
val environment = HashMap<String, String>(envs)
|
val environment = envs.toMutableMap()
|
||||||
if (!UIUtil.isWindows) {
|
if (!UIUtil.isWindows) {
|
||||||
environment["TERM"] = "xterm"
|
environment["TERM"] = "xterm"
|
||||||
|
|
||||||
@ -64,4 +63,7 @@ class R3Pty(val name: String, settings: SettingsProvider, dimension: Dimension,
|
|||||||
session.start()
|
session.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(InterruptedException::class)
|
||||||
|
fun waitFor(): Int? = terminal.ttyConnector?.waitFor()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
package net.corda.demobench.pty
|
||||||
|
|
||||||
|
import java.io.FilterOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes any zero byte values from the output stream.
|
||||||
|
* This stream is connected to a terminal's STDIN, and
|
||||||
|
* any zeros received will trigger unwanted key mappings.
|
||||||
|
* JavaFX seems to be inserting these zeros into the
|
||||||
|
* stream as it tries to inter-operate with Swing.
|
||||||
|
*/
|
||||||
|
private class ZeroFilter(output: OutputStream) : FilterOutputStream(output) {
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun write(b: Int) {
|
||||||
|
if (b != 0) {
|
||||||
|
super.write(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun write(raw: ByteArray, offset: Int, len: Int) {
|
||||||
|
val filtered = ByteArray(len)
|
||||||
|
var count = 0
|
||||||
|
|
||||||
|
var i = 0
|
||||||
|
while (i < len) {
|
||||||
|
val b = raw[offset + i]
|
||||||
|
if (b != 0.toByte()) {
|
||||||
|
filtered[count] = b
|
||||||
|
++count
|
||||||
|
}
|
||||||
|
++i
|
||||||
|
}
|
||||||
|
|
||||||
|
super.write(filtered, 0, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a process's output stream with a zero filter.
|
||||||
|
*/
|
||||||
|
private class ZeroFilteringProcess(private val process: Process) : Process() {
|
||||||
|
private val output: OutputStream
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.output = ZeroFilter(process.outputStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOutputStream() = output
|
||||||
|
|
||||||
|
override fun getInputStream(): InputStream = process.inputStream
|
||||||
|
|
||||||
|
override fun getErrorStream(): InputStream = process.errorStream
|
||||||
|
|
||||||
|
@Throws(InterruptedException::class)
|
||||||
|
override fun waitFor() = process.waitFor()
|
||||||
|
|
||||||
|
override fun destroy() = process.destroy()
|
||||||
|
|
||||||
|
override fun exitValue() = process.exitValue()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the ZeroFilter to this process.
|
||||||
|
*/
|
||||||
|
fun Process.zeroFiltered(): Process = ZeroFilteringProcess(this)
|
@ -0,0 +1,58 @@
|
|||||||
|
package net.corda.demobench.pty
|
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mockito.Mockito.*
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.nio.charset.StandardCharsets.UTF_8
|
||||||
|
|
||||||
|
class ZeroFilterTest {
|
||||||
|
private lateinit var output: ByteArrayOutputStream
|
||||||
|
private lateinit var filter: OutputStream
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
output = ByteArrayOutputStream()
|
||||||
|
|
||||||
|
val process = mock(Process::class.java)
|
||||||
|
`when`(process.outputStream).thenReturn(output)
|
||||||
|
|
||||||
|
filter = process.zeroFiltered().outputStream
|
||||||
|
verify(process).outputStream
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `non-zero is OK`() {
|
||||||
|
for (c in 'A'..'Z') {
|
||||||
|
filter.write(c.toInt())
|
||||||
|
}
|
||||||
|
assertEquals(26, output.size())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `zero is removed`() {
|
||||||
|
filter.write(0)
|
||||||
|
assertEquals(0, output.size())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `zero is removed from array`() {
|
||||||
|
val input = "He\u0000l\u0000lo".toByteArray(UTF_8)
|
||||||
|
filter.write(input)
|
||||||
|
|
||||||
|
assertEquals(5, output.size())
|
||||||
|
assertEquals("Hello", output.toString("UTF-8"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `zero is removed starting from offset`() {
|
||||||
|
val input = "H\u0000el\u0000lo W\u0000or\u0000ld!\u0000".toByteArray(UTF_8)
|
||||||
|
val offset = input.indexOf('W'.toByte())
|
||||||
|
filter.write(input, offset, input.size - offset)
|
||||||
|
|
||||||
|
assertEquals(6, output.size())
|
||||||
|
assertEquals("World!", output.toString("UTF-8"))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user