Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You 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.apache.tomcat.websocket;
 
 import static org.jboss.web.WebsocketsMessages.MESSAGES;
 
 import java.util.List;
 
 
 public class PerMessageDeflate implements Transformation {
 
     private static final String SERVER_NO_CONTEXT_TAKEOVER = "server_no_context_takeover";
     private static final String CLIENT_NO_CONTEXT_TAKEOVER = "client_no_context_takeover";
     private static final String SERVER_MAX_WINDOW_BITS = "server_max_window_bits";
     private static final String CLIENT_MAX_WINDOW_BITS = "client_max_window_bits";
 
     private static final int RSV_BITMASK = 0x4;
     private static final byte[] EOM_BYTES = new byte[] {0, 0, -1, -1};
 
     public static final String NAME = "permessage-deflate";
 
     private final boolean serverContextTakeover;
     private final int serverMaxWindowBits;
     private final boolean clientContextTakeover;
     private final int clientMaxWindowBits;
     private final boolean isServer;
     private final Inflater inflater = new Inflater(true);
     private final ByteBuffer readBuffer = ByteBuffer.allocate(.);
     private final Deflater deflater = new Deflater(.true);
     private final byte[] EOM_BUFFER = new byte[. + 1];
 
     private volatile Transformation next;
     private volatile boolean skipDecompression = false;
     private volatile ByteBuffer writeBuffer = ByteBuffer.allocate(.);
     private volatile boolean firstCompressedFrameWritten = false;
 
     static PerMessageDeflate negotiate(List<List<Parameter>> preferencesboolean isServer) {
         // Accept the first preference that the endpoint is able to support
         for (List<Parameterpreference : preferences) {
             boolean ok = true;
             boolean serverContextTakeover = true;
             int serverMaxWindowBits = -1;
             boolean clientContextTakeover = true;
             int clientMaxWindowBits = -1;
 
             for (Parameter param : preference) {
                 if (.equals(param.getName())) {
                     if (serverContextTakeover) {
                         serverContextTakeover = false;
                     } else {
                         // Duplicate definition
                         throw .duplicateDeflateParameter();
                     }
                 } else if (.equals(param.getName())) {
                     if (clientContextTakeover) {
                         clientContextTakeover = false;
                     } else {
                         // Duplicate definition
                         throw .duplicateDeflateParameter( );
                     }
                 } else if (.equals(param.getName())) {
                     if (serverMaxWindowBits == -1) {
                         serverMaxWindowBits = Integer.parseInt(param.getValue());
                         if (serverMaxWindowBits < 8 || serverMaxWindowBits > 15) {
                             throw .invalidDeflateWindowSize(,
                                     Integer.valueOf(serverMaxWindowBits));
                         }
                         // Java SE API (as of Java 8) does not expose the API to
                         // control the Window size. It is effectively hard-coded
                         // to 15
                         if (isServer && serverMaxWindowBits != 15) {
                             ok = false;
                             break;
                             // Note server window size is not an issue for the
                             // client since the client will assume 15 and if the
                             // server uses a smaller window everything will
                            // still work
                        }
                    } else {
                        // Duplicate definition
                        throw .duplicateDeflateParameter( );
                    }
                } else if (.equals(param.getName())) {
                    if (clientMaxWindowBits == -1) {
                        if (param.getValue() == null) {
                            // Hint to server that the client supports this
                            // option. Java SE API (as of Java 8) does not
                            // expose the API to control the Window size. It is
                            // effectively hard-coded to 15
                            clientMaxWindowBits = 15;
                        } else {
                            clientMaxWindowBits = Integer.parseInt(param.getValue());
                            if (clientMaxWindowBits < 8 || clientMaxWindowBits > 15) {
                                throw .invalidDeflateWindowSize(,
                                        Integer.valueOf(clientMaxWindowBits));
                            }
                        }
                        // Java SE API (as of Java 8) does not expose the API to
                        // control the Window size. It is effectively hard-coded
                        // to 15
                        if (!isServer && clientMaxWindowBits != 15) {
                            ok = false;
                            break;
                            // Note client window size is not an issue for the
                            // server since the server will assume 15 and if the
                            // client uses a smaller window everything will
                            // still work
                        }
                    } else {
                        // Duplicate definition
                        throw .duplicateDeflateParameter();
                    }
                } else {
                    // Unknown parameter
                    throw .unkownDeflateParameter(param.getName());
                }
            }
            if (ok) {
                return new PerMessageDeflate(serverContextTakeoverserverMaxWindowBits,
                        clientContextTakeoverclientMaxWindowBitsisServer);
            }
        }
        // Failed to negotiate agreeable terms
        return null;
    }
    private PerMessageDeflate(boolean serverContextTakeoverint serverMaxWindowBits,
            boolean clientContextTakeoverint clientMaxWindowBitsboolean isServer) {
        this. = serverContextTakeover;
        this. = serverMaxWindowBits;
        this. = clientContextTakeover;
        this. = clientMaxWindowBits;
        this. = isServer;
    }
    @Override
    public TransformationResult getMoreData(byte opCodeboolean finint rsvByteBuffer dest)
            throws IOException {
        // Control frames are never compressed and may appear in the middle of
        // a WebSocket method. Pass them straight through.
        if (Util.isControl(opCode)) {
            return .getMoreData(opCodefinrsvdest);
        }
        if (!Util.isContinuation(opCode)) {
            // First frame in new message
             = (rsv & ) == 0;
        }
        // Pass uncompressed frames straight through.
        if () {
            return .getMoreData(opCodefinrsvdest);
        }
        int written;
        boolean usedEomBytes = false;
        while (dest.remaining() > 0) {
            // Space available in destination. Try and fill it.
            try {
                written = .inflate(
                        dest.array(), dest.arrayOffset() + dest.position(), dest.remaining());
            } catch (DataFormatException e) {
                throw new IOException(.deflateFailure(), e);
            }
            dest.position(dest.position() + written);
            if (.needsInput() && !usedEomBytes ) {
                if (dest.hasRemaining()) {
                    .clear();
                    TransformationResult nextResult =
                            .getMoreData(opCodefin, (rsv ^ ), );
                    .setInput(
                            .array(), .arrayOffset(), .position());
                    if (..equals(nextResult)) {
                        return nextResult;
                    } else if (..equals(nextResult) &&
                            .position() == 0) {
                        if (fin) {
                            .setInput();
                            usedEomBytes = true;
                        } else {
                            return .;
                        }
                    }
                }
            } else if (written == 0) {
                if (fin && ( && ! ||
                        ! && !)) {
                    .reset();
                }
                return .;
            }
        }
        return .;
    }
    @Override
    public boolean validateRsv(int rsvbyte opCode) {
        if (Util.isControl(opCode)) {
            if ((rsv & ) > 0) {
                return false;
            } else {
                if ( == null) {
                    return true;
                } else {
                    return .validateRsv(rsvopCode);
                }
            }
        } else {
            int rsvNext = rsv;
            if ((rsv & ) > 0) {
                rsvNext = rsv ^ ;
            }
            if ( == null) {
                return true;
            } else {
                return .validateRsv(rsvNextopCode);
            }
        }
    }
    @Override
    public Extension getExtensionResponse() {
        Extension result = new WsExtension();
        List<Extension.Parameterparams = result.getParameters();
        if (!) {
            params.add(new WsExtensionParameter(null));
        }
        if ( != -1) {
            params.add(new WsExtensionParameter(,
                    Integer.toString()));
        }
        if (!) {
            params.add(new WsExtensionParameter(null));
        }
        if ( != -1) {
            params.add(new WsExtensionParameter(,
                    Integer.toString()));
        }
        return result;
    }
    @Override
    public void setNext(Transformation t) {
        if ( == null) {
            this. = t;
        } else {
            .setNext(t);
        }
    }
    @Override
    public boolean validateRsvBits(int i) {
        if ((i & ) > 0) {
            return false;
        }
        if ( == null) {
            return true;
        } else {
            return .validateRsvBits(i | );
        }
    }
    @Override
    public List<MessagePartsendMessagePart(List<MessagePartuncompressedParts) {
        List<MessagePartallCompressedParts = new ArrayList<MessagePart>();
        for (MessagePart uncompressedPart : uncompressedParts) {
            byte opCode = uncompressedPart.getOpCode();
            if (Util.isControl(opCode)) {
                // Control messages can appear in the middle of other messages
                // and must not be compressed. Pass it straight through
                allCompressedParts.add(uncompressedPart);
            } else {
                List<MessagePartcompressedParts = new ArrayList<MessagePart>();
                ByteBuffer uncompressedPayload = uncompressedPart.getPayload();
                SendHandler uncompressedIntermediateHandler =
                        uncompressedPart.getIntermediateHandler();
                .setInput(uncompressedPayload.array(),
                        uncompressedPayload.arrayOffset() + uncompressedPayload.position(),
                        uncompressedPayload.remaining());
                int flush = (uncompressedPart.isFin() ? . : .);
                boolean deflateRequired = true;
                while(deflateRequired) {
                    ByteBuffer compressedPayload = ;
                    int written = .deflate(compressedPayload.array(),
                            compressedPayload.arrayOffset() + compressedPayload.position(),
                            compressedPayload.remaining(), flush);
                    compressedPayload.position(compressedPayload.position() + written);
                    if (!uncompressedPart.isFin() && compressedPayload.hasRemaining() && .needsInput()) {
                        // This message part has been fully processed by the
                        // deflater. Fire the send handler for this message part
                        // and move on to the next message part.
                        break;
                    }
                    // If this point is reached, a new compressed message part
                    // will be created...
                    MessagePart compressedPart;
                    // .. and a new writeBuffer will be required.
                     = ByteBuffer.allocate(.);
                    // Flip the compressed payload ready for writing
                    compressedPayload.flip();
                    boolean fin = uncompressedPart.isFin();
                    boolean full = compressedPayload.limit() == compressedPayload.capacity();
                    boolean needsInput = .needsInput();
                    if (fin && !full && needsInput) {
                        // End of compressed message. Drop EOM bytes and output.
                        compressedPayload.limit(compressedPayload.limit() - .);
                        compressedPart = new MessagePart(truegetRsv(uncompressedPart),
                                opCodecompressedPayloaduncompressedIntermediateHandler,
                                uncompressedIntermediateHandler);
                        deflateRequired = false;
                        startNewMessage();
                    } else if (full && !needsInput) {
                        // Write buffer full and input message not fully read.
                        // Output and start new compressed part.
                        compressedPart = new MessagePart(falsegetRsv(uncompressedPart),
                                opCodecompressedPayloaduncompressedIntermediateHandler,
                                uncompressedIntermediateHandler);
                    } else if (!fin && full && needsInput) {
                        // Write buffer full and input message not fully read.
                        // Output and get more data.
                        compressedPart = new MessagePart(falsegetRsv(uncompressedPart),
                                opCodecompressedPayloaduncompressedIntermediateHandler,
                                uncompressedIntermediateHandler);
                        deflateRequired = false;
                    } else if (fin && full && needsInput) {
                        // Write buffer full. Input fully read. Deflater may be
                        // in one of four states:
                        // - output complete (just happened to align with end of
                        //   buffer
                        // - in middle of EOM bytes
                        // - about to write EOM bytes
                        // - more data to write
                        int eomBufferWritten = .deflate(, 0, ..);
                        if (eomBufferWritten < .) {
                            // EOM has just been completed
                            compressedPayload.limit(compressedPayload.limit() - . + eomBufferWritten);
                            compressedPart = new MessagePart(true,
                                    getRsv(uncompressedPart), opCodecompressedPayload,
                                    uncompressedIntermediateHandleruncompressedIntermediateHandler);
                            deflateRequired = false;
                            startNewMessage();
                        } else {
                            // More data to write
                            // Copy bytes to new write buffer
                            .put(, 0, eomBufferWritten);
                            compressedPart = new MessagePart(false,
                                    getRsv(uncompressedPart), opCodecompressedPayload,
                                    uncompressedIntermediateHandleruncompressedIntermediateHandler);
                        }
                    } else {
                        throw new IllegalStateException("Should never happen");
                    }
                    // Add the newly created compressed part to the set of parts
                    // to pass on to the next transformation.
                    compressedParts.add(compressedPart);
                }
                SendHandler uncompressedEndHandler = uncompressedPart.getEndHandler();
                int size = compressedParts.size();
                if (size > 0) {
                    compressedParts.get(size - 1).setEndHandler(uncompressedEndHandler);
                }
                allCompressedParts.addAll(compressedParts);
            }
        }
        if ( == null) {
            return allCompressedParts;
        } else {
            return .sendMessagePart(allCompressedParts);
        }
    }
    private void startNewMessage() {
         = false;
        if ( && ! || ! && !) {
            .reset();
        }
    }
    private int getRsv(MessagePart uncompressedMessagePart) {
        int result = uncompressedMessagePart.getRsv();
        if (!) {
            result += ;
             = true;
        }
        return result;
    }
New to GrepCode? Check out our FAQ X