diff --git a/components/api/src/main/java/com/hotels/styx/api/HttpInterceptor.java b/components/api/src/main/java/com/hotels/styx/api/HttpInterceptor.java index 5d7fa49c2..2b0f93d7c 100644 --- a/components/api/src/main/java/com/hotels/styx/api/HttpInterceptor.java +++ b/components/api/src/main/java/com/hotels/styx/api/HttpInterceptor.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -74,6 +74,11 @@ default Optional getIfAvailable(String key, Class clazz) { * @return returns the netty executor which started handling the current request */ Executor executor(); + + /** + * Removes all the stored items from this context. + */ + void clear(); } /** diff --git a/components/api/src/test/java/com/hotels/styx/api/extension/service/spi/MockContext.java b/components/api/src/test/java/com/hotels/styx/api/extension/service/spi/MockContext.java index f37be25bc..c909f26b7 100644 --- a/components/api/src/test/java/com/hotels/styx/api/extension/service/spi/MockContext.java +++ b/components/api/src/test/java/com/hotels/styx/api/extension/service/spi/MockContext.java @@ -48,4 +48,9 @@ public Optional clientAddress() { public Executor executor() { return Runnable::run; } + + @Override + public void clear() { + // no-op + } } diff --git a/components/client/src/main/kotlin/com/hotels/styx/client/DummyContext.kt b/components/client/src/main/kotlin/com/hotels/styx/client/DummyContext.kt index ba7e8e19d..65b699aeb 100644 --- a/components/client/src/main/kotlin/com/hotels/styx/client/DummyContext.kt +++ b/components/client/src/main/kotlin/com/hotels/styx/client/DummyContext.kt @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2023 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,16 +25,26 @@ import java.util.concurrent.Executor * (because the call was not made within an interceptor chain). */ object DummyContext : HttpInterceptor.Context { - override fun add(key: String, value: Any) { + override fun add( + key: String, + value: Any, + ) { // Empty by design } @Deprecated("Deprecated in Java", ReplaceWith("getIfAvailable")) - override fun get(key: String, clazz: Class): T? = null + override fun get( + key: String, + clazz: Class, + ): T? = null override fun isSecure(): Boolean = false override fun clientAddress(): Optional = Optional.empty() override fun executor(): Executor = Executor { it.run() } + + override fun clear() { + // no-op + } } diff --git a/components/common/src/main/kotlin/com/hotels/styx/server/HttpInterceptorContext.kt b/components/common/src/main/kotlin/com/hotels/styx/server/HttpInterceptorContext.kt index 17e3ca46c..86ab2ac6d 100644 --- a/components/common/src/main/kotlin/com/hotels/styx/server/HttpInterceptorContext.kt +++ b/components/common/src/main/kotlin/com/hotels/styx/server/HttpInterceptorContext.kt @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2023 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,7 +23,6 @@ import java.util.Optional import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.Executor - /** * ConcurrentHashMap backed implementation of HttpInterceptor.Context. * @@ -34,19 +33,25 @@ class HttpInterceptorContext( private val secure: Boolean, private val clientAddress: InetSocketAddress?, private val executor: Executor?, - override val timers: ContextualTimers? = null + override val timers: ContextualTimers? = null, ) : HttpInterceptor.Context, TimeMeasurable { // This may seem redundant but it allows Executor to be a lambda without needing to set `timers`. constructor(secure: Boolean, clientAddress: InetSocketAddress?, executor: Executor?) : this(secure, clientAddress, executor, null) private val context = ConcurrentHashMap() - override fun add(key: String, value: Any) { + override fun add( + key: String, + value: Any, + ) { context[key] = value } @Deprecated("Deprecated in Java") - override fun get(key: String, clazz: Class): T = context[key] as T + override fun get( + key: String, + clazz: Class, + ): T = context[key] as T override fun isSecure() = secure @@ -54,6 +59,8 @@ class HttpInterceptorContext( override fun executor(): Executor? = executor + override fun clear() = context.clear() + companion object { // Visible for testing @Deprecated("use the constructor instead") diff --git a/components/server/src/main/java/com/hotels/styx/server/netty/connectors/HttpPipelineHandler.java b/components/server/src/main/java/com/hotels/styx/server/netty/connectors/HttpPipelineHandler.java index 69149fe1b..ebb0a8777 100644 --- a/components/server/src/main/java/com/hotels/styx/server/netty/connectors/HttpPipelineHandler.java +++ b/components/server/src/main/java/com/hotels/styx/server/netty/connectors/HttpPipelineHandler.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2023 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -278,6 +278,8 @@ protected void hookOnCancel() { protected void hookFinally(SignalType type) { timers.stopTiming(RESPONSE_PROCESSING); timers.stopTiming(REQUEST_PROCESSING); + + context.clear(); } }); diff --git a/support/api-testsupport/src/main/java/com/hotels/styx/support/Support.java b/support/api-testsupport/src/main/java/com/hotels/styx/support/Support.java index c4c5d1f0d..3ba4cf767 100644 --- a/support/api-testsupport/src/main/java/com/hotels/styx/support/Support.java +++ b/support/api-testsupport/src/main/java/com/hotels/styx/support/Support.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -81,6 +81,11 @@ public Optional clientAddress() { public Executor executor() { return this.executor; } + + @Override + public void clear() { + context.clear(); + } } }