<commit_before>//
//  ========================================================================
//  Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.websocket.core.extensions.deflate;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.api.BadPayloadException;
import org.eclipse.jetty.websocket.core.api.Extension;
import org.eclipse.jetty.websocket.core.protocol.ExtensionConfig;
import org.eclipse.jetty.websocket.core.protocol.WebSocketFrame;

/**
 * Implementation of the <a href="https://tools.ietf.org/id/draft-tyoshino-hybi-websocket-perframe-deflate-05.txt">x-webkit-deflate-frame</a> extension seen out
 * in the wild.
 */
public class WebkitDeflateFrameExtension extends Extension
{
    private static final Logger LOG = Log.getLogger(WebkitDeflateFrameExtension.class);
    private static final int BUFFER_SIZE = 64 * 1024;

    private Deflater deflater;
    private Inflater inflater;

    public ByteBuffer deflate(ByteBuffer data)
    {
        int length = data.remaining();

        // prepare the uncompressed input
        deflater.reset();
        deflater.setInput(BufferUtil.toArray(data));
        deflater.finish();

        // prepare the output buffer
        int bufsize = Math.max(BUFFER_SIZE,length * 2);
        ByteBuffer buf = getBufferPool().acquire(bufsize,false);
        BufferUtil.clearToFill(buf);

        if (LOG.isDebugEnabled())
        {
            LOG.debug("Uncompressed length={} - {}",length,buf.position());
        }

        while (!deflater.finished())
        {
            byte out[] = new byte[BUFFER_SIZE];
            int len = deflater.deflate(out,0,out.length,Deflater.SYNC_FLUSH);

            if (LOG.isDebugEnabled())
            {
                LOG.debug("Deflater: finished={}, needsInput={}, len={} / input.len={}",deflater.finished(),deflater.needsInput(),len,length);
            }

            buf.put(out,0,len);
        }
        BufferUtil.flipToFlush(buf,0);

        /* Per the spec, it says that BFINAL 1 or 0 are allowed.
         * However, Java always uses BFINAL 1, where the browsers
         * Chrome and Safari fail to decompress when it encounters
         * BFINAL 1.
         * 
         * This hack will always set BFINAL 0
         */
        byte b0 = buf.get(0);
        if ((b0 & 1) != 0) // if BFINAL 1
        {
            buf.put(0,(b0 ^= 1)); // flip bit to BFINAL 0
        }
        return buf;
    }

    @Override
    public void incoming(WebSocketFrame frame)
    {
        if (frame.isControlFrame() || !frame.isRsv1())
        {
            // Cannot modify incoming control frames or ones with RSV1 set.
            super.incoming(frame);<commit_msg>Bug 391591 - WebSocket client should support x-webkit-deflate-frame<commit_after>//
//  ========================================================================
//  Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.websocket.core.extensions.deflate;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.api.BadPayloadException;
import org.eclipse.jetty.websocket.core.api.Extension;
import org.eclipse.jetty.websocket.core.protocol.ExtensionConfig;
import org.eclipse.jetty.websocket.core.protocol.WebSocketFrame;

/**
 * Implementation of the <a href="https://tools.ietf.org/id/draft-tyoshino-hybi-websocket-perframe-deflate-05.txt">x-webkit-deflate-frame</a> extension seen out
 * in the wild.
 */
public class WebkitDeflateFrameExtension extends Extension
{
    private static final Logger LOG = Log.getLogger(WebkitDeflateFrameExtension.class);
    private static final int BUFFER_SIZE = 64 * 1024;
    private static final boolean BFINAL_HACK = Boolean.parseBoolean(System.getProperty("jetty.websocket.bfinal.hack","true"));

    private Deflater deflater;
    private Inflater inflater;

    public ByteBuffer deflate(ByteBuffer data)
    {
        int length = data.remaining();

        // prepare the uncompressed input
        deflater.reset();
        deflater.setInput(BufferUtil.toArray(data));
        deflater.finish();

        // prepare the output buffer
        int bufsize = Math.max(BUFFER_SIZE,length * 2);
        ByteBuffer buf = getBufferPool().acquire(bufsize,false);
        BufferUtil.clearToFill(buf);

        if (LOG.isDebugEnabled())
        {
            LOG.debug("Uncompressed length={} - {}",length,buf.position());
        }

        while (!deflater.finished())
        {
            byte out[] = new byte[BUFFER_SIZE];
            int len = deflater.deflate(out,0,out.length,Deflater.SYNC_FLUSH);

            if (LOG.isDebugEnabled())
            {
                LOG.debug("Deflater: finished={}, needsInput={}, len={} / input.len={}",deflater.finished(),deflater.needsInput(),len,length);
            }

            buf.put(out,0,len);
        }
        BufferUtil.flipToFlush(buf,0);

        if (BFINAL_HACK)
        {
            /* Per the spec, it says that BFINAL 1 or 0 are allowed.
             * However, Java always uses BFINAL 1, where the browsers
             * Chrome and Safari fail to decompress when it encounters
             * BFINAL 1.
             * 
             * This hack will always set BFINAL 0
             */
            byte b0 = buf.get(0);
            if ((b0 & 1) != 0) // if BFINAL 1
            {
                buf.put(0,(b0 ^= 1)); // flip bit to BFINAL 0
            }
        }
        return buf;
    }

    @Override
    public void incoming(WebSocketFrame frame)
    {
        if (frame.isControlFrame() || !frame.isRsv1())
        {
            // Cannot modify incoming control frames or ones with RSV1 set.
            super.incoming(frame);
{'fraction_non_alphanumeric': 0.16440501043841335, 'fraction_numerical': 0.013048016701461378, 'mean_word_length': 2.4777676950998186, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4338709', 'n_tokens_mistral': 2296, 'n_tokens_neox': 2140, 'n_words': 529}