diff --git a/src/main/java/net/sourceforge/plantuml/servlet/AsciiCoderServlet.java b/src/main/java/net/sourceforge/plantuml/servlet/AsciiCoderServlet.java
new file mode 100644
index 0000000..bcff40a
--- /dev/null
+++ b/src/main/java/net/sourceforge/plantuml/servlet/AsciiCoderServlet.java
@@ -0,0 +1,151 @@
+/* ========================================================================
+ * PlantUML : a free UML diagram generator
+ * ========================================================================
+ *
+ * Project Info: https://plantuml.com
+ *
+ * This file is part of PlantUML.
+ *
+ * PlantUML is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * PlantUML distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+package net.sourceforge.plantuml.servlet;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import net.sourceforge.plantuml.code.Transcoder;
+import net.sourceforge.plantuml.code.TranscoderUtil;
+import net.sourceforge.plantuml.servlet.utility.UrlDataExtractor;
+
+/**
+ * ASCII encoder and decoder servlet for the webapp.
+ * This servlet encodes the diagram in text format or decodes the compressed diagram string.
+ */
+@SuppressWarnings("SERIAL")
+public class AsciiCoderServlet extends HttpServlet {
+
+ /**
+ * Regex pattern to fetch last part of the URL.
+ */
+ private static final Pattern URL_PATTERN = Pattern.compile("^.*[^a-zA-Z0-9\\-\\_]([a-zA-Z0-9\\-\\_]+)");
+
+ /**
+ * Context path from the servlet mapping URL pattern.
+ *
+ * @return servlet context path without leading or tailing slash
+ */
+ protected String getServletContextPath() {
+ return "coder";
+ }
+
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
+ request.setCharacterEncoding("UTF-8");
+
+ final String encodedText = getEncodedTextFromUrl(request);
+
+ String text = "";
+ try {
+ text = getTranscoder().decode(encodedText);
+ } catch (Exception e) {
+ response.setStatus(500);
+ e.printStackTrace();
+ }
+
+ response.addHeader("Access-Control-Allow-Origin", "*");
+ response.setContentType("text/plain;charset=UTF-8");
+ response.getWriter().write(text);
+ }
+
+ @Override
+ protected void doPost(
+ HttpServletRequest request,
+ HttpServletResponse response
+ ) throws ServletException, IOException {
+ request.setCharacterEncoding("UTF-8");
+
+ // read textual diagram source from request body
+ final StringBuilder uml = new StringBuilder();
+ try (BufferedReader in = request.getReader()) {
+ String line;
+ while ((line = in.readLine()) != null) {
+ uml.append(line).append('\n');
+ }
+ }
+
+ // encode textual diagram source
+ String encoded = "";
+ try {
+ encoded = getTranscoder().encode(uml.toString());
+ } catch (Exception e) {
+ response.setStatus(500);
+ e.printStackTrace();
+ }
+
+ response.addHeader("Access-Control-Allow-Origin", "*");
+ response.setContentType("text/plain;charset=UTF-8");
+ response.getWriter().write(encoded);
+ }
+
+ /**
+ * Get PlantUML transcoder.
+ *
+ * @return transcoder instance
+ */
+ protected Transcoder getTranscoder() {
+ return TranscoderUtil.getDefaultTranscoder();
+ }
+
+ /**
+ * Get encoded textual diagram source from URL.
+ *
+ * @param request http request which contains the source URL
+ *
+ * @return if successful encoded textual diagram source from URL; otherwise empty string
+ *
+ * @throws IOException if an input or output exception occurred
+ */
+ protected String getEncodedTextFromUrl(HttpServletRequest request) throws IOException {
+ // textual diagram source from request URI
+ String url = request.getRequestURI();
+ final String contextpath = "/" + getServletContextPath() + "/";
+ if (url.contains(contextpath) && !url.endsWith(contextpath)) {
+ final String encoded = UrlDataExtractor.getEncodedDiagram(request.getRequestURI(), "");
+ if (!encoded.isEmpty()) {
+ return encoded;
+ }
+ }
+ // textual diagram source from "url" parameter
+ url = request.getParameter("url");
+ if (url != null && !url.trim().isEmpty()) {
+ // Catch the last part of the URL if necessary
+ final Matcher matcher = URL_PATTERN.matcher(url);
+ if (matcher.find()) {
+ url = matcher.group(1);
+ }
+ return url;
+ }
+ // nothing found
+ return "";
+ }
+
+}
diff --git a/src/main/java/net/sourceforge/plantuml/servlet/PlantUmlServlet.java b/src/main/java/net/sourceforge/plantuml/servlet/PlantUmlServlet.java
index 1444a0b..123067e 100644
--- a/src/main/java/net/sourceforge/plantuml/servlet/PlantUmlServlet.java
+++ b/src/main/java/net/sourceforge/plantuml/servlet/PlantUmlServlet.java
@@ -27,21 +27,15 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
import javax.net.ssl.HttpsURLConnection;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
-import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import net.sourceforge.plantuml.OptionFlags;
import net.sourceforge.plantuml.api.PlantumlUtils;
-import net.sourceforge.plantuml.code.Transcoder;
-import net.sourceforge.plantuml.code.TranscoderUtil;
import net.sourceforge.plantuml.png.MetadataTag;
import net.sourceforge.plantuml.servlet.utility.Configuration;
import net.sourceforge.plantuml.servlet.utility.UmlExtractor;
@@ -58,7 +52,7 @@ import net.sourceforge.plantuml.servlet.utility.UrlDataExtractor;
* Modified by Maxime Sinclair
*/
@SuppressWarnings("SERIAL")
-public class PlantUmlServlet extends HttpServlet {
+public class PlantUmlServlet extends AsciiCoderServlet {
/**
* Default encoded uml text.
@@ -66,10 +60,10 @@ public class PlantUmlServlet extends HttpServlet {
*/
private static final String DEFAULT_ENCODED_TEXT = "SyfFKj2rKt3CoKnELR1Io4ZDoSa70000";
- /**
- * Regex pattern to fetch last part of the URL.
- */
- private static final Pattern URL_PATTERN = Pattern.compile("^.*[^a-zA-Z0-9\\-\\_]([a-zA-Z0-9\\-\\_]+)");
+ @Override
+ protected String getServletContextPath() {
+ return "uml";
+ }
static {
OptionFlags.ALLOW_INCLUDE = false;
@@ -78,11 +72,19 @@ public class PlantUmlServlet extends HttpServlet {
}
}
+ /**
+ * Encode arbitrary string to HTML string.
+ *
+ * @param string arbitrary string
+ *
+ * @return html encoded string
+ */
public static String stringToHTMLString(String string) {
- final StringBuffer sb = new StringBuffer(string.length());
+ final StringBuilder sb = new StringBuilder(string.length());
// true if last char was blank
final int length = string.length();
- for (int offset = 0; offset < length;) {
+ int offset = 0;
+ while (offset < length) {
final int c = string.codePointAt(offset);
if (c == ' ') {
sb.append(' ');
@@ -115,7 +117,6 @@ public class PlantUmlServlet extends HttpServlet {
return sb.toString();
}
-
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
@@ -215,26 +216,7 @@ public class PlantUmlServlet extends HttpServlet {
* @throws IOException if an input or output exception occurred
*/
private String getTextFromUrl(HttpServletRequest request) throws IOException {
- // textual diagram source from request URI
- String url = request.getRequestURI();
- if (url.contains("/uml/") && !url.endsWith("/uml/")) {
- final String encoded = UrlDataExtractor.getEncodedDiagram(request.getRequestURI(), "");
- if (!encoded.isEmpty()) {
- return getTranscoder().decode(encoded);
- }
- }
- // textual diagram source from "url" parameter
- url = request.getParameter("url");
- if (url != null && !url.trim().isEmpty()) {
- // Catch the last part of the URL if necessary
- final Matcher matcher = URL_PATTERN.matcher(url);
- if (matcher.find()) {
- url = matcher.group(1);
- }
- return getTranscoder().decode(url);
- }
- // nothing found
- return "";
+ return getTranscoder().decode(getEncodedTextFromUrl(request));
}
/**
@@ -318,15 +300,6 @@ public class PlantUmlServlet extends HttpServlet {
response.sendRedirect(path);
}
- /**
- * Get PlantUML transcoder.
- *
- * @return transcoder instance
- */
- private Transcoder getTranscoder() {
- return TranscoderUtil.getDefaultTranscoder();
- }
-
/**
* Get open http connection from URL.
*
@@ -341,7 +314,6 @@ public class PlantUmlServlet extends HttpServlet {
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setReadTimeout(10000); // 10 seconds
- // printHttpsCert(con);
con.connect();
return con;
} else {
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
index bcdef3d..9d5ea77 100644
--- a/src/main/webapp/WEB-INF/web.xml
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -201,6 +201,15 @@
/language
+
+ asciicoder
+ net.sourceforge.plantuml.servlet.AsciiCoderServlet
+
+
+ asciicoder
+ /coder/*
+
+
diff --git a/src/test/java/net/sourceforge/plantuml/servlet/TestAsciiCoder.java b/src/test/java/net/sourceforge/plantuml/servlet/TestAsciiCoder.java
new file mode 100644
index 0000000..8a6c6c7
--- /dev/null
+++ b/src/test/java/net/sourceforge/plantuml/servlet/TestAsciiCoder.java
@@ -0,0 +1,61 @@
+package net.sourceforge.plantuml.servlet;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+
+
+public class TestAsciiCoder extends WebappTestCase {
+
+ /**
+ * Verifies the decoding for the Bob -> Alice sample
+ */
+ public void testBobAliceSampleDiagramDecoding() throws IOException {
+ final URL url = new URL(getServerUrl() + "/coder/" + TestUtils.SEQBOB);
+ final URLConnection conn = url.openConnection();
+ // Analyze response
+ // Verifies the Content-Type header
+ assertEquals(
+ "Response content type is not TEXT PLAIN or UTF-8",
+ "text/plain;charset=utf-8",
+ conn.getContentType().toLowerCase()
+ );
+ // Get and verify the content
+ final String diagram = getContentText(conn);
+ assertEquals(TestUtils.SEQBOBCODE, diagram);
+ }
+
+ /**
+ * Verifies the encoding for the Bob -> Alice sample
+ */
+ public void testBobAliceSampleDiagramEncoding() throws IOException {
+ final URL url = new URL(getServerUrl() + "/coder");
+ final HttpURLConnection conn = (HttpURLConnection)url.openConnection();
+ conn.setRequestMethod("POST");
+ conn.setDoOutput(true);
+ conn.setRequestProperty("Content-type", "text/plain");
+ try (final OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream())) {
+ writer.write(TestUtils.SEQBOBCODE);
+ writer.flush();
+ }
+ // Analyze response
+ // HTTP response 200
+ assertEquals(
+ "Bad HTTP status received",
+ 200,
+ conn.getResponseCode()
+ );
+ // Verifies the Content-Type header
+ assertEquals(
+ "Response content type is not TEXT PLAIN or UTF-8",
+ "text/plain;charset=utf-8",
+ conn.getContentType().toLowerCase()
+ );
+ // Get the content and verify its size
+ final String diagram = getContentText(conn.getInputStream());
+ assertEquals(TestUtils.SEQBOB, diagram);
+ }
+
+}
diff --git a/src/test/java/net/sourceforge/plantuml/servlet/TestForm.java b/src/test/java/net/sourceforge/plantuml/servlet/TestForm.java
index 894ecd1..ba54846 100644
--- a/src/test/java/net/sourceforge/plantuml/servlet/TestForm.java
+++ b/src/test/java/net/sourceforge/plantuml/servlet/TestForm.java
@@ -28,7 +28,7 @@ public class TestForm extends WebappTestCase {
assertEquals(2, forms.size());
// Ensure the Text field is correct
String text = ((HtmlTextArea)(forms.get(0).getFirstByXPath("//textarea[contains(@name, 'text')]"))).getTextContent();
- assertEquals("@startuml\nBob -> Alice : hello\n@enduml", text);
+ assertEquals(TestUtils.SEQBOBCODE, text);
// Ensure the URL field is correct
HtmlInput url = forms.get(1).getInputByName("url");
assertNotNull(url);
@@ -57,7 +57,7 @@ public class TestForm extends WebappTestCase {
assertEquals(2, forms.size());
// Ensure the Text field is correct
String text = ((HtmlTextArea)(forms.get(0).getFirstByXPath("//textarea[contains(@name, 'text')]"))).getTextContent();
- assertEquals("@startuml\nversion\n@enduml", text);
+ assertEquals(TestUtils.VERSIONCODE, text);
// Ensure the URL field is correct
HtmlInput url = forms.get(1).getInputByName("url");
assertNotNull(url);
@@ -86,7 +86,7 @@ public class TestForm extends WebappTestCase {
assertEquals(2, forms.size());
// Ensure the Text field is correct
String text = ((HtmlTextArea)(forms.get(0).getFirstByXPath("//textarea[contains(@name, 'text')]"))).getTextContent();
- assertEquals("@startuml\nBob -> Alice : hello\n@enduml", text);
+ assertEquals(TestUtils.SEQBOBCODE, text);
// Ensure the URL field is correct
HtmlInput url = forms.get(1).getInputByName("url");
assertNotNull(url);
@@ -116,7 +116,7 @@ public class TestForm extends WebappTestCase {
assertEquals(2, forms.size());
// Ensure the Text field is correct
String text = ((HtmlTextArea)(forms.get(0).getFirstByXPath("//textarea[contains(@name, 'text')]"))).getTextContent();
- assertEquals("@startuml\nBob -> Alice : hello\n@enduml", text);
+ assertEquals(TestUtils.SEQBOBCODE, text);
// Ensure the URL field is correct
url = forms.get(1).getInputByName("url");
assertNotNull(url);
@@ -204,7 +204,7 @@ public class TestForm extends WebappTestCase {
assertEquals(2, forms.size());
// Ensure the Text field is correct
String text = ((HtmlTextArea)(forms.get(0).getFirstByXPath("//textarea[contains(@name, 'text')]"))).getTextContent();
- assertEquals("@startuml\nBob -> Alice : hello\n@enduml", text);
+ assertEquals(TestUtils.SEQBOBCODE, text);
// Ensure the URL field is correct
HtmlInput url = forms.get(1).getInputByName("url");
assertNotNull(url);
diff --git a/src/test/java/net/sourceforge/plantuml/servlet/TestUtils.java b/src/test/java/net/sourceforge/plantuml/servlet/TestUtils.java
index b66e85e..6257793 100644
--- a/src/test/java/net/sourceforge/plantuml/servlet/TestUtils.java
+++ b/src/test/java/net/sourceforge/plantuml/servlet/TestUtils.java
@@ -15,9 +15,19 @@ public abstract class TestUtils {
*/
public static final String VERSION = "AqijAixCpmC0";
+ /**
+ * version
+ */
+ public static final String VERSIONCODE = "@startuml\nversion\n@enduml";
+
/**
* Bob -> Alice : hello
*/
public static final String SEQBOB = "SyfFKj2rKt3CoKnELR1Io4ZDoSa70000";
+ /**
+ * Bob -> Alice : hello
+ */
+ public static final String SEQBOBCODE = "@startuml\nBob -> Alice : hello\n@enduml";
+
}