Skip to content

Commit 1ca05f7

Browse files
authored
📜 Implement encoding handling in XML requests (#12)
* 📜 Implement encoding handling in XML requests * Fix XML encoding marker * Fix XML encoding marker² * 🛠️ Handle invalid charset encoding in XMLRequestExtractor
1 parent 023c616 commit 1ca05f7

20 files changed

+542
-42
lines changed

Dockerfile

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
# Verwenden Sie ein schlankes OpenJDK-Basisimage
21
FROM eclipse-temurin:21-alpine
32

4-
# Setze das Arbeitsverzeichnis
53
WORKDIR /app
64

7-
# Kopiere die JAR-Datei und das Datenverzeichnis in das Image
85
COPY build/libs/xrviz.jar /app/xrviz.jar
96
COPY data /app/data
107

11-
# Exponieren Sie die relevanten Ports (optional, falls Ihr daemon auf bestimmten ports hört)
128
EXPOSE 4000
139

14-
# Startbefehl für das JAR
1510
CMD ["java", "-jar", "/app/xrviz.jar"]

build.gradle

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ repositories {
1515
}
1616

1717
dependencies {
18-
implementation 'net.sf.saxon:Saxon-HE:12.4'
18+
implementation 'net.sf.saxon:Saxon-HE:12.5'
1919
implementation 'org.apache.xmlgraphics:fop:2.9'
20+
implementation 'com.googlecode.juniversalchardet:juniversalchardet:1.0.3'
2021
}
2122

2223
jar {
@@ -49,7 +50,7 @@ tasks.register('buildDockerImage', Exec) {
4950

5051
wrapper {
5152
distributionType = Wrapper.DistributionType.BIN
52-
gradleVersion = '8.7'
53+
gradleVersion = '8.10.1'
5354
}
5455

5556
tasks.register('createVersionBadge') {
@@ -61,3 +62,22 @@ tasks.register('createVersionBadge') {
6162
outputFile.text = inputFile.text.replaceAll('\\$VERS\\$', currentVersion)
6263
}
6364
}
65+
66+
tasks.register('getLatestGradleVersion') {
67+
doLast {
68+
def responseText = project.resources.text.fromUri('https://api.github.com/repos/gradle/gradle/releases').asString()
69+
def latestStableVersion = (responseText =~ /"tag_name"\s*:\s*"v(\d+\.\d+(?:\.\d+)?)"[^}]+"draft"\s*:\s*(false)[^}]+"prerelease"\s*:\s*(false)/)
70+
.findAll().first()[1]
71+
72+
if (latestStableVersion) {
73+
if (latestStableVersion == gradle.gradleVersion) {
74+
println "You are up to date ($latestStableVersion)."
75+
} else {
76+
println "Latest stable Gradle version is: $latestStableVersion (in use: ${gradle.gradleVersion})" +
77+
"\n\nGet it with: ./gradlew wrapper --gradle-version=$latestStableVersion"
78+
}
79+
} else {
80+
println "Could not determine the latest stable Gradle version."
81+
}
82+
}
83+
}

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
currentVersion=0.1.7
1+
currentVersion=0.1.9
22
mainClassName=io.github.easybill.xrviz.App

gradle/wrapper/gradle-wrapper.jar

130 Bytes
Binary file not shown.

gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

gradlew

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
# See the License for the specific language governing permissions and
1616
# limitations under the License.
1717
#
18+
# SPDX-License-Identifier: Apache-2.0
19+
#
1820

1921
##############################################################################
2022
#
@@ -55,7 +57,7 @@
5557
# Darwin, MinGW, and NonStop.
5658
#
5759
# (3) This script is generated from the Groovy template
58-
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
60+
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
5961
# within the Gradle project.
6062
#
6163
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
8486
# shellcheck disable=SC2034
8587
APP_BASE_NAME=${0##*/}
8688
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
87-
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
89+
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
90+
' "$PWD" ) || exit
8891

8992
# Use the maximum available, or set MAX_FD != -1 to use that value.
9093
MAX_FD=maximum

gradlew.bat

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
@rem See the License for the specific language governing permissions and
1414
@rem limitations under the License.
1515
@rem
16+
@rem SPDX-License-Identifier: Apache-2.0
17+
@rem
1618

1719
@if "%DEBUG%"=="" @echo off
1820
@rem ##########################################################################

src/main/java/io/github/easybill/xrviz/Config.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,10 @@ public static String getVersion() {
8585
}
8686

8787
public static void showBanner() {
88-
try {
89-
logger.info("\n" + (new String(Config.class.getResourceAsStream("/banner.txt").readAllBytes())));
88+
try (InputStream inputStream = Config.class.getResourceAsStream("/banner.txt")) {
89+
if (inputStream != null) {
90+
logger.info("\n" + new String(inputStream.readAllBytes()));
91+
}
9092
} catch (IOException ignored) {
9193
}
9294
logger.info("XRechnung Visualizer v" + getVersion());

src/main/java/io/github/easybill/xrviz/XmlHelper.java

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/main/java/io/github/easybill/xrviz/XslTransformer.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.github.easybill.xrviz;
22

3-
import net.sf.saxon.regex.RegularExpression;
43
import org.apache.fop.apps.FOPException;
54
import org.apache.fop.apps.Fop;
65
import org.apache.fop.apps.FopFactory;

src/main/java/io/github/easybill/xrviz/handler/HtmlHandler.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import com.sun.net.httpserver.HttpExchange;
44
import com.sun.net.httpserver.HttpHandler;
5-
import io.github.easybill.xrviz.XmlHelper;
65
import io.github.easybill.xrviz.XslTransformer;
76

87
import javax.xml.transform.TransformerException;
@@ -20,9 +19,7 @@ public void handle(HttpExchange exchange) throws IOException {
2019
return;
2120
}
2221

23-
var xmlContent = XmlHelper.removeBOM(xml.get());
24-
25-
byte[] response = XslTransformer.transformToHtml(xmlContent, getLanguage(exchange)).getBytes(StandardCharsets.UTF_8);
22+
byte[] response = XslTransformer.transformToHtml(xml.get(), getLanguage(exchange)).getBytes(StandardCharsets.UTF_8);
2623

2724
exchange.getResponseHeaders().set("Content-Type", "text/html");
2825
exchange.sendResponseHeaders(200, response.length);

src/main/java/io/github/easybill/xrviz/handler/PdfHandler.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22

33
import com.sun.net.httpserver.HttpExchange;
44
import com.sun.net.httpserver.HttpHandler;
5-
import io.github.easybill.xrviz.XmlHelper;
65
import io.github.easybill.xrviz.XslTransformer;
76
import org.apache.fop.apps.FOPException;
8-
import org.apache.fop.render.txt.Helper;
97

108
import javax.xml.transform.TransformerException;
119
import java.io.IOException;
@@ -21,9 +19,7 @@ public void handle(HttpExchange exchange) throws IOException {
2119
return;
2220
}
2321

24-
var xmlContent = XmlHelper.removeBOM(xml.get());
25-
26-
byte[] response = XslTransformer.transformToPdf(xmlContent, getLanguage(exchange));
22+
byte[] response = XslTransformer.transformToPdf(xml.get(), getLanguage(exchange));
2723

2824
exchange.getResponseHeaders().set("Content-Type", "application/pdf");
2925
exchange.sendResponseHeaders(200, response.length);

src/main/java/io/github/easybill/xrviz/handler/XmlRequestExtractor.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package io.github.easybill.xrviz.handler;
22

33
import com.sun.net.httpserver.HttpExchange;
4+
import org.mozilla.universalchardet.UniversalDetector;
45

56
import java.io.IOException;
67
import java.net.HttpURLConnection;
8+
import java.nio.charset.Charset;
79
import java.nio.charset.StandardCharsets;
810
import java.util.Optional;
911
import java.util.logging.Logger;
@@ -21,7 +23,30 @@ Optional<String> validate(HttpExchange exchange) throws IOException {
2123
return Optional.empty();
2224
}
2325

24-
String xml = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);
26+
byte[] requestBody = exchange.getRequestBody().readAllBytes();
27+
28+
// detect encoding
29+
UniversalDetector detector = new UniversalDetector(null);
30+
detector.handleData(requestBody, 0, requestBody.length);
31+
detector.dataEnd();
32+
String encoding = detector.getDetectedCharset();
33+
detector.reset();
34+
35+
Charset charset = null;
36+
try {
37+
charset = (encoding != null) ? Charset.forName(encoding) : StandardCharsets.UTF_8;
38+
} catch (IllegalArgumentException e) {
39+
logger.severe("Invalid charset: " + encoding);
40+
exchange.sendResponseHeaders(HttpURLConnection.HTTP_BAD_REQUEST, -1);
41+
return Optional.empty();
42+
}
43+
44+
String xml = new String(requestBody, charset);
45+
46+
// Remove BOM if present
47+
if (xml.startsWith("\uFEFF") || xml.startsWith("\uFFFE")) {
48+
xml = xml.substring(1);
49+
}
2550

2651
if (!isXMLValid(xml)) {
2752
logger.severe("Invalid XML content!");

0 commit comments

Comments
 (0)