-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathHtmlPdfPlusJavaClient.java
More file actions
146 lines (134 loc) · 6.67 KB
/
Copy pathHtmlPdfPlusJavaClient.java
File metadata and controls
146 lines (134 loc) · 6.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// ***************************************************************************************
// MIT LICENCE
// The maintenance and evolution is maintained by the HtmlPdfPlus team
// https://github.com/FRACerqueira/HtmlPdfPlus
// ***************************************************************************************
//
// Minimal Java client for the HtmlPdfPlus server - no build tool, no dependency beyond the
// JDK itself (java.net.http.HttpClient + java.util.zip.GZIPOutputStream). The point of this
// sample is to show the exact wire format any non-.NET client must produce, not to be a
// polished library - a real integration would likely use a JSON library instead of the
// hand-rolled escaping below.
//
// Wire format (see HtmlPdfEndpointExtensions.MapHtmlPdfEndpoints and
// HtmlPdfClientInstance.CreateHttpContent on the .NET side for the authoritative version):
// 1) Build the request as JSON: {"Html":"...","Alias":"...","Config":null,
// "Timeout":30000,"InputParam":null,"Mode":0,"SentAtUtc":null}
// - Config:null lets the server fall back to its own configured page defaults.
// - Mode is the RenderMode enum's underlying int: 0 = Html, 1 = Url.
// 2) gzip-compress the UTF-8 JSON bytes (standard RFC 1952 gzip - interoperable with
// .NET's GZipStream, no custom framing).
// 3) POST the gzip bytes directly as the HTTP body with
// Content-Type: application/octet-stream - no base64, no extra JSON-string wrapping.
// 4) A 200 response with Content-Type: application/pdf is the raw PDF bytes.
// A non-2xx response is a JSON ErrorInfo body ({"code":...,"message":...}).
//
// Run the server first with the plain-HTTP profile so there's no TLS dev-certificate trust
// to set up across runtimes:
// dotnet run --project samples/WebHtmlToPdf.GenericServer --launch-profile http
// (the server logs a harmless "Failed to determine the https port for redirect" warning on
// this profile - UseHttpsRedirection has no HTTPS endpoint to redirect to and no-ops; the
// request below still gets a normal response)
//
// Then compile and run this file (JDK 17+, for the text block below):
// javac HtmlPdfPlusJavaClient.java
// java HtmlPdfPlusJavaClient
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.GZIPOutputStream;
public class HtmlPdfPlusJavaClient {
private static final String SERVER_URL = "http://localhost:5042/GeneratePdf";
public static void main(String[] args) throws IOException, InterruptedException {
System.out.println("Example: minimal Java client for HtmlPdfPlus - hand-built wire format, no JSON/HTTP dependency beyond the JDK");
System.out.println("Start the WebHtmlToPdf.GenericServer sample with the http profile first (see the header comment), then press Enter.");
System.in.read();
String html = htmlSample();
String requestJson = buildRequestJson(html, "java-client-sample", 30000);
byte[] compressed = gzip(requestJson.getBytes(StandardCharsets.UTF_8));
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(SERVER_URL))
.header("Content-Type", "application/octet-stream")
.POST(HttpRequest.BodyPublishers.ofByteArray(compressed))
.build();
HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
String contentType = response.headers().firstValue("Content-Type").orElse("");
if (response.statusCode() == 200 && contentType.startsWith("application/pdf")) {
Path outputPath = Path.of(System.getProperty("user.home"), "Desktop", "html2pdf-java.pdf");
Files.write(outputPath, response.body());
System.out.println("File PDF generated at " + outputPath);
} else {
// A real client would parse this JSON ErrorInfo body with a JSON library; printed
// raw here to keep this sample dependency-free.
System.out.println("HtmlPdfPlus error (HTTP " + response.statusCode() + "): "
+ new String(response.body(), StandardCharsets.UTF_8));
}
}
private static String buildRequestJson(String html, String alias, int timeoutMs) {
return "{"
+ "\"Html\":\"" + escapeJson(html) + "\","
+ "\"Alias\":\"" + escapeJson(alias) + "\","
+ "\"Config\":null,"
+ "\"Timeout\":" + timeoutMs + ","
+ "\"InputParam\":null,"
+ "\"Mode\":0,"
+ "\"SentAtUtc\":null"
+ "}";
}
private static String escapeJson(String value) {
StringBuilder sb = new StringBuilder(value.length());
for (int i = 0; i < value.length(); i++) {
char c = value.charAt(i);
switch (c) {
case '"' -> sb.append("\\\"");
case '\\' -> sb.append("\\\\");
case '\n' -> sb.append("\\n");
case '\r' -> sb.append("\\r");
case '\t' -> sb.append("\\t");
default -> {
if (c < 0x20) {
sb.append(String.format("\\u%04x", (int) c));
} else {
sb.append(c);
}
}
}
}
return sb.toString();
}
private static byte[] gzip(byte[] data) throws IOException {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
try (GZIPOutputStream gzipStream = new GZIPOutputStream(byteStream)) {
gzipStream.write(data);
}
return byteStream.toByteArray();
}
private static String htmlSample() {
return """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HtmlPdfPlus Java Client</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
h1 { color: #4682b4; }
</style>
</head>
<body>
<h1>Generated from a Java client</h1>
<p>This PDF was produced by HtmlPdfPlusJavaClient.java, a dependency-free
demonstration of the HtmlPdfPlus wire format - no .NET runtime involved on
the client side.</p>
</body>
</html>
""";
}
}