From 8513d314c152e7b0a9fb14c3f033b4a650946e23 Mon Sep 17 00:00:00 2001 From: testinfected Date: Tue, 22 Dec 2020 00:52:51 -0500 Subject: [PATCH] Use possessive quantifiers in regex for decoding cookies Decoding cookies becomes very complex to handle for the regex engine when cookie values are very large. This causes `StackOverflowError`s probable due to the catastrophic backtracking Use possessive quantifiers to prevent the regex engine from trying all permutations. This should make the complexity of the regex linear and not exponential. The performance increase can be significant and fixes the issue. Closes #77 --- src/main/java/com/vtence/molecule/http/CookieDecoder.java | 2 +- .../java/com/vtence/molecule/http/CookieDecoderTest.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/vtence/molecule/http/CookieDecoder.java b/src/main/java/com/vtence/molecule/http/CookieDecoder.java index 4708313..4316f96 100644 --- a/src/main/java/com/vtence/molecule/http/CookieDecoder.java +++ b/src/main/java/com/vtence/molecule/http/CookieDecoder.java @@ -7,7 +7,7 @@ public class CookieDecoder { - private static final Pattern NAME_VALUE_PAIR = Pattern.compile("(?:\\s|[;,])*([^;=]+)(?:=([\"]((?:\\\\\"|[^\"])*)[\"]|[^;,]*))?"); + private static final Pattern NAME_VALUE_PAIR = Pattern.compile("(?:\\s|[;,])*+([^;=]++)(?:=([\"]((?:\\\\\"|[^\"])++)[\"]|[^;,]*+))?+"); private static final int NAME = 1; private static final int VALUE = 2; diff --git a/src/test/java/com/vtence/molecule/http/CookieDecoderTest.java b/src/test/java/com/vtence/molecule/http/CookieDecoderTest.java index b8b91a7..cd1daca 100644 --- a/src/test/java/com/vtence/molecule/http/CookieDecoderTest.java +++ b/src/test/java/com/vtence/molecule/http/CookieDecoderTest.java @@ -1,5 +1,6 @@ package com.vtence.molecule.http; +import org.hamcrest.Matchers; import org.junit.Test; import java.util.List; @@ -132,6 +133,12 @@ public void decodesCommaSeparatedPairs() { assertThat("cookie value", launcher.value(), equalTo("Rocket_Launcher_0001")); } + @Test + public void handlesVeryLongCookieValue() { + Cookie cookie = decodeSingle("$Version=\"1\"; molecule.session=\"rO0ABXNyACNjb20udnRlbmNlLm1vbGVjdWxlLnNlc3Npb24uU2Vzc2lvbvJqkJ0nBioiAgAGWgAHaW52YWxpZEkABm1heEFnZUwACmF0dHJpYnV0ZXN0AA9MamF2YS91dGlsL01hcDtMAAljcmVhdGVkQXR0ABNMamF2YS90aW1lL0luc3RhbnQ7TAACaWR0ABJMamF2YS9sYW5nL1N0cmluZztMAAl1cGRhdGVkQXRxAH4AAnhwAP////9zcgAmamF2YS51dGlsLmNvbmN1cnJlbnQuQ29uY3VycmVudEhhc2hNYXBkmd4SnYcpPQMAA0kAC3NlZ21lbnRNYXNrSQAMc2VnbWVudFNoaWZ0WwAIc2VnbWVudHN0ADFbTGphdmEvdXRpbC9jb25jdXJyZW50L0NvbmN1cnJlbnRIYXNoTWFwJFNlZ21lbnQ7eHAAAAAPAAAAHHVyADFbTGphdmEudXRpbC5jb25jdXJyZW50LkNvbmN1cnJlbnRIYXNoTWFwJFNlZ21lbnQ7Unc/QTKbOXQCAAB4cAAAABBzcgAuamF2YS51dGlsLmNvbmN1cnJlbnQuQ29uY3VycmVudEhhc2hNYXAkU2VnbWVudB82TJBYkyk9AgABRgAKbG9hZEZhY3RvcnhyAChqYXZhLnV0aWwuY29uY3VycmVudC5sb2Nrcy5SZWVudHJhbnRMb2NrZlWoLCzIausCAAFMAARzeW5jdAAvTGphdmEvdXRpbC9jb25jdXJyZW50L2xvY2tzL1JlZW50cmFudExvY2skU3luYzt4cHNyADRqYXZhLnV0aWwuY29uY3VycmVudC5sb2Nrcy5SZWVudHJhbnRMb2NrJE5vbmZhaXJTeW5jZYgy51N7vwsCAAB4cgAtamF2YS51dGlsLmNvbmN1cnJlbnQubG9ja3MuUmVlbnRyYW50TG9jayRTeW5juB6ilKpEWnwCAAB4cgA1amF2YS51dGlsLmNvbmN1cnJlbnQubG9ja3MuQWJzdHJhY3RRdWV1ZWRTeW5jaHJvbml6ZXJmVahDdT9S4wIAAUkABXN0YXRleHIANmphdmEudXRpbC5jb25jdXJyZW50LmxvY2tzLkFic3RyYWN0T3duYWJsZVN5bmNocm9uaXplcjPfr7mtbW+pAgAAeHAAAAAAP0AAAHNxAH4ACnNxAH4ADgAAAAA/QAAAc3EAfgAKc3EAfgAOAAAAAD9AAABzcQB+AApzcQB+AA4AAAAAP0AAAHNxAH4ACnNxAH4ADgAAAAA/QAAAc3EAfgAKc3EAfgAOAAAAAD9AAABzcQB+AApzcQB+AA4AAAAAP0AAAHNxAH4ACnNxAH4ADgAAAAA/QAAAc3EAfgAKc3EAfgAOAAAAAD9AAABzcQB+AApzcQB+AA4AAAAAP0AAAHNxAH4ACnNxAH4ADgAAAAA/QAAAc3EAfgAKc3EAfgAOAAAAAD9AAABzcQB+AApzcQB+AA4AAAAAP0AAAHNxAH4ACnNxAH4ADgAAAAA/QAAAc3EAfgAKc3EAfgAOAAAAAD9AAABzcQB+AApzcQB+AA4AAAAAP0AAAHQACHVzZXJuYW1ldAAHVmluY2VudHBweHNyAA1qYXZhLnRpbWUuU2VylV2EuhsiSLIMAAB4cHcNAgAAAABf4YaaJOx4CHh0ACRjNGIxMDNlMC0zYzAzLTQxZDYtOWEzNC1lZTczOWE3ODc0YzBxAH4ANA==--r3q1yut2aSCAjMF03DMV2z5A79aeWP744I2pMVoO7qk=\";$Path=\"/\";$Domain=\"0.0.0.0\""); + assertThat(cookie.value(), Matchers.endsWith("MVoO7qk=")); + } + private Cookie decodeSingle(String cookieHeader) { List cookies = decodeAll(cookieHeader); assertThat("cookies found", cookies, hasSize(1));