diff --git a/src/main/java/core/packetproxy/gui/ExtendedTextPane.java b/src/main/java/core/packetproxy/gui/ExtendedTextPane.java index 6a136354..14fdd5a0 100644 --- a/src/main/java/core/packetproxy/gui/ExtendedTextPane.java +++ b/src/main/java/core/packetproxy/gui/ExtendedTextPane.java @@ -30,6 +30,7 @@ import javax.swing.event.EventListenerList; import javax.swing.event.UndoableEditEvent; import javax.swing.event.UndoableEditListener; +import javax.swing.text.BadLocationException; import javax.swing.undo.UndoManager; import org.apache.commons.lang3.ArrayUtils; import packetproxy.common.BinaryBuffer; @@ -93,6 +94,10 @@ public void insertUpdate(DocumentEvent e) { public void removeUpdate(DocumentEvent e) { try { + if (init_flg == true) { + + return; + } if (fin_flg == true) { fin_flg = false; @@ -260,6 +265,23 @@ protected void callDataChanged(byte[] data) { } } + protected byte[] getLoadedData() { + return data; + } + + protected void finishDocumentInitialization() { + init_flg = false; + fin_flg = false; + init_count = 0; + try { + + prev_text_panel = getDocument().getText(0, getDocument().getLength()); + } catch (BadLocationException e) { + + errWithStackTrace(e); + } + } + public abstract void setData(byte[] data) throws Exception; public abstract byte[] getData(); diff --git a/src/main/java/core/packetproxy/gui/RawTextPane.java b/src/main/java/core/packetproxy/gui/RawTextPane.java index 640a0c7a..fd47ff1a 100644 --- a/src/main/java/core/packetproxy/gui/RawTextPane.java +++ b/src/main/java/core/packetproxy/gui/RawTextPane.java @@ -421,6 +421,11 @@ public void copy() { return; } + if (selected.length() == getDocument().getLength()) { + super.copy(); + return; + } + String sanitized = stripTrailingNewlines(selected); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); StringSelection selection = new StringSelection(sanitized); @@ -447,11 +452,27 @@ public void setData(byte[] data) throws Exception { } String charSetName = charSetUtility.getCharSet(); setText(new String(data, charSetName)); + finishDocumentInitialization(); undo_manager.discardAllEdits(); } public byte[] getData() { - // Logging.log(raw_data.toString()); + var loadedData = getLoadedData(); + if (loadedData != null) { + try { + + var documentText = getDocument().getText(0, getDocument().getLength()); + var charSetName = charSetUtility.getCharSet(); + var loadedText = new String(loadedData, charSetName); + if (normalizeForComparison(documentText).equals(normalizeForComparison(loadedText))) { + + return Arrays.copyOf(loadedData, loadedData.length); + } + } catch (Exception e) { + + errWithStackTrace(e); + } + } return raw_data.toByteArray(); } @@ -470,6 +491,7 @@ public void setText(String text) { prev_text_panel = ""; raw_data.reset(text.getBytes()); super.setText(text); + finishDocumentInitialization(); undo_manager.discardAllEdits(); } catch (Exception e) { @@ -477,6 +499,10 @@ public void setText(String text) { } } + private static String normalizeForComparison(String s) { + return stripTrailingNewlines(s.replace("\r\n", "\n").replace("\r", "\n")); + } + private static String stripTrailingNewlines(String s) { int end = s.length(); while (end > 0) { diff --git a/src/test/java/packetproxy/gui/RawTextPaneTest.java b/src/test/java/packetproxy/gui/RawTextPaneTest.java new file mode 100644 index 00000000..313805a4 --- /dev/null +++ b/src/test/java/packetproxy/gui/RawTextPaneTest.java @@ -0,0 +1,88 @@ +package packetproxy.gui; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import javax.swing.SwingUtilities; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import packetproxy.model.Database; +import packetproxy.util.CharSetUtility; + +class RawTextPaneTest { + + private static final byte[] HTTP_REQUEST = "GET / HTTP/1.1\r\nHost: example\r\n\r\n" + .getBytes(StandardCharsets.UTF_8); + + @BeforeAll + static void setUpHeadless() throws Exception { + System.setProperty("java.awt.headless", "true"); + var tempDb = Files.createTempFile("packetproxy-raw-text-pane-test", ".sqlite3"); + tempDb.toFile().deleteOnExit(); + Database.getInstance().openAt(tempDb.toString()); + } + + @BeforeEach + void setUpCharset() { + CharSetUtility.getInstance().setCharSet("UTF-8"); + } + + @Test + void setData_clearsInitFlagAndReturnsOriginalBytes() throws Exception { + var pane = new RawTextPane(); + SwingUtilities.invokeAndWait(() -> { + try { + + pane.setData(HTTP_REQUEST, false); + } catch (Exception e) { + + throw new RuntimeException(e); + } + }); + + assertFalse(pane.init_flg); + assertThat(pane.getData()).isEqualTo(HTTP_REQUEST); + } + + @Test + void fullDocumentReplace_returnsOriginalBytes() throws Exception { + var pane = new RawTextPane(); + SwingUtilities.invokeAndWait(() -> { + try { + + pane.setData(HTTP_REQUEST, false); + var doc = pane.getDocument(); + var text = doc.getText(0, doc.getLength()); + doc.remove(0, doc.getLength()); + doc.insertString(0, text, null); + } catch (Exception e) { + + throw new RuntimeException(e); + } + }); + + assertThat(pane.getData()).isEqualTo(HTTP_REQUEST); + } + + @Test + void partialEdit_returnsModifiedBytes() throws Exception { + var pane = new RawTextPane(); + SwingUtilities.invokeAndWait(() -> { + try { + + pane.setData(HTTP_REQUEST, false); + var doc = pane.getDocument(); + doc.remove(4, 1); + doc.insertString(4, "X", null); + } catch (Exception e) { + + throw new RuntimeException(e); + } + }); + + assertThat(pane.getData()).isNotEqualTo(HTTP_REQUEST); + } +}