Fix random number generators in WebSocketUtil
Motivation: Implementation of WebSocketUtil/randomNumber is incorrect and might violate the API returning values > maximum specified. Modifications: * WebSocketUtil/randomNumber is reimplemented, the idea of the solution described in the comment in the code * Implementation of WebSocketUtil/randomBytes changed to nextBytes method * PlatformDependet.threadLocalRandom is used instead of Math.random to improve efficiency * Added test cases to check random numbers generator * To ensure corretness, we now assert that min < max when generating random number Result: WebSocketUtil/randomNumber always produces correct result. Covers https://github.com/netty/netty/issues/8023
This commit is contained in:
parent
9ffdec302e
commit
fa4e28ba1c
@ -20,6 +20,7 @@ import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.base64.Base64;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.concurrent.FastThreadLocal;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@ -105,11 +106,7 @@ final class WebSocketUtil {
|
||||
*/
|
||||
static byte[] randomBytes(int size) {
|
||||
byte[] bytes = new byte[size];
|
||||
|
||||
for (int index = 0; index < size; index++) {
|
||||
bytes[index] = (byte) randomNumber(0, 255);
|
||||
}
|
||||
|
||||
PlatformDependent.threadLocalRandom().nextBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@ -121,7 +118,29 @@ final class WebSocketUtil {
|
||||
* @return A pseudo-random number
|
||||
*/
|
||||
static int randomNumber(int minimum, int maximum) {
|
||||
return (int) (Math.random() * maximum + minimum);
|
||||
assert minimum < maximum;
|
||||
double fraction = PlatformDependent.threadLocalRandom().nextDouble();
|
||||
|
||||
// the idea here is that nextDouble gives us a random value
|
||||
//
|
||||
// 0 <= fraction <= 1
|
||||
//
|
||||
// the distance from min to max declared as
|
||||
//
|
||||
// dist = max - min
|
||||
//
|
||||
// satisfies the following
|
||||
//
|
||||
// min + dist = max
|
||||
//
|
||||
// taking into account
|
||||
//
|
||||
// 0 <= fraction * dist <= dist
|
||||
//
|
||||
// we've got
|
||||
//
|
||||
// min <= min + fraction * dist <= max
|
||||
return (int) (minimum + fraction * (maximum - minimum));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -240,8 +240,8 @@ public abstract class WebSocketClientHandshakerTest {
|
||||
}
|
||||
};
|
||||
|
||||
byte[] data = new byte[24];
|
||||
PlatformDependent.threadLocalRandom().nextBytes(data);
|
||||
// use randomBytes helper from utils to check that it functions properly
|
||||
byte[] data = WebSocketUtil.randomBytes(24);
|
||||
|
||||
// Create a EmbeddedChannel which we will use to encode a BinaryWebsocketFrame to bytes and so use these
|
||||
// to test the actual handshaker.
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2018 The Netty Project
|
||||
*
|
||||
* The Netty Project 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 io.netty.handler.codec.http.websocketx;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class WebSocketUtilTest {
|
||||
|
||||
// how many times do we want to run each random variable checker
|
||||
private static final int NUM_ITERATIONS = 1000;
|
||||
|
||||
private static void assertRandomWithinBoundaries(int min, int max) {
|
||||
int r = WebSocketUtil.randomNumber(min, max);
|
||||
assertTrue(min <= r && r <= max);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRandomNumberGenerator() {
|
||||
int iteration = 0;
|
||||
while (++iteration < NUM_ITERATIONS) {
|
||||
assertRandomWithinBoundaries(0, 1);
|
||||
assertRandomWithinBoundaries(0, 1);
|
||||
assertRandomWithinBoundaries(-1, 1);
|
||||
assertRandomWithinBoundaries(-1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user