/*
 * 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 javax.websocket.CloseReason.CloseCode;
import javax.websocket.CloseReason.CloseCodes;

/**
 * Utility class for internal use only within the
 * {@link org.apache.tomcat.websocket} package.
 */
class Util {

    private Util() {
        // Hide default constructor
    }


    static boolean isControl(byte opCode) {
        return (opCode & 0x08) > 0;
    }


    static boolean isText(byte opCode) {
        return opCode == Constants.OPCODE_TEXT;
    }


    static CloseCode getCloseCode(int code) {
        if (code > 2999 && code < 5000) {
            return CloseCodes.NORMAL_CLOSURE;
        }
        switch (code) {
            case 1000:
                return CloseCodes.NORMAL_CLOSURE;
            case 1001:
                return CloseCodes.GOING_AWAY;
            case 1002:
                return CloseCodes.PROTOCOL_ERROR;
            case 1003:
                return CloseCodes.CANNOT_ACCEPT;
            case 1004:
                // Should not be used in a close frame
                // return CloseCodes.RESERVED;
                return CloseCodes.PROTOCOL_ERROR;
            case 1005:
                // Should not be used in a close frame
                // return CloseCodes.NO_STATUS_CODE;
                return CloseCodes.PROTOCOL_ERROR;
            case 1006:
                // Should not be used in a close frame
                // return CloseCodes.CLOSED_ABNORMALLY;
                return CloseCodes.PROTOCOL_ERROR;
            case 1007:
                return CloseCodes.NOT_CONSISTENT;
            case 1008:
                return CloseCodes.VIOLATED_POLICY;
            case 1009:
                return CloseCodes.TOO_BIG;
            case 1010:
                return CloseCodes.NO_EXTENSION;
            case 1011:
                return CloseCodes.UNEXPECTED_CONDITION;
            case 1012:
                // Not in RFC6455
                // return CloseCodes.SERVICE_RESTART;
                return CloseCodes.PROTOCOL_ERROR;
            case 1013:
                // Not in RFC6455
                // return CloseCodes.TRY_AGAIN_LATER;
                return CloseCodes.PROTOCOL_ERROR;
            case 1015:
                // Should not be used in a close frame
                // return CloseCodes.TLS_HANDSHAKE_FAILURE;
                return CloseCodes.PROTOCOL_ERROR;
            default:
                return CloseCodes.PROTOCOL_ERROR;
        }
    }
}

@@ -833,16 +833,174 @@
 ocket;%0A%0A
+import java.security.NoSuchAlgorithmException;%0Aimport java.security.SecureRandom;%0Aimport java.util.Queue;%0Aimport java.util.concurrent.ConcurrentLinkedQueue;%0A%0A
 import j
@@ -1205,16 +1205,115 @@
 Util %7B%0A%0A
+    private static final Queue%3CSecureRandom%3E randoms =%0A            new ConcurrentLinkedQueue%3C%3E();%0A%0A
     priv
@@ -3509,10 +3509,921 @@
 %7D%0A    %7D%0A
+%0A%0A    static byte%5B%5D generateMask() %7B%0A        // SecureRandom is not thread-safe so need to make sure only one thread%0A        // uses it at a time. In theory, the pool could grow to the same size%0A        // as the number of request processing threads. In reality it will be%0A        // a lot smaller.%0A%0A        // Get a SecureRandom from the pool%0A        SecureRandom sr = randoms.poll();%0A%0A        // If one isn't available, generate a new one%0A        if (sr == null) %7B%0A            try %7B%0A                sr = SecureRandom.getInstance(%22SHA1PRNG%22);%0A            %7D catch (NoSuchAlgorithmException e) %7B%0A                // Fall back to platform default%0A                sr = new SecureRandom();%0A            %7D%0A        %7D%0A%0A        // Generate the mask%0A        byte%5B%5D result = new byte%5B4%5D;%0A        sr.nextBytes(result);%0A%0A        // Put the SecureRandom back in the poll%0A        randoms.add(sr);%0A%0A        return result;%0A    %7D%0A
 %7D%0A

Add a utility method for generating secure masks for client data.