diff --git a/java/google/registry/proxy/handler/QuotaHandler.java b/java/google/registry/proxy/handler/QuotaHandler.java index 1381d72c9..183e89a7b 100644 --- a/java/google/registry/proxy/handler/QuotaHandler.java +++ b/java/google/registry/proxy/handler/QuotaHandler.java @@ -156,7 +156,9 @@ public abstract class QuotaHandler extends ChannelInboundHandlerAdapter { public void channelInactive(ChannelHandlerContext ctx) { // If no reads occurred before the connection is inactive (for example when the handshake // is not successful), no quota is leased and therefore no return is needed. - if (quotaResponse != null) { + // Note that the quota response can be a failure, in which case no token was leased to us from + // the token store. Consequently no return is necessary. + if (quotaResponse != null && quotaResponse.success()) { Future unusedFuture = quotaManager.releaseQuota(QuotaRebate.create(quotaResponse)); } ctx.fireChannelInactive(); diff --git a/javatests/google/registry/proxy/handler/EppQuotaHandlerTest.java b/javatests/google/registry/proxy/handler/EppQuotaHandlerTest.java index 1669df3a0..df2211aa9 100644 --- a/javatests/google/registry/proxy/handler/EppQuotaHandlerTest.java +++ b/javatests/google/registry/proxy/handler/EppQuotaHandlerTest.java @@ -109,7 +109,11 @@ public class EppQuotaHandlerTest { .thenReturn(QuotaResponse.create(false, clientCertHash, now)); OverQuotaException e = assertThrows(OverQuotaException.class, () -> channel.writeInbound(message)); + ChannelFuture unusedFuture = channel.close(); assertThat(e).hasMessageThat().contains(clientCertHash); + verify(quotaManager).acquireQuota(QuotaRequest.create(clientCertHash)); + // Make sure that quotaManager.releaseQuota() is not called when the channel closes. + verifyNoMoreInteractions(quotaManager); verify(metrics).registerQuotaRejection("epp", clientCertHash); verifyNoMoreInteractions(metrics); }