diff --git a/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttCodecUtil.java b/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttCodecUtil.java index 9969e7b2f5..788b6a4185 100644 --- a/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttCodecUtil.java +++ b/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttCodecUtil.java @@ -21,11 +21,11 @@ import io.netty.handler.codec.DecoderException; import io.netty.util.Attribute; import io.netty.util.AttributeKey; +import static io.netty.handler.codec.mqtt.MqttConstant.MIN_CLIENT_ID_LENGTH; + final class MqttCodecUtil { private static final char[] TOPIC_WILDCARDS = {'#', '+'}; - private static final int MIN_CLIENT_ID_LENGTH = 1; - private static final int MAX_CLIENT_ID_LENGTH = 23; static final AttributeKey MQTT_VERSION_KEY = AttributeKey.valueOf("NETTY_CODEC_MQTT_VERSION"); @@ -57,10 +57,10 @@ final class MqttCodecUtil { return messageId != 0; } - static boolean isValidClientId(MqttVersion mqttVersion, String clientId) { + static boolean isValidClientId(MqttVersion mqttVersion, int maxClientIdLength, String clientId) { if (mqttVersion == MqttVersion.MQTT_3_1) { return clientId != null && clientId.length() >= MIN_CLIENT_ID_LENGTH && - clientId.length() <= MAX_CLIENT_ID_LENGTH; + clientId.length() <= maxClientIdLength; } if (mqttVersion == MqttVersion.MQTT_3_1_1 || mqttVersion == MqttVersion.MQTT_5) { // In 3.1.3.1 Client Identifier of MQTT 3.1.1 and 5.0 specifications, The Server MAY allow ClientId’s diff --git a/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttConstant.java b/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttConstant.java new file mode 100644 index 0000000000..3de70310b3 --- /dev/null +++ b/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttConstant.java @@ -0,0 +1,39 @@ +/* + * Copyright 2021 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: + * + * https://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.mqtt; + +public final class MqttConstant { + + private MqttConstant() { + } + + /** + * Default max bytes in message + */ + public static final int DEFAULT_MAX_BYTES_IN_MESSAGE = 8092; + + /** + * min client id length + */ + public static final int MIN_CLIENT_ID_LENGTH = 1; + + /** + * Default max client id length,In the mqtt3.1 protocol, + * the default maximum Client Identifier length is 23 + */ + public static final int DEFAULT_MAX_CLIENT_ID_LENGTH = 23; + +} diff --git a/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttDecoder.java b/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttDecoder.java index e1e26ff00d..5594b35866 100644 --- a/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttDecoder.java +++ b/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttDecoder.java @@ -24,6 +24,7 @@ import io.netty.handler.codec.TooLongFrameException; import io.netty.handler.codec.mqtt.MqttDecoder.DecoderState; import io.netty.handler.codec.mqtt.MqttProperties.IntegerProperty; import io.netty.util.CharsetUtil; +import io.netty.util.internal.ObjectUtil; import java.util.ArrayList; import java.util.List; @@ -33,6 +34,8 @@ import static io.netty.handler.codec.mqtt.MqttCodecUtil.isValidMessageId; import static io.netty.handler.codec.mqtt.MqttCodecUtil.isValidPublishTopicName; import static io.netty.handler.codec.mqtt.MqttCodecUtil.resetUnusedFields; import static io.netty.handler.codec.mqtt.MqttCodecUtil.validateFixedHeader; +import static io.netty.handler.codec.mqtt.MqttConstant.DEFAULT_MAX_BYTES_IN_MESSAGE; +import static io.netty.handler.codec.mqtt.MqttConstant.DEFAULT_MAX_CLIENT_ID_LENGTH; import static io.netty.handler.codec.mqtt.MqttSubscriptionOption.RetainedHandlingPolicy; /** @@ -45,8 +48,6 @@ import static io.netty.handler.codec.mqtt.MqttSubscriptionOption.RetainedHandlin */ public final class MqttDecoder extends ReplayingDecoder { - private static final int DEFAULT_MAX_BYTES_IN_MESSAGE = 8092; - /** * States of the decoder. * We start at READ_FIXED_HEADER, followed by @@ -64,14 +65,20 @@ public final class MqttDecoder extends ReplayingDecoder { private int bytesRemainingInVariablePart; private final int maxBytesInMessage; + private final int maxClientIdLength; public MqttDecoder() { - this(DEFAULT_MAX_BYTES_IN_MESSAGE); + this(DEFAULT_MAX_BYTES_IN_MESSAGE, DEFAULT_MAX_CLIENT_ID_LENGTH); } public MqttDecoder(int maxBytesInMessage) { + this(maxBytesInMessage, DEFAULT_MAX_CLIENT_ID_LENGTH); + } + + public MqttDecoder(int maxBytesInMessage, int maxClientIdLength) { super(DecoderState.READ_FIXED_HEADER); - this.maxBytesInMessage = maxBytesInMessage; + this.maxBytesInMessage = ObjectUtil.checkPositive(maxBytesInMessage, "maxBytesInMessage"); + this.maxClientIdLength = ObjectUtil.checkPositive(maxClientIdLength, "maxClientIdLength"); } @Override @@ -108,6 +115,7 @@ public final class MqttDecoder extends ReplayingDecoder { buffer, mqttFixedHeader.messageType(), bytesRemainingInVariablePart, + maxClientIdLength, variableHeader); bytesRemainingInVariablePart -= decodedPayload.numberOfBytesConsumed; if (bytesRemainingInVariablePart != 0) { @@ -434,10 +442,11 @@ public final class MqttDecoder extends ReplayingDecoder { ByteBuf buffer, MqttMessageType messageType, int bytesRemainingInVariablePart, + int maxClientIdLength, Object variableHeader) { switch (messageType) { case CONNECT: - return decodeConnectionPayload(buffer, (MqttConnectVariableHeader) variableHeader); + return decodeConnectionPayload(buffer, maxClientIdLength, (MqttConnectVariableHeader) variableHeader); case SUBSCRIBE: return decodeSubscribePayload(buffer, bytesRemainingInVariablePart); @@ -462,12 +471,13 @@ public final class MqttDecoder extends ReplayingDecoder { private static Result decodeConnectionPayload( ByteBuf buffer, + int maxClientIdLength, MqttConnectVariableHeader mqttConnectVariableHeader) { final Result decodedClientId = decodeString(buffer); final String decodedClientIdValue = decodedClientId.value; final MqttVersion mqttVersion = MqttVersion.fromProtocolNameAndLevel(mqttConnectVariableHeader.name(), (byte) mqttConnectVariableHeader.version()); - if (!isValidClientId(mqttVersion, decodedClientIdValue)) { + if (!isValidClientId(mqttVersion, maxClientIdLength, decodedClientIdValue)) { throw new MqttIdentifierRejectedException("invalid clientIdentifier: " + decodedClientIdValue); } int numberOfBytesConsumed = decodedClientId.numberOfBytesConsumed; diff --git a/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttEncoder.java b/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttEncoder.java index 81c17d25bc..9a601ead1c 100644 --- a/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttEncoder.java +++ b/codec-mqtt/src/main/java/io/netty/handler/codec/mqtt/MqttEncoder.java @@ -31,6 +31,7 @@ import static io.netty.buffer.ByteBufUtil.*; import static io.netty.handler.codec.mqtt.MqttCodecUtil.getMqttVersion; import static io.netty.handler.codec.mqtt.MqttCodecUtil.isValidClientId; import static io.netty.handler.codec.mqtt.MqttCodecUtil.setMqttVersion; +import static io.netty.handler.codec.mqtt.MqttConstant.DEFAULT_MAX_CLIENT_ID_LENGTH; /** * Encodes Mqtt messages into bytes following the protocol specification v3.1 @@ -124,7 +125,7 @@ public final class MqttEncoder extends MessageToMessageEncoder { // Client id String clientIdentifier = payload.clientIdentifier(); - if (!isValidClientId(mqttVersion, clientIdentifier)) { + if (!isValidClientId(mqttVersion, DEFAULT_MAX_CLIENT_ID_LENGTH, clientIdentifier)) { throw new MqttIdentifierRejectedException("invalid clientIdentifier: " + clientIdentifier); } int clientIdentifierBytes = utf8Bytes(clientIdentifier);