diff --git a/src/main/java/cz/cvut/kbss/termit/rest/TermController.java b/src/main/java/cz/cvut/kbss/termit/rest/TermController.java index 3b03799f..84d68322 100644 --- a/src/main/java/cz/cvut/kbss/termit/rest/TermController.java +++ b/src/main/java/cz/cvut/kbss/termit/rest/TermController.java @@ -124,8 +124,8 @@ private Optional> exportTerms(Vocabulary vocabulary, ExportTyp .contentLength(r.contentLength()) .contentType(MediaType.parseMediaType(mediaType)) .header(HttpHeaders.CONTENT_DISPOSITION, - "attachment; filename=\"" + IdentifierResolver.extractIdentifierFragment( - vocabulary.getUri()) + + "attachment; filename=\"" + IdentifierResolver.normalizeToAscii(IdentifierResolver.extractIdentifierFragment( + vocabulary.getUri())) + r.getFileExtension().orElse("") + "\"") .body(r); } catch (IOException e) { @@ -202,9 +202,9 @@ public List getAllRoots(@PathVariable String vocabularyIdFragment, defaultValue = "") List includeTerms) { final Vocabulary vocabulary = getVocabulary(getVocabularyUri(namespace, vocabularyIdFragment)); return includeImported ? - termService - .findAllRootsIncludingImported(vocabulary, createPageRequest(pageSize, pageNo), includeTerms) : - termService.findAllRoots(vocabulary, createPageRequest(pageSize, pageNo), includeTerms); + termService + .findAllRootsIncludingImported(vocabulary, createPageRequest(pageSize, pageNo), includeTerms) : + termService.findAllRoots(vocabulary, createPageRequest(pageSize, pageNo), includeTerms); } /** @@ -264,10 +264,10 @@ public Term getById(@PathVariable("termIdFragment") String termIdFragment, private URI getTermUri(String vocabIdFragment, String termIdFragment, Optional namespace) { return idResolver.resolveIdentifier(idResolver - .buildNamespace( - getVocabularyUri(namespace, vocabIdFragment).toString(), - config.getNamespace().getTerm().getSeparator()), - termIdFragment); + .buildNamespace( + getVocabularyUri(namespace, vocabIdFragment).toString(), + config.getNamespace().getTerm().getSeparator()), + termIdFragment); } /** @@ -469,7 +469,7 @@ public void runTextAnalysisOnTerm(@PathVariable String vocabularyIdFragment, @RequestParam(name = QueryParams.NAMESPACE, required = false) Optional namespace) { termService.analyzeTermDefinition(getById(vocabularyIdFragment, termIdFragment, namespace), - getVocabularyUri(namespace, vocabularyIdFragment)); + getVocabularyUri(namespace, vocabularyIdFragment)); } @PutMapping(value = "/terms/{termIdFragment}/definition-source", @@ -548,8 +548,8 @@ public List getComments(@PathVariable("vocabularyIdFragment") String vo required = false) Optional namespace) { final URI termUri = getTermUri(vocabularyIdFragment, termIdFragment, namespace); return termService.getComments(termService.getRequiredReference(termUri), - from.map(RestUtils::parseTimestamp).orElse(Constants.EPOCH_TIMESTAMP), - to.map(RestUtils::parseTimestamp).orElse(Utils.timestamp())); + from.map(RestUtils::parseTimestamp).orElse(Constants.EPOCH_TIMESTAMP), + to.map(RestUtils::parseTimestamp).orElse(Utils.timestamp())); } /** @@ -567,8 +567,8 @@ public List getComments(@PathVariable("termIdFragment") String termIdFr @RequestParam(name = QueryParams.NAMESPACE) String namespace) { final URI termUri = idResolver.resolveIdentifier(namespace, termIdFragment); return termService.getComments(termService.getRequiredReference(termUri), - from.map(RestUtils::parseTimestamp).orElse(Constants.EPOCH_TIMESTAMP), - to.map(RestUtils::parseTimestamp).orElse(Utils.timestamp())); + from.map(RestUtils::parseTimestamp).orElse(Constants.EPOCH_TIMESTAMP), + to.map(RestUtils::parseTimestamp).orElse(Utils.timestamp())); } /** @@ -586,12 +586,12 @@ public ResponseEntity addComment(@PathVariable("vocabularyIdFragment") Str termService.addComment(comment, term); LOG.debug("Comment added to term {}.", term); return ResponseEntity.created(RestUtils - .createLocationFromCurrentContextWithPathAndQuery("/comments/{name}", - QueryParams.NAMESPACE, - IdentifierResolver.extractIdentifierNamespace( - comment.getUri()), - IdentifierResolver.extractIdentifierFragment( - comment.getUri()))) + .createLocationFromCurrentContextWithPathAndQuery("/comments/{name}", + QueryParams.NAMESPACE, + IdentifierResolver.extractIdentifierNamespace( + comment.getUri()), + IdentifierResolver.extractIdentifierFragment( + comment.getUri()))) .build(); } @@ -612,12 +612,12 @@ public ResponseEntity addComment(@PathVariable("termIdFragment") String te termService.addComment(comment, term); LOG.debug("Comment added to term {}.", term); return ResponseEntity.created(RestUtils - .createLocationFromCurrentContextWithPathAndQuery("/comments/{name}", - QueryParams.NAMESPACE, - IdentifierResolver.extractIdentifierNamespace( - comment.getUri()), - IdentifierResolver.extractIdentifierFragment( - comment.getUri()))) + .createLocationFromCurrentContextWithPathAndQuery("/comments/{name}", + QueryParams.NAMESPACE, + IdentifierResolver.extractIdentifierNamespace( + comment.getUri()), + IdentifierResolver.extractIdentifierFragment( + comment.getUri()))) .build(); } diff --git a/src/test/java/cz/cvut/kbss/termit/rest/TermControllerTest.java b/src/test/java/cz/cvut/kbss/termit/rest/TermControllerTest.java index feabda43..ff6e153e 100644 --- a/src/test/java/cz/cvut/kbss/termit/rest/TermControllerTest.java +++ b/src/test/java/cz/cvut/kbss/termit/rest/TermControllerTest.java @@ -1189,4 +1189,28 @@ void getSnapshotsThrowsBadRequestWhenAtIsNotValidInstantString() throws Exceptio void getTermsReturnsNotAcceptableWhenAskingForUnsupportedMediaType() throws Exception { mockMvc.perform(get("/terms").accept(MediaType.APPLICATION_PDF_VALUE)).andExpect(status().isNotAcceptable()); } + + @Test + void getAllSanitizesFilenameInContentDispositionHeaderToAscii() throws Exception { + final String name = "metropolitní-plán"; + final String sanitizedName = "metropolitni-plan"; + final URI vocabularyUri = URI.create(Environment.BASE_URI + "/" + name); + when(idResolverMock.resolveIdentifier(config.getNamespace().getVocabulary(), name)) + .thenReturn(vocabularyUri); + final cz.cvut.kbss.termit.model.Vocabulary vocabulary = Generator.generateVocabulary(); + vocabulary.setUri(vocabularyUri); + when(termServiceMock.findVocabularyRequired(vocabulary.getUri())).thenReturn(vocabulary); + final TypeAwareByteArrayResource export = prepareTurtle(); + when(termServiceMock.exportGlossary(vocabulary, new ExportConfig(ExportType.SKOS, + ExportFormat.TURTLE.getMediaType()))).thenReturn( + Optional.of(export)); + + final MvcResult mvcResult = mockMvc + .perform(get(URI.create(PATH + name + "/terms")).accept(ExportFormat.TURTLE.getMediaType()) + .queryParam("exportType", ExportType.SKOS.toString())) + .andReturn(); + assertThat(mvcResult.getResponse().getHeader(HttpHeaders.CONTENT_DISPOSITION), containsString("attachment")); + assertThat(mvcResult.getResponse().getHeader(HttpHeaders.CONTENT_DISPOSITION), + containsString("filename=\"" + sanitizedName + ExportFormat.TURTLE.getFileExtension() + "\"")); + } }