mirror of
https://github.com/gotson/komga.git
synced 2026-05-08 12:35:30 +02:00
fix: handle query parameters with square brackets
because of https://github.com/flutterchina/dio/issues/799
This commit is contained in:
parent
f04674d6cd
commit
245dea906c
4 changed files with 343 additions and 0 deletions
|
|
@ -1,6 +1,24 @@
|
||||||
package org.gotson.komga.infrastructure.language
|
package org.gotson.komga.infrastructure.language
|
||||||
|
|
||||||
|
import java.util.Enumeration
|
||||||
import java.util.SortedMap
|
import java.util.SortedMap
|
||||||
|
|
||||||
fun <T> List<T>.toIndexedMap(): SortedMap<Int, T> =
|
fun <T> List<T>.toIndexedMap(): SortedMap<Int, T> =
|
||||||
mapIndexed { i, e -> i to e }.toMap().toSortedMap()
|
mapIndexed { i, e -> i to e }.toMap().toSortedMap()
|
||||||
|
|
||||||
|
fun <T> List<T>.toEnumeration(): Enumeration<T> {
|
||||||
|
return object : Enumeration<T> {
|
||||||
|
var count = 0
|
||||||
|
|
||||||
|
override fun hasMoreElements(): Boolean {
|
||||||
|
return this.count < size
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun nextElement(): T {
|
||||||
|
if (this.count < size) {
|
||||||
|
return get(this.count++)
|
||||||
|
}
|
||||||
|
throw NoSuchElementException("List enumeration asked for more elements than present")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package org.gotson.komga.infrastructure.web
|
||||||
|
|
||||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import javax.servlet.Filter
|
||||||
|
import javax.servlet.FilterChain
|
||||||
|
import javax.servlet.ServletRequest
|
||||||
|
import javax.servlet.ServletResponse
|
||||||
|
import javax.servlet.http.HttpServletRequest
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
class BracketParamsFilterConfiguration {
|
||||||
|
@Bean
|
||||||
|
fun bracketParamsFilter(): FilterRegistrationBean<BracketParamsFilter> =
|
||||||
|
FilterRegistrationBean(BracketParamsFilter())
|
||||||
|
.also {
|
||||||
|
it.addUrlPatterns(
|
||||||
|
"/api/*"
|
||||||
|
)
|
||||||
|
it.setName("queryParamsFilter")
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class BracketParamsFilter : Filter {
|
||||||
|
override fun doFilter(request: ServletRequest?, response: ServletResponse?, chain: FilterChain?) {
|
||||||
|
chain?.doFilter(BracketParamsRequestWrapper(request as HttpServletRequest), response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package org.gotson.komga.infrastructure.web
|
||||||
|
|
||||||
|
import org.gotson.komga.infrastructure.language.toEnumeration
|
||||||
|
import java.util.Enumeration
|
||||||
|
import javax.servlet.http.HttpServletRequest
|
||||||
|
import javax.servlet.http.HttpServletRequestWrapper
|
||||||
|
|
||||||
|
class BracketParamsRequestWrapper(request: HttpServletRequest) : HttpServletRequestWrapper(request) {
|
||||||
|
override fun getParameter(name: String): String? {
|
||||||
|
val nameWithoutSuffix = name.removeSuffix("[]")
|
||||||
|
val values = listOfNotNull(super.getParameter(nameWithoutSuffix), super.getParameter("$nameWithoutSuffix[]"))
|
||||||
|
return if (values.isEmpty()) null
|
||||||
|
else values.joinToString(",")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getParameterValues(name: String): Array<String>? {
|
||||||
|
val nameWithoutSuffix = name.removeSuffix("[]")
|
||||||
|
val regular = super.getParameterValues(nameWithoutSuffix)
|
||||||
|
val suffix = super.getParameterValues("$nameWithoutSuffix[]")
|
||||||
|
val values = listOfNotNull(regular, suffix)
|
||||||
|
return if (values.isEmpty()) null
|
||||||
|
else values.reduce { acc, strings -> acc + strings }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getParameterNames(): Enumeration<String> =
|
||||||
|
super.getParameterNames().toList().map { it.removeSuffix("[]") }.distinct().toEnumeration()
|
||||||
|
|
||||||
|
override fun getParameterMap(): MutableMap<String, Array<String>> {
|
||||||
|
return super.getParameterMap().asSequence()
|
||||||
|
.groupBy({ it.key.removeSuffix("[]") }, { it.value })
|
||||||
|
.mapValues { it.value.reduce { acc, strings -> acc + strings } }
|
||||||
|
.toMutableMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,258 @@
|
||||||
|
package org.gotson.komga.infrastructure.web
|
||||||
|
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.junit.jupiter.api.Nested
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.springframework.mock.web.MockHttpServletRequest
|
||||||
|
|
||||||
|
class BracketParamsRequestWrapperTest {
|
||||||
|
@Nested
|
||||||
|
inner class ParameterNames {
|
||||||
|
@Test
|
||||||
|
fun `given parameters with and without brackets when getting parameter names then only the name without bracket is returned`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
request.setParameter("param")
|
||||||
|
request.setParameter("param[]")
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(filtered.parameterNames.toList()).containsExactlyInAnyOrder("param")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given parameters with brackets when getting parameter names then only the name without bracket is returned`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
request.setParameter("param[]")
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(filtered.parameterNames.toList()).containsExactlyInAnyOrder("param")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given parameters without brackets when getting parameter names then only the name without bracket is returned`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
request.setParameter("param")
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(filtered.parameterNames.toList()).containsExactlyInAnyOrder("param")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given empty parameters when getting parameter names then it is empty`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(filtered.parameterNames.toList()).isEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
inner class ParameterValue {
|
||||||
|
@Test
|
||||||
|
fun `given parameters with and without brackets when getting parameter value then both values are joined to string`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
request.setParameter("param", "a")
|
||||||
|
request.setParameter("param[]", "b")
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
val value = filtered.getParameter("param")
|
||||||
|
val valueBracket = filtered.getParameter("param[]")
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(value).isEqualTo(valueBracket)
|
||||||
|
assertThat(value).isEqualTo("a,b")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given parameters with brackets when getting parameter value single value is returned`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
request.setParameter("param[]", "b")
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
val value = filtered.getParameter("param")
|
||||||
|
val valueBracket = filtered.getParameter("param[]")
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(value).isEqualTo(valueBracket)
|
||||||
|
assertThat(value).isEqualTo("b")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given parameters without brackets when getting parameter value single value is returned`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
request.setParameter("param", "b")
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
val value = filtered.getParameter("param")
|
||||||
|
val valueBracket = filtered.getParameter("param[]")
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(value).isEqualTo(valueBracket)
|
||||||
|
assertThat(value).isEqualTo("b")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given empty parameters when getting parameter value then return null`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
val value = filtered.getParameter("param")
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(value).isNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
inner class ParameterValues {
|
||||||
|
@Test
|
||||||
|
fun `given parameters with and without brackets when getting parameter values then both values are returned`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
request.setParameter("param[]", "a")
|
||||||
|
request.setParameter("param", "b")
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
val values = filtered.getParameterValues("param")
|
||||||
|
val valuesBracket = filtered.getParameterValues("param[]")
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(values).isEqualTo(valuesBracket)
|
||||||
|
assertThat(values).containsExactlyInAnyOrder("a", "b")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given parameters with brackets when getting parameter values then value is returned`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
request.setParameter("param[]", "a")
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
val values = filtered.getParameterValues("param")
|
||||||
|
val valuesBracket = filtered.getParameterValues("param[]")
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(values).isEqualTo(valuesBracket)
|
||||||
|
assertThat(values).containsExactlyInAnyOrder("a")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given parameters without brackets when getting parameter values then value is returned`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
request.setParameter("param", "a")
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
val values = filtered.getParameterValues("param")
|
||||||
|
val valuesBracket = filtered.getParameterValues("param[]")
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(values).isEqualTo(valuesBracket)
|
||||||
|
assertThat(values).containsExactlyInAnyOrder("a")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given empty parameters when getting parameter values then return null`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
val values = filtered.getParameterValues("param")
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(values).isNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
inner class ParameterMap {
|
||||||
|
@Test
|
||||||
|
fun `given parameters with and without brackets when getting parameter map then both values are returned`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
request.setParameter("param[]", "a")
|
||||||
|
request.setParameter("param", "b")
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
val map = filtered.parameterMap
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(map.keys).hasSize(1)
|
||||||
|
assertThat(map.keys).containsExactly("param")
|
||||||
|
assertThat(map["param"]).containsExactlyInAnyOrder("a", "b")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given parameters with brackets when getting parameter map then key without bracket is returned`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
request.setParameter("param[]", "a")
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
val map = filtered.parameterMap
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(map.keys).hasSize(1)
|
||||||
|
assertThat(map.keys).containsExactly("param")
|
||||||
|
assertThat(map["param"]).containsExactlyInAnyOrder("a")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given parameters without brackets when getting parameter map then key without bracket is returned`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
request.setParameter("param", "a")
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
val map = filtered.parameterMap
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(map.keys).hasSize(1)
|
||||||
|
assertThat(map.keys).containsExactly("param")
|
||||||
|
assertThat(map["param"]).containsExactlyInAnyOrder("a")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `given empty parameters when getting parameter map then empty map is returned`() {
|
||||||
|
// given
|
||||||
|
val request = MockHttpServletRequest()
|
||||||
|
|
||||||
|
// when
|
||||||
|
val filtered = BracketParamsRequestWrapper(request)
|
||||||
|
val map = filtered.parameterMap
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(map).isEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue