Give a choice for app to extend the length limitation of clientId even in mqtt v3.1 on the server side (#11205)

Motivation:

In the mqtt v3.1 protocol, the default maximum Client Identifier length is 23.However, in (#11114), there are many cases, the server may still receive a client ID with a length greater than 23. Perhaps should consider letting the user decide whether accept client id greater than 23 on the server side

Modification:

- Allow to specify max length.

Result:

Give a choice for app to extend the length limitation of clientId even in mqtt v3.1 on the server side.

Signed-off-by: xingrufei <xingrufei@sogou-inc.com>

Co-authored-by: xingrufei <xingrufei@sogou-inc.com>
This commit is contained in:
skyguard1 2021-04-28 22:20:59 +08:00 committed by Norman Maurer
parent 8636aad989
commit 438632a3ac
4 changed files with 61 additions and 11 deletions

View File

@ -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<MqttVersion> 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 ClientIds

View File

@ -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;
}

View File

@ -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<DecoderState> {
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<DecoderState> {
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<DecoderState> {
buffer,
mqttFixedHeader.messageType(),
bytesRemainingInVariablePart,
maxClientIdLength,
variableHeader);
bytesRemainingInVariablePart -= decodedPayload.numberOfBytesConsumed;
if (bytesRemainingInVariablePart != 0) {
@ -434,10 +442,11 @@ public final class MqttDecoder extends ReplayingDecoder<DecoderState> {
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<DecoderState> {
private static Result<MqttConnectPayload> decodeConnectionPayload(
ByteBuf buffer,
int maxClientIdLength,
MqttConnectVariableHeader mqttConnectVariableHeader) {
final Result<String> 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;

View File

@ -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<MqttMessage> {
// 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);