Repository: jhy/jsoup
Pull request #1452 (2020-11-16 20:51:38)

Limit reading CharBuffer.array() to CharBuffer.limit() to avoid additional NULL characters at the end of some inputs
It is not documented explicitly, but `CharBuffer.array()` "Returns the char array that backs this buffer", so the buffer may have excess space at the end that was not used for the input.

(See also the explanation why https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6442955 is not a bug: 

> The Charset Buffer API is optimized for efficiency, not convenience. Buffer copies are avoided, but this means some buffers have extra elements between their limit and their capacity.

)

In a recent change to DataUtil the `array()` was passed without restricting its use to the length of `limit()`, hence adding NULL characters at the end.

Fixed by passing the value of `limit()` to the `CharArrayReader` that is actually reading from the `array()`.


Patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 00000000..18394b44
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,23 @@
+name: Build
+on: [push]
+
+jobs:
+  test:
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        os: [ubuntu-latest, windows-latest, macOS-latest]
+        java: [8, 9, 11, 12, 13, 15, 16-ea]
+      fail-fast: false
+      max-parallel: 4
+    name: Test JDK ${{ matrix.java }}, ${{ matrix.os }}
+    steps:
+      - uses: actions/checkout@v2
+      - name: Set up JDK ${{ matrix.java }}
+        uses: actions/setup-java@v1
+        with:
+          java-version: ${{ matrix.java }}
+
+      - name: Verify with Maven
+        run: mvn -X verify -B --file pom.xml
+...
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 988bd1b8..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-# From https://github.com/DanySK/Gravis-CI
-
-language: bash
-dist: xenial
-os:
-  - linux
-
-env:
-  global:
-    - GRAVIS="https://raw.githubusercontent.com/DanySK/Gravis-CI/master/"
-
-  matrix:
-    # List any JDK you want to build your software with.
-    # You can see the list of supported environments by installing Jabba and using ls-remote:
-    # https://github.com/shyiko/jabba#usage
-    - JDK="adopt@1.8."
-    - JDK="amazon-corretto@1.8."
-    - JDK="openjdk@1.9."
-    - JDK="openjdk@1.11."
-    - JDK="openjdk@1.12."
-    - JDK="openjdk@1.13."
-
-cache:
-  directories:
-    # Avoid re-downloading the JDK every time
-    - $HOME/.jabba/
-    - $HOME/.m2/
-
-before_install:
-  # Sets up the Java environment
-  - curl "${GRAVIS}.install-jdk-travis.sh" --output .install-jdk-travis.sh
-  # Get maven 3.1.1
-  - "wget http://apache.mirror.iphh.net/maven/maven-3/3.1.1/binaries/apache-maven-3.1.1-bin.tar.gz && tar xfz apache-maven-3.1.1-bin.tar.gz && sudo mv apache-maven-3.1.1 /usr/local/maven-3.1.1 && sudo rm -f /usr/local/maven && sudo ln -s /usr/local/maven-3.1.1 /usr/local/maven"
-
-before_script:
-  - bash .install-jdk-travis.sh
-
-script:
-  - /usr/local/maven/bin/mvn verify -B
diff --git a/CHANGES b/CHANGES
index 44bc0194..62e2640b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,11 +1,15 @@
 jsoup changelog
 
 *** Release 1.14.1 [PENDING]
+  * Improvement: added support for loading and parsing gzipped HTML files in Jsoup.parse(File in, charset, baseUri).
+
+  * Build Improvement: moved to GitHub Workflows for build verification.
+
   * Change: updated the minimum supported Java version from Java 7 to Java 8.
 
   * Change: updated the minimum Android API level from 8 to 10.
 
-  * Improvement: added support for loading and parsing gzipped HTML files in Jsoup.parse(File in, charset, baseUri).
+  * Change: updated Jetty (used for integration tests; not bundled) to 9.4.35.v2020112.
 
 *** Release 1.13.1 [2020-Feb-29]
   * Improvement: added Element#closest(selector), which walks up the tree to find the nearest element matching the
diff --git a/README.md b/README.md
index 7dada4fb..bc248277 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ jsoup is designed to deal with all varieties of HTML found in the wild; from pri
 
 See [**jsoup.org**](https://jsoup.org/) for downloads and the full [API documentation](https://jsoup.org/apidocs/).
 
-[![Build Status](https://travis-ci.org/jhy/jsoup.svg?branch=master)](https://travis-ci.org/jhy/jsoup)
+[![Build Status](https://github.com/jhy/jsoup/workflows/Build/badge.svg)](https://github.com/jhy/jsoup/actions?query=workflow%3ABuild)
 
 ## Example
 Fetch the [Wikipedia](https://en.wikipedia.org/wiki/Main_Page) homepage, parse it to a [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction), and select the headlines from the *In the News* section into a list of [Elements](https://jsoup.org/apidocs/index.html?org/jsoup/select/Elements.html):
@@ -31,7 +31,7 @@ for (Element headline : newsHeadlines) {
 [Online sample](https://try.jsoup.org/~LGB7rk_atM2roavV0d-czMt3J_g), [full source](https://github.com/jhy/jsoup/blob/master/src/main/java/org/jsoup/examples/Wikipedia.java).
 
 ## Open source
-jsoup is an open source project distributed under the liberal [MIT license](https://jsoup.org/license). The source code is available at [GitHub](https://github.com/jhy/jsoup/tree/master/src/main/java/org/jsoup).
+jsoup is an open source project distributed under the liberal [MIT license](https://jsoup.org/license). The source code is available at [GitHub](https://github.com/jhy/jsoup).
 
 ## Getting started
 1. [Download](https://jsoup.org/download) the latest jsoup jar (or add it to your Maven/Gradle build)
diff --git a/pom.xml b/pom.xml
index 3b6fdb59..8ae92756 100644
--- a/pom.xml
+++ b/pom.xml
@@ -276,7 +276,7 @@
       <!-- jetty for webserver integration tests. 9.2 is last with Java7 support -->
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-server</artifactId>
-      <version>9.4.26.v20200117</version>
+      <version>9.4.35.v20201120</version>
       <scope>test</scope>
     </dependency>
 
@@ -285,7 +285,7 @@
       <!-- jetty for webserver integration tests -->
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-servlet</artifactId>
-      <version>9.4.26.v20200117</version>
+      <version>9.4.35.v20201120</version>
       <scope>test</scope>
     </dependency>
 
diff --git a/src/main/java/org/jsoup/helper/DataUtil.java b/src/main/java/org/jsoup/helper/DataUtil.java
index c4d94bbe..d0385e3f 100644
--- a/src/main/java/org/jsoup/helper/DataUtil.java
+++ b/src/main/java/org/jsoup/helper/DataUtil.java
@@ -130,7 +130,7 @@ public final class DataUtil {
             try {
                 CharBuffer defaultDecoded = Charset.forName(defaultCharset).decode(firstBytes);
                 if (defaultDecoded.hasArray())
-                    doc = parser.parseInput(new CharArrayReader(defaultDecoded.array()), baseUri);
+                    doc = parser.parseInput(new CharArrayReader(defaultDecoded.array(), defaultDecoded.arrayOffset(), defaultDecoded.limit()), baseUri);
                 else
                     doc = parser.parseInput(defaultDecoded.toString(), baseUri);
             } catch (UncheckedIOException e) {


Test patch:
diff --git a/src/test/java/org/jsoup/helper/DataUtilTest.java b/src/test/java/org/jsoup/helper/DataUtilTest.java
index f585bb26..a775723f 100644
--- a/src/test/java/org/jsoup/helper/DataUtilTest.java
+++ b/src/test/java/org/jsoup/helper/DataUtilTest.java
@@ -161,6 +161,14 @@ public class DataUtilTest {
         assertEquals("OK", doc.head().select("title").text());
     }
 
+    @Test
+    public void noExtraNULLBytes() throws IOException {
+    	final byte[] b = "<html><head><meta charset=\"UTF-8\"></head><body><div><u>ü</u>ü</div></body></html>".getBytes("UTF-8");
+    	
+    	Document doc = Jsoup.parse(new ByteArrayInputStream(b), null, "");
+    	assertFalse( doc.outerHtml().contains("\u0000") );
+    }
+
     @Test
     public void supportsZippedUTF8BOM() throws IOException {
         File in = getFile("/bomtests/bom_utf8.html.gz");