Skip to content

Commit

Permalink
feat: return bad request error when unknown compression format in req…
Browse files Browse the repository at this point in the history
…uest #647
  • Loading branch information
fengelniederhammer committed Feb 16, 2024
1 parent 7e49aa5 commit a194d63
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import org.springframework.core.annotation.Order
import org.springframework.core.env.Environment
import org.springframework.http.HttpHeaders.ACCEPT_ENCODING
import org.springframework.http.HttpHeaders.CONTENT_ENCODING
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ProblemDetail
import org.springframework.http.converter.StringHttpMessageConverter
import org.springframework.stereotype.Component
import org.springframework.web.context.annotation.RequestScope
Expand Down Expand Up @@ -71,6 +73,25 @@ class CompressionFilter(val objectMapper: ObjectMapper, val requestCompression:
) {
val reReadableRequest = CachedBodyHttpServletRequest(request, objectMapper)

try {
validateCompressionProperty(reReadableRequest)
} catch (e: UnknownCompressionFormatException) {
response.status = HttpStatus.BAD_REQUEST.value()
response.contentType = MediaType.APPLICATION_JSON_VALUE
response.writer.write(
objectMapper.writeValueAsString(
LapisErrorResponse(
ProblemDetail.forStatus(HttpStatus.BAD_REQUEST).apply {
title = HttpStatus.BAD_REQUEST.reasonPhrase
detail = "Unknown compression format: ${e.unknownFormatValue}. " +
"Supported formats are: ${Compression.entries.joinToString { it.value }}"
},
),
),
)
return
}

val requestWithContentEncoding = HeaderModifyingRequestWrapper(
reReadableRequest = reReadableRequest,
headerName = ACCEPT_ENCODING,
Expand All @@ -91,6 +112,14 @@ class CompressionFilter(val objectMapper: ObjectMapper, val requestCompression:
maybeCompressingResponse.outputStream.close()
}

private fun validateCompressionProperty(reReadableRequest: CachedBodyHttpServletRequest) {
val compressionFormat = reReadableRequest.getStringField(COMPRESSION_PROPERTY) ?: return

if (Compression.entries.toSet().none { it.value == compressionFormat }) {
throw UnknownCompressionFormatException(unknownFormatValue = compressionFormat)
}
}

private fun createMaybeCompressingResponse(
response: HttpServletResponse,
acceptEncodingHeaders: Enumeration<String>?,
Expand All @@ -110,6 +139,8 @@ private fun computeAcceptEncodingValueFromRequest(reReadableRequest: CachedBodyH
else -> null
}

private class UnknownCompressionFormatException(val unknownFormatValue: String) : Exception()

class CompressingResponse(
response: HttpServletResponse,
compression: Compression,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ package org.genspectrum.lapis.controller
import com.github.luben.zstd.ZstdInputStream
import com.ninjasquad.springmockk.MockkBean
import io.mockk.every
import org.genspectrum.lapis.controller.SampleRoute.AGGREGATED
import org.genspectrum.lapis.controller.SampleRoute.ALIGNED_AMINO_ACID_SEQUENCES
import org.genspectrum.lapis.controller.SampleRoute.ALIGNED_NUCLEOTIDE_SEQUENCES
import org.genspectrum.lapis.controller.SampleRoute.UNALIGNED_NUCLEOTIDE_SEQUENCES
import org.genspectrum.lapis.model.SiloQueryModel
import org.genspectrum.lapis.request.LapisInfo
import org.hamcrest.Matchers.containsString
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.MethodSource
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
Expand All @@ -20,9 +26,12 @@ import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.header
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import java.util.zip.GZIPInputStream

private const val INVALID_COMPRESSION_FORMAT = "invalidCompressionFormat"

@SpringBootTest
@AutoConfigureMockMvc
class LapisControllerCompressionTest(
Expand All @@ -39,6 +48,19 @@ class LapisControllerCompressionTest(
every { lapisInfo.dataVersion } returns "1234"
}

@ParameterizedTest
@MethodSource("getRequestsWithInvalidCompressionFormat")
fun `WHEN I send a request with unknown compression format THEN should show an error`(
request: MockHttpServletRequestBuilder,
) {
mockMvc.perform(request)
.andExpect(status().isBadRequest)
.andExpect(
jsonPath("\$.error.detail")
.value(containsString("Unknown compression format: $INVALID_COMPRESSION_FORMAT")),
)
}

@ParameterizedTest(name = "{0}")
@MethodSource("getScenarios")
fun `endpoints return compressed data`(requestsScenario: RequestScenario) {
Expand All @@ -64,6 +86,16 @@ class LapisControllerCompressionTest(
}

private companion object {
@JvmStatic
val requestsWithInvalidCompressionFormat = listOf(
Arguments.of(getSample("${AGGREGATED.pathSegment}?compression=$INVALID_COMPRESSION_FORMAT")),
Arguments.of(
postSample(AGGREGATED.pathSegment)
.content("""{"compression": "$INVALID_COMPRESSION_FORMAT"}""")
.contentType(APPLICATION_JSON),
),
)

@JvmStatic
val scenarios =
SampleRoute.entries
Expand All @@ -83,21 +115,21 @@ class LapisControllerCompressionTest(
)
} +
getRequests(
SampleRoute.AGGREGATED,
AGGREGATED,
dataFormat = MockDataCollection.DataFormat.NESTED_JSON,
compressionFormat = "gzip",
expectedContentType = APPLICATION_JSON_VALUE,
) +
getRequests(
SampleRoute.AGGREGATED,
AGGREGATED,
dataFormat = MockDataCollection.DataFormat.TSV,
compressionFormat = "zstd",
expectedContentType = "$TEXT_TSV_HEADER;charset=UTF-8",
) +
listOf(
"${SampleRoute.UNALIGNED_NUCLEOTIDE_SEQUENCES.pathSegment}/main",
"${SampleRoute.ALIGNED_NUCLEOTIDE_SEQUENCES.pathSegment}/main",
"${SampleRoute.ALIGNED_AMINO_ACID_SEQUENCES.pathSegment}/gene1",
"${UNALIGNED_NUCLEOTIDE_SEQUENCES.pathSegment}/main",
"${ALIGNED_NUCLEOTIDE_SEQUENCES.pathSegment}/main",
"${ALIGNED_AMINO_ACID_SEQUENCES.pathSegment}/gene1",
)
.flatMap { getFastaRequests(it, "gzip") + getFastaRequests(it, "zstd") }
}
Expand Down

0 comments on commit a194d63

Please sign in to comment.