Skip to content

Commit

Permalink
Add cache control headers for some static payloads (#4326)
Browse files Browse the repository at this point in the history
  • Loading branch information
kbirk authored Aug 1, 2024
1 parent 73320d5 commit 26f8a6e
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,23 @@
@NoArgsConstructor
public class Config {

/** The base url of the deployed application. Eg/ http://localhost:5173 or https://myapp.uncharted.software */
/**
* The base url of the deployed application. Eg/ http://localhost:5173 or
* https://myapp.uncharted.software
*/
String baseUrl;

/** A list of patterns for service requests that can be used via basic auth */
List<String> serviceRequestPatterns;

/**
* A list of unauthenticated {@link org.springframework.util.AntPathMatcher} patterns for urls that should not be
* Max age of the cache headers in seconds.
*/
Integer cacheHeadersMaxAge = 60 * 60 * 24;

/**
* A list of unauthenticated {@link org.springframework.util.AntPathMatcher}
* patterns for urls that should not be
* authenticated via Spring Security
*/
List<String> unauthenticatedUrlPatterns;
Expand All @@ -40,13 +49,19 @@ public class Config {
/** Configuration values that are passed to the client */
ClientConfig clientConfig;

/** If queues should be declared durable. IF running Rabbit inside docker, this should be false */
/**
* If queues should be declared durable. IF running Rabbit inside docker, this
* should be false
*/
Boolean durableQueues = false;

/** The buffer size when uploading large files to the server */
Integer multipartFileBufferSize = 50 * 1024 * 1024;

/** The encryption key used to encrypt the download urls for retrieving files from the server */
/**
* The encryption key used to encrypt the download urls for retrieving files
* from the server
*/
String presignedUrlEncryptionKey;

/** The number of seconds that a presigned url signature is valid for */
Expand Down Expand Up @@ -74,15 +89,21 @@ public class Config {
@Accessors(chain = true)
public static class Caching {

/** If true, clear the cache on startup. Should be false in production environments */
/**
* If true, clear the cache on startup. Should be false in production
* environments
*/
Boolean clearOnStartup;
}

@Data
@Accessors(chain = true)
public static class Keycloak {

/** The url of the keycloak server. eg/ http://localhost:8081 or https://keycloak.uncharted.software */
/**
* The url of the keycloak server. eg/ http://localhost:8081 or
* https://keycloak.uncharted.software
*/
String url;
/** The realm name to use for authentication */
String realm;
Expand All @@ -108,19 +129,26 @@ public static class Keycloak {
@TSModel
public static class ClientConfig implements Serializable {

/** The base url of the deployed application. Mirror of {@link Config#baseUrl} */
/**
* The base url of the deployed application. Mirror of {@link Config#baseUrl}
*/
String baseUrl;

/**
* If true, we will log all client-side errors to the server. This is useful for debugging, but should be false
* If true, we will log all client-side errors to the server. This is useful for
* debugging, but should be false
*/
Boolean clientLogShippingEnabled;

/** The interval, in milliseconds, at which we will ship client-side logs to the server */
/**
* The interval, in milliseconds, at which we will ship client-side logs to the
* server
*/
Long clientLogShippingIntervalMillis;

/**
* The interval, in milliseconds, at which we will send a heartbeat to connected clients for server-side-events
* The interval, in milliseconds, at which we will send a heartbeat to connected
* clients for server-side-events
*/
Long sseHeartbeatIntervalMillis;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
Expand All @@ -32,6 +34,7 @@
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;
import software.uncharted.terarium.hmiserver.configuration.Config;
import software.uncharted.terarium.hmiserver.models.dataservice.Artifact;
import software.uncharted.terarium.hmiserver.models.dataservice.PresignedURL;
import software.uncharted.terarium.hmiserver.models.dataservice.ResponseDeleted;
Expand All @@ -49,6 +52,8 @@
@Transactional
public class ArtifactController {

final Config config;

final ArtifactService artifactService;

final JsDelivrProxy gitHubProxy;
Expand Down Expand Up @@ -352,7 +357,15 @@ public ResponseEntity<byte[]> downloadFile(

try {
final Optional<byte[]> bytes = artifactService.fetchFileAsBytes(artifactId, filename);
return bytes.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());

if (bytes.isEmpty()) {
return ResponseEntity.notFound().build();
}
final CacheControl cacheControl = CacheControl.maxAge(
config.getCacheHeadersMaxAge(),
TimeUnit.SECONDS
).cachePublic();
return ResponseEntity.ok().cacheControl(cacheControl).body(bytes.get());
} catch (final Exception e) {
log.error("Unable to GET artifact data", e);
throw new ResponseStatusException(
Expand Down Expand Up @@ -390,7 +403,10 @@ public ResponseEntity<Integer> uploadFile(
return uploadArtifactHelper(artifactId, filename, fileEntity);
}

/** Downloads a file from GitHub given the path and owner name, then uploads it to the project. */
/**
* Downloads a file from GitHub given the path and owner name, then uploads it
* to the project.
*/
@PutMapping("/{id}/upload-artifact-from-github")
@Secured(Roles.USER)
@Operation(summary = "Uploads a file from GitHub to the artifact")
Expand Down Expand Up @@ -428,8 +444,8 @@ public ResponseEntity<Integer> uploadArtifactFromGithub(
/**
* Uploads an artifact inside the entity to TDS via a presigned URL
*
* @param artifactId The ID of the artifact to upload to
* @param fileName The name of the file to upload
* @param artifactId The ID of the artifact to upload to
* @param fileName The name of the file to upload
* @param artifactHttpEntity The entity containing the artifact to upload
* @return A response containing the status of the upload
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
Expand All @@ -44,6 +46,7 @@
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import software.uncharted.terarium.hmiserver.configuration.Config;
import software.uncharted.terarium.hmiserver.models.dataservice.CsvAsset;
import software.uncharted.terarium.hmiserver.models.dataservice.CsvColumnStats;
import software.uncharted.terarium.hmiserver.models.dataservice.PresignedURL;
Expand All @@ -69,6 +72,8 @@ public class DatasetController {

private static final int DEFAULT_CSV_LIMIT = 100;

final Config config;

final DatasetService datasetService;
final ClimateDataProxy climateDataProxy;

Expand Down Expand Up @@ -364,7 +369,11 @@ public ResponseEntity<CsvAsset> getCsv(
csv.size()
);

return ResponseEntity.ok(csvAsset);
final CacheControl cacheControl = CacheControl.maxAge(
config.getCacheHeadersMaxAge(),
TimeUnit.SECONDS
).cachePublic();
return ResponseEntity.ok().cacheControl(cacheControl).body(csvAsset);
}

@GetMapping("/{id}/download-file")
Expand Down Expand Up @@ -475,7 +484,10 @@ public ResponseEntity<PresignedURL> getDownloadURL(
}
}

/** Downloads a CSV file from github given the path and owner name, then uploads it to the dataset. */
/**
* Downloads a CSV file from github given the path and owner name, then uploads
* it to the dataset.
*/
@PutMapping("/{id}/upload-csv-from-github")
@Secured(Roles.USER)
@Operation(summary = "Uploads a CSV file from github to a dataset")
Expand Down Expand Up @@ -522,10 +534,11 @@ public ResponseEntity<ResponseStatus> uploadCsvFromGithub(
}

/**
* Uploads a CSV file to the dataset. This will grab a presigned URL from TDS then push the file to S3.
* Uploads a CSV file to the dataset. This will grab a presigned URL from TDS
* then push the file to S3.
*
* @param datasetId ID of the dataset to upload t
* @param filename CSV file to upload
* @param filename CSV file to upload
* @return Response
*/
@PutMapping(value = "/{id}/upload-csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
Expand Down Expand Up @@ -675,16 +688,19 @@ public ResponseEntity<PresignedURL> getUploadURL(
}

/**
* Uploads a CSV file to the dataset. This will grab a presigned URL from TDS then push the file to S3 via a
* Uploads a CSV file to the dataset. This will grab a presigned URL from TDS
* then push the file to S3 via a
* presigned URL and update the dataset with the headers.
*
* <p>If the headers fail to update there will be a print to the log, however, the response will just be the status
* <p>
* If the headers fail to update there will be a print to the log, however, the
* response will just be the status
* of the original csv upload.
*
* @param datasetId ID of the dataset to upload to
* @param filename CSV file to upload
* @param filename CSV file to upload
* @param csvEntity CSV file as an HttpEntity
* @param headers headers of the CSV file
* @param headers headers of the CSV file
* @return Response from the upload
*/
private ResponseEntity<ResponseStatus> uploadCSVAndUpdateColumns(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
Expand All @@ -21,6 +22,7 @@
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
Expand All @@ -37,13 +39,12 @@
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;
import software.uncharted.terarium.hmiserver.configuration.Config;
import software.uncharted.terarium.hmiserver.controller.services.DownloadService;
import software.uncharted.terarium.hmiserver.models.dataservice.PresignedURL;
import software.uncharted.terarium.hmiserver.models.dataservice.ResponseDeleted;
import software.uncharted.terarium.hmiserver.models.dataservice.ResponseStatus;
import software.uncharted.terarium.hmiserver.models.dataservice.document.DocumentAsset;
import software.uncharted.terarium.hmiserver.models.dataservice.document.DocumentExtraction;
import software.uncharted.terarium.hmiserver.models.dataservice.document.ExtractionAssetType;
import software.uncharted.terarium.hmiserver.proxies.jsdelivr.JsDelivrProxy;
import software.uncharted.terarium.hmiserver.proxies.skema.SkemaRustProxy;
import software.uncharted.terarium.hmiserver.proxies.skema.SkemaUnifiedProxy;
Expand All @@ -64,6 +65,7 @@
@Transactional
public class DocumentController {

final Config config;
final ReBACService reBACService;
final CurrentUserService currentUserService;
final Messages messages;
Expand Down Expand Up @@ -380,7 +382,7 @@ public ResponseEntity<ResponseDeleted> deleteDocument(
* Uploads an artifact inside the entity to TDS via a presigned URL
*
* @param documentId The ID of the document to upload to
* @param fileName The name of the file to upload
* @param fileName The name of the file to upload
* @param fileEntity The entity containing the file to upload
* @return A response containing the status of the upload
*/
Expand Down Expand Up @@ -453,7 +455,10 @@ public ResponseEntity<Void> uploadDocument(
}
}

/** Downloads a file from GitHub given the path and owner name, then uploads it to the project. */
/**
* Downloads a file from GitHub given the path and owner name, then uploads it
* to the project.
*/
@PutMapping("/{documentId}/upload-document-from-github")
@Secured(Roles.USER)
@Operation(summary = "Uploads a document from github")
Expand Down Expand Up @@ -516,7 +521,14 @@ public ResponseEntity<byte[]> downloadDocument(
) {
try {
final Optional<byte[]> bytes = documentAssetService.fetchFileAsBytes(id, filename);
return bytes.map(ResponseEntity::ok).orElse(null);
if (bytes.isEmpty()) {
return ResponseEntity.notFound().build();
}
final CacheControl cacheControl = CacheControl.maxAge(
config.getCacheHeadersMaxAge(),
TimeUnit.SECONDS
).cachePublic();
return ResponseEntity.ok().cacheControl(cacheControl).body(bytes.get());
} catch (final Exception e) {
final String error = "Unable to download document";
log.error(error, e);
Expand Down Expand Up @@ -564,7 +576,7 @@ public ResponseEntity<String> getDocumentFileAsText(
* Post Images to Equations Unified service to get an AMR
*
* @param documentId document id
* @param filename filename of the image
* @param filename filename of the image
* @return LaTeX representation of the equation
*/
@GetMapping("/{id}/image-to-equation")
Expand Down Expand Up @@ -617,11 +629,12 @@ public ResponseEntity<String> postImageToEquation(
}

/**
* Uploads a PDF file to a document asset and then fires and forgets the extraction
* Uploads a PDF file to a document asset and then fires and forgets the
* extraction
*
* @param doi DOI of the document
* @param doi DOI of the document
* @param filename filename of the PDF
* @param docId document id
* @param docId document id
* @return extraction job id
*/
private void uploadPDFFileToDocumentThenExtract(
Expand Down
Loading

0 comments on commit 26f8a6e

Please sign in to comment.