diff --git a/transport/wseb/src/main/java/org/kaazing/gateway/transport/wseb/WsebAcceptor.java b/transport/wseb/src/main/java/org/kaazing/gateway/transport/wseb/WsebAcceptor.java index af10d730df..4a78fe3072 100644 --- a/transport/wseb/src/main/java/org/kaazing/gateway/transport/wseb/WsebAcceptor.java +++ b/transport/wseb/src/main/java/org/kaazing/gateway/transport/wseb/WsebAcceptor.java @@ -628,7 +628,14 @@ public void initializeSession(IoSession wsSession, IoFuture future) { wsebSession.setPingEnabled(pingEnabled); IoSessionEx extensionsSession = wsebSession.getTransportSession(); IoFilterChain extensionsFilterChain = extensionsSession.getFilterChain(); - WsUtils.addExtensionFilters(negotiated, extensionHelper, extensionsFilterChain, false); + + // we don't want IdleTimeoutFilter in the filter chain. It sends 0x8A (PONG) + // and some clients don't understand it. WSEB anyway sends NOOP command when + // writer is idle. + List negotiatedCopy = new ArrayList<>(negotiated); + negotiatedCopy.removeIf(e -> e.getExtensionHeader().getExtensionToken().equals("x-kaazing-idle-timeout")); + WsUtils.addExtensionFilters(negotiatedCopy, extensionHelper, extensionsFilterChain, false); + extensionsFilterChain.fireSessionCreated(); extensionsFilterChain.fireSessionOpened(); } diff --git a/transport/wseb/src/test/java/org/kaazing/gateway/transport/wseb/WsebIdleTimeoutExtensionIT.java b/transport/wseb/src/test/java/org/kaazing/gateway/transport/wseb/WsebIdleTimeoutExtensionIT.java new file mode 100644 index 0000000000..1e423860c8 --- /dev/null +++ b/transport/wseb/src/test/java/org/kaazing/gateway/transport/wseb/WsebIdleTimeoutExtensionIT.java @@ -0,0 +1,104 @@ +/** + * Copyright 2007-2016, Kaazing Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.kaazing.gateway.transport.wseb; + +import org.apache.mina.core.service.IoHandler; +import org.jmock.integration.junit4.JUnitRuleMockery; +import org.jmock.lib.concurrent.Synchroniser; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; +import org.kaazing.gateway.resource.address.ResourceAddress; +import org.kaazing.gateway.resource.address.ResourceAddressFactory; +import org.kaazing.gateway.transport.test.Expectations; +import org.kaazing.gateway.transport.wseb.test.WsebAcceptorRule; +import org.kaazing.gateway.util.InternalSystemProperty; +import org.kaazing.k3po.junit.annotation.Specification; +import org.kaazing.k3po.junit.rules.K3poRule; +import org.kaazing.test.util.ITUtil; +import org.kaazing.test.util.MethodExecutionTrace; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicReference; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.junit.Assert.assertNull; +import static org.kaazing.gateway.resource.address.ws.WsResourceAddress.INACTIVITY_TIMEOUT; +import static org.kaazing.test.util.ITUtil.timeoutRule; + +public class WsebIdleTimeoutExtensionIT { + + private final K3poRule k3po = new K3poRule(); + + private final WsebAcceptorRule acceptor; + + { + Properties configuration = new Properties(); + configuration.setProperty(InternalSystemProperty.WS_CLOSE_TIMEOUT.getPropertyName(), "2s"); + + acceptor = new WsebAcceptorRule(configuration); + } + + private final JUnitRuleMockery context = new JUnitRuleMockery() { + { + setThreadingPolicy(new Synchroniser()); + } + }; + + private final TestRule contextRule = ITUtil.toTestRule(context); + private final TestRule trace = new MethodExecutionTrace(); + private final TestRule timeoutRule = timeoutRule(5, SECONDS); + + @Rule + public final TestRule chain = RuleChain.outerRule(trace).around(acceptor).around(contextRule). + around(k3po).around(timeoutRule); + + private final ResourceAddressFactory resourceAddressFactory = ResourceAddressFactory.newResourceAddressFactory(); + + + @Test + @Specification("should.negotiate.idle.timeout.extension") + public void shouldNegotiateIdleTimeoutExtension() throws Exception { + + Map options = new HashMap<>(); + options.put(INACTIVITY_TIMEOUT.name(), 10000L); + ResourceAddress address = resourceAddressFactory.newResourceAddress("wse://localhost:8080/path", options); + final AtomicReference session = new AtomicReference<>(); + + acceptor.bind(address, mockHandler(session)); + k3po.finish(); + + // IdleTimeoutFilter shouldn't be in transport session filter chain for wseb + assertNull(session.get().getTransportSession().getFilterChain().get("x-kaazing-idle-timeout")); + } + + private IoHandler mockHandler(AtomicReference session) throws Exception { + IoHandler handler = context.mock(IoHandler.class); + + context.checking(new Expectations() { + { + oneOf(handler).sessionCreated(with(any(WsebSession.class))); + oneOf(handler).sessionOpened(with(any(WsebSession.class))); + will(saveParameter(session, 0)); + } + }); + return handler; + } + +} diff --git a/transport/wseb/src/test/scripts/org/kaazing/gateway/transport/wseb/should.negotiate.idle.timeout.extension.rpt b/transport/wseb/src/test/scripts/org/kaazing/gateway/transport/wseb/should.negotiate.idle.timeout.extension.rpt new file mode 100644 index 0000000000..6b0d16ecd5 --- /dev/null +++ b/transport/wseb/src/test/scripts/org/kaazing/gateway/transport/wseb/should.negotiate.idle.timeout.extension.rpt @@ -0,0 +1,38 @@ +# +# Copyright 2007-2016, Kaazing Corporation. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +property sequence ${wse:randomInt(100)} + +connect http://localhost:8080/path/;e/cb?query +connected + +write method "POST" +write version "HTTP/1.1" +write header host +write header content-length +write header "X-WebSocket-Version" "wseb-1.0" +write header "X-Sequence-No" ${wse:asString(sequence)} +write header "X-WebSocket-Extensions" "x-kaazing-idle-timeout" +write close + +read status "201" /.+/ +read version "HTTP/1.1" +read header "Content-Type" /text\/plain;charset=(?i)utf-8/ +read header "X-WebSocket-Extensions" "x-kaazing-idle-timeout; timeout=10000" + +read /http:\/\/localhost:8080\/path\/.+?\n/ +read /http:\/\/localhost:8080\/path\/.+?\n/ +read closed