Browse Source

Optimized website serving, and added code to return the correct content types.

This is probably the most efficient way to process the data on the fly, but it's still not very scalable. A better approach would be to pre-process the HTML when building the file structure, and then serve them completely statically (i.e. using a standard webserver rather than via application memory). But it makes sense to keep it this way for development and maybe early beta testing.
qdn
CalDescent 3 years ago
parent
commit
b286c15c51
  1. 64
      src/main/java/org/qortal/api/resource/WebsiteResource.java

64
src/main/java/org/qortal/api/resource/WebsiteResource.java

@ -1,15 +1,15 @@
package org.qortal.api.resource; package org.qortal.api.resource;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import java.io.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
@ -41,8 +41,9 @@ public class WebsiteResource {
private static final Logger LOGGER = LogManager.getLogger(WebsiteResource.class); private static final Logger LOGGER = LogManager.getLogger(WebsiteResource.class);
@Context @Context HttpServletRequest request;
HttpServletRequest request; @Context HttpServletResponse response;
@Context ServletContext context;
@POST @POST
@Path("/upload") @Path("/upload")
@ -179,17 +180,17 @@ public class WebsiteResource {
@GET @GET
@Path("{resource}") @Path("{resource}")
public Response getResourceIndex(@PathParam("resource") String resourceId) { public HttpServletResponse getResourceIndex(@PathParam("resource") String resourceId) {
return this.get(resourceId, "/"); return this.get(resourceId, "/");
} }
@GET @GET
@Path("{resource}/{path:.*}") @Path("{resource}/{path:.*}")
public Response getResourcePath(@PathParam("resource") String resourceId, @PathParam("path") String inPath) { public HttpServletResponse getResourcePath(@PathParam("resource") String resourceId, @PathParam("path") String inPath) {
return this.get(resourceId, inPath); return this.get(resourceId, inPath);
} }
private Response get(String resourceId, String inPath) { private HttpServletResponse get(String resourceId, String inPath) {
if (!inPath.startsWith(File.separator)) { if (!inPath.startsWith(File.separator)) {
inPath = File.separator + inPath; inPath = File.separator + inPath;
} }
@ -204,14 +205,14 @@ public class WebsiteResource {
DataFile dataFile = DataFile.fromBase58Digest(resourceId); DataFile dataFile = DataFile.fromBase58Digest(resourceId);
if (dataFile == null || !dataFile.exists()) { if (dataFile == null || !dataFile.exists()) {
LOGGER.info("Unable to validate complete file hash"); LOGGER.info("Unable to validate complete file hash");
return Response.serverError().build(); return this.get404Response();
} }
String newHash = dataFile.base58Digest(); String newHash = dataFile.base58Digest();
LOGGER.info("newHash: {}", newHash); LOGGER.info("newHash: {}", newHash);
if (!dataFile.base58Digest().equals(resourceId)) { if (!dataFile.base58Digest().equals(resourceId)) {
LOGGER.info("Unable to validate complete file hash"); LOGGER.info("Unable to validate complete file hash");
return Response.serverError().build(); return this.get404Response();
} }
try { try {
@ -223,14 +224,36 @@ public class WebsiteResource {
try { try {
String filename = this.getFilename(unzippedPath, inPath); String filename = this.getFilename(unzippedPath, inPath);
byte[] data = Files.readAllBytes(Paths.get(unzippedPath + File.separator + filename)); // TODO: limit file size that can be read into memory String filePath = unzippedPath + File.separator + filename;
data = this.replaceRelativeLinks(filename, data, resourceId);
return Response.ok(data).build(); if (this.isHtmlFile(filename)) {
// HTML file - needs to be parsed
byte[] data = Files.readAllBytes(Paths.get(filePath)); // TODO: limit file size that can be read into memory
data = this.replaceRelativeLinks(filename, data, resourceId);
response.setContentType(context.getMimeType(filename));
response.setContentLength(data.length);
response.getOutputStream().write(data);
}
else {
// Regular file - can be streamed directly
File file = new File(filePath);
FileInputStream inputStream = new FileInputStream(file);
response.setContentType(context.getMimeType(filename));
int bytesRead, length = 0;
byte[] buffer = new byte[1024];
while ((bytesRead = inputStream.read(buffer)) != -1) {
response.getOutputStream().write(buffer, 0, bytesRead);
length += bytesRead;
}
response.setContentLength(length);
inputStream.close();
}
return response;
} catch (IOException e) { } catch (IOException e) {
LOGGER.info("Unable to serve file at path: {}", inPath); LOGGER.info("Unable to serve file at path: {}", inPath);
} }
return Response.serverError().build(); return this.get404Response();
} }
private String getFilename(String directory, String userPath) { private String getFilename(String directory, String userPath) {
@ -247,6 +270,19 @@ public class WebsiteResource {
return userPath; return userPath;
} }
private HttpServletResponse get404Response() {
try {
String responseString = "404: File Not Found";
byte[] responseData = responseString.getBytes();
response.setStatus(404);
response.setContentLength(responseData.length);
response.getOutputStream().write(responseData);
} catch (IOException e) {
LOGGER.info("Error writing 404 response");
}
return response;
}
/** /**
* Find relative links and prefix them with the resource ID, using Jsoup * Find relative links and prefix them with the resource ID, using Jsoup
* @param path * @param path

Loading…
Cancel
Save