Skip to content

Commit

Permalink
add servlet to encode and decode diagrams
Browse files Browse the repository at this point in the history
.
  • Loading branch information
Florian authored and arnaudroques committed Apr 18, 2023
1 parent 3ef176e commit 763976a
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 49 deletions.
151 changes: 151 additions & 0 deletions src/main/java/net/sourceforge/plantuml/servlet/AsciiCoderServlet.java
Original file line number Diff line number Diff line change
@@ -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 "";
}

}
60 changes: 16 additions & 44 deletions src/main/java/net/sourceforge/plantuml/servlet/PlantUmlServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,15 @@
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;
Expand All @@ -58,18 +52,18 @@
* Modified by Maxime Sinclair
*/
@SuppressWarnings("SERIAL")
public class PlantUmlServlet extends HttpServlet {
public class PlantUmlServlet extends AsciiCoderServlet {

/**
* Default encoded uml text.
* Bob -> Alice : hello
*/
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;
Expand All @@ -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(' ');
Expand Down Expand Up @@ -115,7 +117,6 @@ public static String stringToHTMLString(String string) {
return sb.toString();
}


@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
Expand Down Expand Up @@ -215,26 +216,7 @@ private String getText(final HttpServletRequest request) throws IOException {
* @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));
}

/**
Expand Down Expand Up @@ -318,15 +300,6 @@ private void redirectNow(
response.sendRedirect(path);
}

/**
* Get PlantUML transcoder.
*
* @return transcoder instance
*/
private Transcoder getTranscoder() {
return TranscoderUtil.getDefaultTranscoder();
}

/**
* Get open http connection from URL.
*
Expand All @@ -341,7 +314,6 @@ private static HttpURLConnection getConnection(URL url) throws IOException {
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setReadTimeout(10000); // 10 seconds
// printHttpsCert(con);
con.connect();
return con;
} else {
Expand Down
9 changes: 9 additions & 0 deletions src/main/webapp/WEB-INF/web.xml
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,15 @@
<url-pattern>/language</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>asciicoder</servlet-name>
<servlet-class>net.sourceforge.plantuml.servlet.AsciiCoderServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>asciicoder</servlet-name>
<url-pattern>/coder/*</url-pattern>
</servlet-mapping>


<!-- ========================================================== -->
<!-- Error Handler -->
Expand Down
61 changes: 61 additions & 0 deletions src/test/java/net/sourceforge/plantuml/servlet/TestAsciiCoder.java
Original file line number Diff line number Diff line change
@@ -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);
}

}
Loading

0 comments on commit 763976a

Please sign in to comment.