@Override
    public WebSocketClientExtension handshakeExtension(WebSocketExtensionData extensionData) {
        if (!PERMESSAGE_DEFLATE_EXTENSION.equals(extensionData.name())) {
            return null;
        }

        boolean succeed = true;
        int clientWindowSize = MAX_WINDOW_SIZE;
        int serverWindowSize = MAX_WINDOW_SIZE;
        boolean serverNoContext = false;
        boolean clientNoContext = false;

        Iterator<Entry<String, String>> parametersIterator =
                extensionData.parameters().entrySet().iterator();
        while (succeed && parametersIterator.hasNext()) {
            Entry<String, String> parameter = parametersIterator.next();

            if (CLIENT_MAX_WINDOW.equalsIgnoreCase(parameter.getKey())) {
                // allowed client_window_size_bits
                if (allowClientWindowSize) {
                    clientWindowSize = Integer.parseInt(parameter.getValue());
                    if (clientWindowSize > MAX_WINDOW_SIZE || clientWindowSize < MIN_WINDOW_SIZE) {
                        succeed = false;
                    }
                } else {
                    succeed = false;
                }
            } else if (SERVER_MAX_WINDOW.equalsIgnoreCase(parameter.getKey())) {
                // acknowledged server_window_size_bits
                serverWindowSize = Integer.parseInt(parameter.getValue());
                if (serverWindowSize > MAX_WINDOW_SIZE || serverWindowSize < MIN_WINDOW_SIZE) {
                    succeed = false;
                }
            } else if (CLIENT_NO_CONTEXT.equalsIgnoreCase(parameter.getKey())) {
                // allowed client_no_context_takeover
                if (allowClientNoContext) {
                    clientNoContext = true;
                } else {
                    succeed = false;
                }
            } else if (SERVER_NO_CONTEXT.equalsIgnoreCase(parameter.getKey())) {
                // acknowledged server_no_context_takeover
                serverNoContext = true;
            } else {
                // unknown parameter
                succeed = false;
            }
        }

        if ((requestedServerNoContext && !serverNoContext) ||
                requestedServerWindowSize < serverWindowSize) {
            succeed = false;
        }

        if (succeed) {
            return new PermessageDeflateExtension(serverNoContext, serverWindowSize,
                    clientNoContext, clientWindowSize, extensionFilterProvider);
        } else {
            return null;
        }
    }
@Test
    public void testDecoderNoClientContext() {
        PerMessageDeflateClientExtensionHandshaker handshaker =
                new PerMessageDeflateClientExtensionHandshaker(6, true, MAX_WINDOW_SIZE, true, false);

        byte[] firstPayload = new byte[] {
                76, -50, -53, 10, -62, 48, 20, 4, -48, 95, 41, 89, -37, 36, 77, 90, 31, -39, 41, -72, 112, 33, -120, 20,
                20, 119, -79, 70, 123, -95, 121, -48, 92, -116, 80, -6, -17, -58, -99, -37, -31, 12, 51, 19, 1, -9, -12,
                68, -111, -117, 25, 58, 111, 77, -127, -66, -64, -34, 20, 59, -64, -29, -2, 90, -100, -115, 30, 16, 114,
                -68, 61, 29, 40, 89, -112, -73, 25, 35, 120, -105, -67, -32, -43, -70, -84, 120, -55, 69, 43, -124, 106,
                -92, 18, -110, 114, -50, 111, 25, -3, 10, 17, -75, 13, 127, -84, 106, 90, -66, 84, -75, 84, 53, -89,
                -75, 92, -3, -40, -61, 119, 49, -117, 30, 49, 68, -59, 88, 74, -119, -34, 1, -83, -7, -48, 124, -124,
                -23, 16, 88, -118, 121, 54, -53, 1, 44, 32, 81, 19, 25, -115, -43, -32, -64, -67, -120, -110, -101, 121,
                -2, 2
        };

        byte[] secondPayload = new byte[] {
                -86, 86, 42, 46, 77, 78, 78, 45, 6, 26, 83, 82, 84, -102, -86, 3, -28, 38, 21, 39, 23, 101, 38, -91, 2,
                -51, -51, 47, 74, 73, 45, 114, -54, -49, -49, -10, 49, -78, -118, 112, 10, 9, 13, 118, 1, -102, 84,
                -108, 90, 88, 10, 116, 27, -56, -84, 124, -112, -13, 16, 26, 116, -108, 18, -117, -46, -127, 6, 69, 99,
                -45, 24, 91, 91, 11, 0
        };

        Map<String, String> parameters =  Collections.singletonMap(CLIENT_NO_CONTEXT, null);

        WebSocketClientExtension extension = handshaker.handshakeExtension(
                new WebSocketExtensionData(PERMESSAGE_DEFLATE_EXTENSION, parameters));
        assertNotNull(extension);

        EmbeddedChannel decoderChannel = new EmbeddedChannel(extension.newExtensionDecoder());
        assertTrue(
                decoderChannel.writeInbound(new TextWebSocketFrame(true, RSV1, Unpooled.copiedBuffer(firstPayload))));
        TextWebSocketFrame firstFrameDecompressed = decoderChannel.readInbound();
        assertTrue(
                decoderChannel.writeInbound(new TextWebSocketFrame(true, RSV1, Unpooled.copiedBuffer(secondPayload))));
        TextWebSocketFrame secondFrameDecompressed = decoderChannel.readInbound();

        assertNotNull(firstFrameDecompressed);
        assertNotNull(firstFrameDecompressed.content());
        assertTrue(firstFrameDecompressed instanceof TextWebSocketFrame);
        assertEquals(firstFrameDecompressed.text(),
                     "{\"info\":\"Welcome to the BitMEX Realtime API.\",\"version\"" +
                     ":\"2018-10-02T22:53:23.000Z\",\"timestamp\":\"2018-10-15T06:43:40.437Z\"," +
                     "\"docs\":\"https://www.bitmex.com/app/wsAPI\",\"limit\":{\"remaining\":39}}");
        assertTrue(firstFrameDecompressed.release());

        assertNotNull(secondFrameDecompressed);
        assertNotNull(secondFrameDecompressed.content());
        assertTrue(secondFrameDecompressed instanceof TextWebSocketFrame);
        assertEquals(secondFrameDecompressed.text(),
                     "{\"success\":true,\"subscribe\":\"orderBookL2:XBTUSD\"," +
                     "\"request\":{\"op\":\"subscribe\",\"args\":[\"orderBookL2:XBTUSD\"]}}");
        assertTrue(secondFrameDecompressed.release());

        assertFalse(decoderChannel.finish());
    }