Code server: fix preflight request issues

This commit is contained in:
Alexey Andreev 2022-02-10 19:35:14 +03:00
parent 1c04cd2ba6
commit 8d02dc0f4a

View File

@ -312,10 +312,12 @@ public class CodeServlet extends HttpServlet {
if (!path.startsWith("/")) { if (!path.startsWith("/")) {
path = "/" + path; path = "/" + path;
} }
if (req.getMethod().equals("GET") && path.startsWith(pathToFile) && path.length() > pathToFile.length()) { if ((req.getMethod().equals("GET") || req.getMethod().equals("OPTIONS"))
&& path.startsWith(pathToFile) && path.length() > pathToFile.length()) {
boolean hasBody = req.getMethod().equals("GET");
String fileName = path.substring(pathToFile.length()); String fileName = path.substring(pathToFile.length());
if (fileName.startsWith("src/")) { if (fileName.startsWith("src/")) {
if (serveSourceFile(fileName.substring("src/".length()), resp)) { if (serveSourceFile(fileName.substring("src/".length()), req, resp, hasBody)) {
log.debug("File " + path + " served as source file"); log.debug("File " + path + " served as source file");
return; return;
} }
@ -326,7 +328,7 @@ public class CodeServlet extends HttpServlet {
} }
} }
} else if (path.equals(deobfuscatorPath)) { } else if (path.equals(deobfuscatorPath)) {
serveDeobfuscator(resp); serveDeobfuscator(req, resp, hasBody);
return; return;
} else { } else {
byte[] fileContent; byte[] fileContent;
@ -336,17 +338,21 @@ public class CodeServlet extends HttpServlet {
firstTime = this.firstTime; firstTime = this.firstTime;
} }
if (fileContent != null) { if (fileContent != null) {
resp.setStatus(HttpServletResponse.SC_OK); resp.setStatus(hasBody ? HttpServletResponse.SC_OK : HttpServletResponse.SC_NO_CONTENT);
resp.setCharacterEncoding("UTF-8"); resp.setCharacterEncoding("UTF-8");
resp.setHeader("Access-Control-Allow-Origin", "*"); allowOrigin(req, resp);
resp.setContentType(chooseContentType(fileName)); if (!hasBody) {
noCache(resp); resp.setHeader("Access-Control-Allow-Methods", "GET");
resp.getOutputStream().write(fileContent); } else {
resp.setContentType(chooseContentType(fileName));
noCache(resp);
resp.getOutputStream().write(fileContent);
}
resp.getOutputStream().flush(); resp.getOutputStream().flush();
log.debug("File " + path + " served as generated file"); log.debug("File " + path + " served as generated file");
return; return;
} else if (fileName.equals(this.fileName) && indicator && firstTime) { } else if (fileName.equals(this.fileName) && indicator && firstTime) {
serveBootFile(resp); serveBootFile(req, resp, hasBody);
return; return;
} }
} }
@ -378,14 +384,20 @@ public class CodeServlet extends HttpServlet {
} }
} }
private void serveDeobfuscator(HttpServletResponse resp) throws IOException { private void serveDeobfuscator(HttpServletRequest req, HttpServletResponse resp, boolean hasBody)
throws IOException {
ClassLoader loader = CodeServlet.class.getClassLoader(); ClassLoader loader = CodeServlet.class.getClassLoader();
resp.setStatus(HttpServletResponse.SC_OK); resp.setStatus(hasBody ? HttpServletResponse.SC_OK : HttpServletResponse.SC_NO_CONTENT);
resp.setCharacterEncoding("UTF-8"); allowOrigin(req, resp);
resp.setContentType("application/javascript"); if (!hasBody) {
noCache(resp); resp.setHeader("Access-Control-Allow-Methods", "GET");
try (InputStream input = loader.getResourceAsStream("teavm/devserver/deobfuscator.js")) { } else {
IOUtils.copy(input, resp.getOutputStream()); resp.setCharacterEncoding("UTF-8");
resp.setContentType("application/javascript");
noCache(resp);
try (InputStream input = loader.getResourceAsStream("teavm/devserver/deobfuscator.js")) {
IOUtils.copy(input, resp.getOutputStream());
}
} }
resp.getOutputStream().flush(); resp.getOutputStream().flush();
} }
@ -620,17 +632,23 @@ public class CodeServlet extends HttpServlet {
buildThread = thread; buildThread = thread;
} }
private boolean serveSourceFile(String fileName, HttpServletResponse resp) throws IOException { private boolean serveSourceFile(String fileName, HttpServletRequest req, HttpServletResponse resp,
boolean hasBody) throws IOException {
try (InputStream stream = sourceFileCache.computeIfAbsent(fileName, this::findSourceFile).get()) { try (InputStream stream = sourceFileCache.computeIfAbsent(fileName, this::findSourceFile).get()) {
if (stream == null) { if (stream == null) {
return false; return false;
} }
resp.setStatus(HttpServletResponse.SC_OK); resp.setStatus(hasBody ? HttpServletResponse.SC_OK : HttpServletResponse.SC_NO_CONTENT);
resp.setCharacterEncoding("UTF-8"); resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/plain"); allowOrigin(req, resp);
noCache(resp); if (!hasBody) {
IOUtils.copy(stream, resp.getOutputStream()); resp.setHeader("Access-Control-Allow-Methods", "GET");
} else {
resp.setContentType("text/plain");
noCache(resp);
IOUtils.copy(stream, resp.getOutputStream());
}
resp.getOutputStream().flush(); resp.getOutputStream().flush();
return true; return true;
} }
@ -688,12 +706,18 @@ public class CodeServlet extends HttpServlet {
} }
} }
private void serveBootFile(HttpServletResponse resp) throws IOException { private void serveBootFile(HttpServletRequest req, HttpServletResponse resp, boolean hasBody) throws IOException {
resp.setStatus(HttpServletResponse.SC_OK); resp.setStatus(hasBody ? HttpServletResponse.SC_OK : HttpServletResponse.SC_NO_CONTENT);
resp.setCharacterEncoding("UTF-8"); resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/plain"); allowOrigin(req, resp);
resp.getWriter().write("function main() { }\n"); if (!hasBody) {
resp.getWriter().write(getIndicatorScript(true)); resp.setHeader("Access-Control-Allow-Methods", "GET");
} else {
resp.setContentType("text/plain");
noCache(resp);
resp.getWriter().write("function main() { }\n");
resp.getWriter().write(getIndicatorScript(true));
}
resp.getWriter().flush(); resp.getWriter().flush();
log.debug("Served boot file"); log.debug("Served boot file");
} }
@ -1117,4 +1141,16 @@ public class CodeServlet extends HttpServlet {
static void noCache(HttpServletResponse response) { static void noCache(HttpServletResponse response) {
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
} }
static void allowOrigin(HttpServletRequest req, HttpServletResponse resp) {
String origin = req.getHeader("Origin");
if (origin != null) {
resp.setHeader("Access-Control-Allow-Origin", origin);
resp.setHeader("Vary", "Origin");
} else {
resp.setHeader("Access-Control-Allow-Origin", "*");
}
resp.setHeader("Access-Control-Allow-Credentials", "true");
resp.setHeader("Access-Control-Allow-Private-Network", "true");
}
} }