You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ta...@apache.org on 2026/07/31 14:56:11 UTC
(qpid-proton-dotnet) branch main updated (1a1e130 -> 86c22fc)
This is an automated email from the ASF dual-hosted git repository.
tabish121 pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton-dotnet.git
from 1a1e130 NO-JIRA Update version for next development cycle
new 5a0c8bd Various codec correctness and performance improvements
new 57cecab Update version for next release cycle
new 86c22fc Update versions file for next development cycle
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.gitignore | 1 +
VERSION.txt | 2 +-
src/Proton.Client/Client/DecodeOptions.cs | 80 +
src/Proton.Client/Client/IDelivery.cs | 24 +
src/Proton.Client/Client/IStreamDelivery.cs | 22 +
.../Client/Implementation/ClientConnection.cs | 3 +-
.../Implementation/ClientConversionSupport.cs | 72 +
.../Client/Implementation/ClientDelivery.cs | 16 +
.../Client/Implementation/ClientMessageSupport.cs | 80 +-
.../Client/Implementation/ClientStreamDelivery.cs | 7 +-
.../Implementation/ClientStreamReceiverMessage.cs | 12 +-
src/Proton.Client/Client/StreamDecodeOptions.cs | 117 +
.../Decoders/AbstractDescribedListTypeDecoder.cs | 232 ++
.../Decoders/AbstractDescribedMapTypeDecoder.cs | 248 ++
.../Codec/Decoders/AbstractDescribedTypeDecoder.cs | 8 +-
.../Codec/Decoders/AbstractPrimitiveTypeDecoder.cs | 32 +-
.../Codec/Decoders/IPrimitiveArrayTypeDecoder.cs | 34 +
src/Proton/Codec/Decoders/IPrimitiveTypeDecoder.cs | 4 +
.../Decoders/Messaging/AcceptedTypeDecoder.cs | 66 +-
.../Decoders/Messaging/AmqpSequenceTypeDecoder.cs | 16 +-
.../Decoders/Messaging/AmqpValueTypeDecoder.cs | 50 +-
.../Messaging/ApplicationPropertiesTypeDecoder.cs | 136 +-
.../Codec/Decoders/Messaging/DataTypeDecoder.cs | 22 +-
.../Decoders/Messaging/DeleteOnCloseTypeDecoder.cs | 66 +-
.../DeleteOnNoLinksOrMessagesTypeDecoder.cs | 66 +-
.../Messaging/DeleteOnNoLinksTypeDecoder.cs | 66 +-
.../Messaging/DeleteOnNoMessagesTypeDecoder.cs | 66 +-
.../Messaging/DeliveryAnnotationsTypeDecoder.cs | 136 +-
.../Codec/Decoders/Messaging/FooterTypeDecoder.cs | 136 +-
.../Codec/Decoders/Messaging/HeaderTypeDecoder.cs | 94 +-
.../Messaging/MessageAnnotationsTypeDecoder.cs | 136 +-
.../Decoders/Messaging/ModifiedTypeDecoder.cs | 94 +-
.../Decoders/Messaging/PropertiesTypeDecoder.cs | 94 +-
.../Decoders/Messaging/ReceivedTypeDecoder.cs | 84 +-
.../Decoders/Messaging/RejectedTypeDecoder.cs | 112 +-
.../Decoders/Messaging/ReleasedTypeDecoder.cs | 66 +-
.../Codec/Decoders/Messaging/SourceTypeDecoder.cs | 94 +-
.../Codec/Decoders/Messaging/TargetTypeDecoder.cs | 94 +-
.../Primitives/AbstractArrayTypeDecoder.cs | 154 +-
.../Decoders/Primitives/AbstractBinaryDecoder.cs | 39 +-
.../Decoders/Primitives/AbstractListTypeDecoder.cs | 134 +-
.../Decoders/Primitives/AbstractMapTypeDecoder.cs | 163 +-
.../Primitives/AbstractStringTypeDecoder.cs | 38 +-
.../Primitives/AbstractSymbolTypeDecoder.cs | 52 +-
.../Decoders/Primitives/BooleanFalseTypeDecoder.cs | 22 +
.../Decoders/Primitives/BooleanTrueTypeDecoder.cs | 22 +
.../Codec/Decoders/Primitives/List0TypeDecoder.cs | 82 +-
.../Codec/Decoders/Primitives/NullTypeDecoder.cs | 36 +
...32TypeDecoder.cs => SaslSymbol32TypeDecoder.cs} | 8 +-
...ol8TypeDecoder.cs => SaslSymbol8TypeDecoder.cs} | 8 +-
.../Primitives/UnsignedInteger0TypeDecoder.cs | 24 +-
.../Primitives/UnsignedLong0TypeDecoder.cs | 24 +-
src/Proton/Codec/Decoders/ProtonDecoder.cs | 186 +-
src/Proton/Codec/Decoders/ProtonDecoderFactory.cs | 4 +-
src/Proton/Codec/Decoders/ProtonDecoderState.cs | 47 +-
src/Proton/Codec/Decoders/ProtonStreamDecoder.cs | 138 +-
.../Codec/Decoders/ProtonStreamDecoderFactory.cs | 4 +-
.../Codec/Decoders/ProtonStreamDecoderState.cs | 59 +-
src/Proton/Codec/Decoders/ProtonStreamReadUtils.cs | 5 +
.../Decoders/Security/SaslChallengeTypeDecoder.cs | 92 +-
.../Codec/Decoders/Security/SaslInitTypeDecoder.cs | 96 +-
.../Decoders/Security/SaslMechanismsTypeDecoder.cs | 92 +-
.../Decoders/Security/SaslOutcomeTypeDecoder.cs | 120 +-
.../Decoders/Security/SaslResponseTypeDecoder.cs | 92 +-
.../Transactions/CoordinatorTypeDecoder.cs | 94 +-
.../Decoders/Transactions/DeclareTypeDecoder.cs | 94 +-
.../Decoders/Transactions/DeclaredTypeDecoder.cs | 100 +-
.../Decoders/Transactions/DischargeTypeDecoder.cs | 116 +-
.../Transactions/TransactionalStateTypeDecoder.cs | 116 +-
.../Codec/Decoders/Transport/AttachTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/BeginTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/CloseTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/DetachTypeDecoder.cs | 90 +-
.../Decoders/Transport/DispositionTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/EndTypeDecoder.cs | 108 +-
.../Transport/ErrorConditionTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/FlowTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/OpenTypeDecoder.cs | 90 +-
.../Decoders/Transport/TransferTypeDecoder.cs | 90 +-
.../Codec/Decoders/UnknownDescribedTypeDecoder.cs | 87 +-
.../Encoders/AbstractDescribedMapTypeEncoder.cs | 41 +-
.../Messaging/ApplicationPropertiesTypeEncoder.cs | 10 +-
.../Messaging/DeliveryAnnotationsTypeEncoder.cs | 10 +-
.../Codec/Encoders/Messaging/FooterTypeEncoder.cs | 10 +-
.../Messaging/MessageAnnotationsTypeEncoder.cs | 10 +-
src/Proton/Codec/Encoders/ProtonEncoder.cs | 26 +-
src/Proton/Codec/Encoders/ProtonEncoderFactory.cs | 4 +-
src/Proton/Codec/IDecoderState.cs | 46 +
src/Proton/Codec/IStreamDecoderState.cs | 106 +
.../Exceptions/ProtocolViolationException.cs | 3 +-
src/Proton/Engine/IEngineConfiguration.cs | 14 +
.../Engine/Implementation/ProtonConstants.cs | 6 +
.../Implementation/ProtonEngineConfiguration.cs | 2 +
.../Implementation/ProtonFrameDecodingHandler.cs | 10 +-
.../Implementation/ProtonIncomingDelivery.cs | 29 +-
src/Proton/Engine/Implementation/ProtonReceiver.cs | 33 +-
.../Implementation/ProtonSessionIncomingWindow.cs | 52 +-
.../Implementation/ProtonSessionOutgoingWindow.cs | 29 +-
.../Implementation/ProtonTransactionManager.cs | 2 +-
.../Sasl/ProtonDefaultSaslClientAuthenticator.cs | 3 +-
.../Sasl/ProtonDefaultSaslServerAuthenticator .cs | 2 +-
.../Engine/Sasl/Client/AnonymousMechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/CramMD5Mechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/ExternalMechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/IMechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/PlainMechanism.cs | 2 +-
.../Engine/Sasl/Client/SaslMechanismSelector.cs | 2 +-
.../Engine/Sasl/Client/ScramSHA1Mechanism.cs | 2 +-
.../Engine/Sasl/Client/ScramSHA256Mechanism.cs | 2 +-
.../Engine/Sasl/Client/ScramSHA512Mechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/XOauth2Mechanism.cs | 2 +-
src/Proton/Types/Security/SaslChallenge.cs | 2 +-
src/Proton/Types/Security/SaslInit.cs | 2 +-
src/Proton/Types/Security/SaslMechanisms.cs | 2 +-
src/Proton/Types/Security/SaslOutcome.cs | 2 +-
src/Proton/Types/Security/SaslResponse.cs | 2 +-
src/Proton/Types/Symbol.cs | 239 +-
src/Proton/Types/UnknownDescribedType.cs | 2 +-
src/Proton/Utilities/StringUtils.cs | 48 +
src/Proton/Utilities/UnsettledDictionary.cs | 1722 +++++++++++++
.../Client/Implementation/ClientBaseTestFixture.cs | 56 +-
.../Client/Implementation/ClientReceiverTest.cs | 220 ++
.../Implementation/ClientStreamReceiverTest.cs | 276 +++
.../Implementation/ClilentTransactionsTest.cs | 3 +-
.../Codec/Decoders/ProtonDecoderTest.cs | 213 +-
.../Codec/Decoders/ProtonStreamDecoderTest.cs | 219 +-
.../Codec/Messaging/AcceptedTypeCodecTest.cs | 171 ++
.../Codec/Messaging/AmqpSequenceTypeCodecTest.cs | 79 +
.../Codec/Messaging/AmqpValueTypeCodecTest.cs | 295 +++
.../ApplicationPropertiesTypeCodecTest.cs | 674 ++++-
.../Codec/Messaging/DataTypeCodecTest.cs | 25 +
.../Codec/Messaging/DeleteOnCloseTypeCodecTest.cs | 170 ++
.../DeleteOnNoLinksOrMessagesCodecTest.cs | 170 ++
.../Messaging/DeleteOnNoLinksTypeCodecTest.cs | 169 ++
.../Messaging/DeleteOnNoMessagesTypeCodecTest.cs | 170 ++
.../Messaging/DeliveryAnnotationsTypeCodecTest.cs | 256 +-
.../Codec/Messaging/FooterTypeCodecTest.cs | 271 +-
.../Codec/Messaging/HeaderTypeCodecTest.cs | 233 ++
.../Messaging/MessageAnnotationsTypeCodecTest.cs | 268 +-
.../Codec/Messaging/ModifiedTypeCodecTest.cs | 8 +-
.../Codec/Messaging/RejectedTypeCodecTest.cs | 4 +-
.../Codec/Primitives/ArrayTypeCodecTest.cs | 320 +++
.../Codec/Primitives/BinaryTypeCodecTest.cs | 74 +
.../Codec/Primitives/BooleanTypeCodecTest.cs | 441 +++-
.../Codec/Primitives/ByteTypeCodecTest.cs | 189 ++
.../Codec/Primitives/CharacterTypeCodecTests.cs | 103 +
.../Codec/Primitives/DoubleTypeCodecTest.cs | 39 +
.../Codec/Primitives/FloatTypeCodecTest.cs | 39 +
.../Codec/Primitives/IntegerTypeCodecTest.cs | 81 +-
.../Codec/Primitives/ListTypeCodecTest.cs | 466 +++-
.../Codec/Primitives/LongTypeCodecTest.cs | 81 +-
.../Codec/Primitives/MapTypeCodecTest.cs | 323 ++-
.../Codec/Primitives/NullTypeCodecTest.cs | 229 +-
.../Codec/Primitives/ShortTypeCodecTest.cs | 39 +
.../Codec/Primitives/StringTypeCodecTest.cs | 109 +
.../Codec/Primitives/SymbolTypeCodecTest.cs | 109 +
.../Primitives/UnsignedIntegerTypeCodecTest.cs | 186 ++
.../Codec/Primitives/UnsignedLongTypeCodecTest.cs | 196 +-
.../Codec/Security/SaslChallengeTypeCodecTest.cs | 112 +
.../Codec/Security/SaslInitTypeCodecTest.cs | 30 +-
.../Codec/Security/SaslMechanismsTypeCodecTest.cs | 190 +-
.../Codec/Security/SaslOutcomeTypeCodecTest.cs | 112 +
.../Codec/Security/SaslResponseTypeCodecTest.cs | 112 +
.../Codec/UnknownDescribedTypeCodecTest.cs | 478 ++++
.../Engine/Implementation/ProtonDecodeErrorTest.cs | 30 +-
.../Engine/Implementation/ProtonReceiverTest.cs | 205 +-
.../Engine/Implementation/ProtonSessionTest.cs | 85 +
.../Implementation/Sasl/ProtonSaslHandlerTest.cs | 28 +-
.../Implementation/Sasl/ProtonSaslServerTest.cs | 8 +-
.../Engine/Sasl/Client/AbstractMechanismTest.cs | 2 +-
.../Engine/Sasl/Client/SaslMechanismsTest.cs | 2 +-
test/Proton.Tests/Types/Security/SaslInitTest.cs | 3 +-
.../Types/Security/SaslMechanismsTest.cs | 4 +-
test/Proton.Tests/Types/SymbolTest.cs | 166 ++
.../Utilities/UnsettledDictionaryTest.cs | 2592 ++++++++++++++++++++
175 files changed, 15504 insertions(+), 4072 deletions(-)
create mode 100644 src/Proton.Client/Client/DecodeOptions.cs
create mode 100644 src/Proton.Client/Client/StreamDecodeOptions.cs
create mode 100644 src/Proton/Codec/Decoders/AbstractDescribedListTypeDecoder.cs
create mode 100644 src/Proton/Codec/Decoders/AbstractDescribedMapTypeDecoder.cs
copy src/Proton/Codec/Decoders/Primitives/{Symbol32TypeDecoder.cs => SaslSymbol32TypeDecoder.cs} (82%)
copy src/Proton/Codec/Decoders/Primitives/{Symbol8TypeDecoder.cs => SaslSymbol8TypeDecoder.cs} (82%)
create mode 100644 src/Proton/Utilities/UnsettledDictionary.cs
create mode 100644 test/Proton.Tests/Utilities/UnsettledDictionaryTest.cs
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
(qpid-proton-dotnet) 03/03: Update versions file for next development cycle
Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
tabish121 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton-dotnet.git
commit 86c22fc270c712bb535fa421f99b88e29f210348
Author: Timothy Bish <ta...@gmail.com>
AuthorDate: Fri Jul 31 10:47:31 2026 -0400
Update versions file for next development cycle
---
VERSION.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/VERSION.txt b/VERSION.txt
index 9084fa2..5902d52 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1 +1 @@
-1.1.0
+1.1.0-SNAPSHOT
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
(qpid-proton-dotnet) 01/03: Various codec correctness and performance improvements
Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
tabish121 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton-dotnet.git
commit 5a0c8bd756243acea8bf81d0c01b7a0819ef6ac5
Author: Timothy Bish <ta...@gmail.com>
AuthorDate: Fri Jul 31 09:40:42 2026 -0400
Various codec correctness and performance improvements
---
.gitignore | 1 +
src/Proton.Client/Client/DecodeOptions.cs | 80 +
src/Proton.Client/Client/IDelivery.cs | 24 +
src/Proton.Client/Client/IStreamDelivery.cs | 22 +
.../Client/Implementation/ClientConnection.cs | 3 +-
.../Implementation/ClientConversionSupport.cs | 72 +
.../Client/Implementation/ClientDelivery.cs | 16 +
.../Client/Implementation/ClientMessageSupport.cs | 80 +-
.../Client/Implementation/ClientStreamDelivery.cs | 7 +-
.../Implementation/ClientStreamReceiverMessage.cs | 12 +-
src/Proton.Client/Client/StreamDecodeOptions.cs | 117 +
.../Decoders/AbstractDescribedListTypeDecoder.cs | 232 ++
.../Decoders/AbstractDescribedMapTypeDecoder.cs | 248 ++
.../Codec/Decoders/AbstractDescribedTypeDecoder.cs | 8 +-
.../Codec/Decoders/AbstractPrimitiveTypeDecoder.cs | 32 +-
.../Codec/Decoders/IPrimitiveArrayTypeDecoder.cs | 34 +
src/Proton/Codec/Decoders/IPrimitiveTypeDecoder.cs | 4 +
.../Decoders/Messaging/AcceptedTypeDecoder.cs | 66 +-
.../Decoders/Messaging/AmqpSequenceTypeDecoder.cs | 16 +-
.../Decoders/Messaging/AmqpValueTypeDecoder.cs | 50 +-
.../Messaging/ApplicationPropertiesTypeDecoder.cs | 136 +-
.../Codec/Decoders/Messaging/DataTypeDecoder.cs | 22 +-
.../Decoders/Messaging/DeleteOnCloseTypeDecoder.cs | 66 +-
.../DeleteOnNoLinksOrMessagesTypeDecoder.cs | 66 +-
.../Messaging/DeleteOnNoLinksTypeDecoder.cs | 66 +-
.../Messaging/DeleteOnNoMessagesTypeDecoder.cs | 66 +-
.../Messaging/DeliveryAnnotationsTypeDecoder.cs | 136 +-
.../Codec/Decoders/Messaging/FooterTypeDecoder.cs | 136 +-
.../Codec/Decoders/Messaging/HeaderTypeDecoder.cs | 94 +-
.../Messaging/MessageAnnotationsTypeDecoder.cs | 136 +-
.../Decoders/Messaging/ModifiedTypeDecoder.cs | 94 +-
.../Decoders/Messaging/PropertiesTypeDecoder.cs | 94 +-
.../Decoders/Messaging/ReceivedTypeDecoder.cs | 84 +-
.../Decoders/Messaging/RejectedTypeDecoder.cs | 112 +-
.../Decoders/Messaging/ReleasedTypeDecoder.cs | 66 +-
.../Codec/Decoders/Messaging/SourceTypeDecoder.cs | 94 +-
.../Codec/Decoders/Messaging/TargetTypeDecoder.cs | 94 +-
.../Primitives/AbstractArrayTypeDecoder.cs | 154 +-
.../Decoders/Primitives/AbstractBinaryDecoder.cs | 39 +-
.../Decoders/Primitives/AbstractListTypeDecoder.cs | 134 +-
.../Decoders/Primitives/AbstractMapTypeDecoder.cs | 163 +-
.../Primitives/AbstractStringTypeDecoder.cs | 38 +-
.../Primitives/AbstractSymbolTypeDecoder.cs | 52 +-
.../Decoders/Primitives/BooleanFalseTypeDecoder.cs | 22 +
.../Decoders/Primitives/BooleanTrueTypeDecoder.cs | 22 +
.../Codec/Decoders/Primitives/List0TypeDecoder.cs | 82 +-
.../Codec/Decoders/Primitives/NullTypeDecoder.cs | 36 +
...llTypeDecoder.cs => SaslSymbol32TypeDecoder.cs} | 23 +-
...ullTypeDecoder.cs => SaslSymbol8TypeDecoder.cs} | 23 +-
.../Primitives/UnsignedInteger0TypeDecoder.cs | 24 +-
.../Primitives/UnsignedLong0TypeDecoder.cs | 24 +-
src/Proton/Codec/Decoders/ProtonDecoder.cs | 186 +-
src/Proton/Codec/Decoders/ProtonDecoderFactory.cs | 4 +-
src/Proton/Codec/Decoders/ProtonDecoderState.cs | 47 +-
src/Proton/Codec/Decoders/ProtonStreamDecoder.cs | 138 +-
.../Codec/Decoders/ProtonStreamDecoderFactory.cs | 4 +-
.../Codec/Decoders/ProtonStreamDecoderState.cs | 59 +-
src/Proton/Codec/Decoders/ProtonStreamReadUtils.cs | 5 +
.../Decoders/Security/SaslChallengeTypeDecoder.cs | 92 +-
.../Codec/Decoders/Security/SaslInitTypeDecoder.cs | 96 +-
.../Decoders/Security/SaslMechanismsTypeDecoder.cs | 92 +-
.../Decoders/Security/SaslOutcomeTypeDecoder.cs | 120 +-
.../Decoders/Security/SaslResponseTypeDecoder.cs | 92 +-
.../Transactions/CoordinatorTypeDecoder.cs | 94 +-
.../Decoders/Transactions/DeclareTypeDecoder.cs | 94 +-
.../Decoders/Transactions/DeclaredTypeDecoder.cs | 100 +-
.../Decoders/Transactions/DischargeTypeDecoder.cs | 116 +-
.../Transactions/TransactionalStateTypeDecoder.cs | 116 +-
.../Codec/Decoders/Transport/AttachTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/BeginTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/CloseTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/DetachTypeDecoder.cs | 90 +-
.../Decoders/Transport/DispositionTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/EndTypeDecoder.cs | 108 +-
.../Transport/ErrorConditionTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/FlowTypeDecoder.cs | 90 +-
.../Codec/Decoders/Transport/OpenTypeDecoder.cs | 90 +-
.../Decoders/Transport/TransferTypeDecoder.cs | 90 +-
.../Codec/Decoders/UnknownDescribedTypeDecoder.cs | 87 +-
.../Encoders/AbstractDescribedMapTypeEncoder.cs | 41 +-
.../Messaging/ApplicationPropertiesTypeEncoder.cs | 10 +-
.../Messaging/DeliveryAnnotationsTypeEncoder.cs | 10 +-
.../Codec/Encoders/Messaging/FooterTypeEncoder.cs | 10 +-
.../Messaging/MessageAnnotationsTypeEncoder.cs | 10 +-
src/Proton/Codec/Encoders/ProtonEncoder.cs | 26 +-
src/Proton/Codec/Encoders/ProtonEncoderFactory.cs | 4 +-
src/Proton/Codec/IDecoderState.cs | 46 +
src/Proton/Codec/IStreamDecoderState.cs | 106 +
.../Exceptions/ProtocolViolationException.cs | 3 +-
src/Proton/Engine/IEngineConfiguration.cs | 14 +
.../Engine/Implementation/ProtonConstants.cs | 6 +
.../Implementation/ProtonEngineConfiguration.cs | 2 +
.../Implementation/ProtonFrameDecodingHandler.cs | 10 +-
.../Implementation/ProtonIncomingDelivery.cs | 29 +-
src/Proton/Engine/Implementation/ProtonReceiver.cs | 33 +-
.../Implementation/ProtonSessionIncomingWindow.cs | 52 +-
.../Implementation/ProtonSessionOutgoingWindow.cs | 29 +-
.../Implementation/ProtonTransactionManager.cs | 2 +-
.../Sasl/ProtonDefaultSaslClientAuthenticator.cs | 3 +-
.../Sasl/ProtonDefaultSaslServerAuthenticator .cs | 2 +-
.../Engine/Sasl/Client/AnonymousMechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/CramMD5Mechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/ExternalMechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/IMechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/PlainMechanism.cs | 2 +-
.../Engine/Sasl/Client/SaslMechanismSelector.cs | 2 +-
.../Engine/Sasl/Client/ScramSHA1Mechanism.cs | 2 +-
.../Engine/Sasl/Client/ScramSHA256Mechanism.cs | 2 +-
.../Engine/Sasl/Client/ScramSHA512Mechanism.cs | 2 +-
src/Proton/Engine/Sasl/Client/XOauth2Mechanism.cs | 2 +-
src/Proton/Types/Security/SaslChallenge.cs | 2 +-
src/Proton/Types/Security/SaslInit.cs | 2 +-
src/Proton/Types/Security/SaslMechanisms.cs | 2 +-
src/Proton/Types/Security/SaslOutcome.cs | 2 +-
src/Proton/Types/Security/SaslResponse.cs | 2 +-
src/Proton/Types/Symbol.cs | 239 +-
src/Proton/Types/UnknownDescribedType.cs | 2 +-
src/Proton/Utilities/StringUtils.cs | 48 +
src/Proton/Utilities/UnsettledDictionary.cs | 1722 +++++++++++++
.../Client/Implementation/ClientBaseTestFixture.cs | 56 +-
.../Client/Implementation/ClientReceiverTest.cs | 220 ++
.../Implementation/ClientStreamReceiverTest.cs | 276 +++
.../Implementation/ClilentTransactionsTest.cs | 3 +-
.../Codec/Decoders/ProtonDecoderTest.cs | 213 +-
.../Codec/Decoders/ProtonStreamDecoderTest.cs | 219 +-
.../Codec/Messaging/AcceptedTypeCodecTest.cs | 171 ++
.../Codec/Messaging/AmqpSequenceTypeCodecTest.cs | 79 +
.../Codec/Messaging/AmqpValueTypeCodecTest.cs | 295 +++
.../ApplicationPropertiesTypeCodecTest.cs | 674 ++++-
.../Codec/Messaging/DataTypeCodecTest.cs | 25 +
.../Codec/Messaging/DeleteOnCloseTypeCodecTest.cs | 170 ++
.../DeleteOnNoLinksOrMessagesCodecTest.cs | 170 ++
.../Messaging/DeleteOnNoLinksTypeCodecTest.cs | 169 ++
.../Messaging/DeleteOnNoMessagesTypeCodecTest.cs | 170 ++
.../Messaging/DeliveryAnnotationsTypeCodecTest.cs | 256 +-
.../Codec/Messaging/FooterTypeCodecTest.cs | 271 +-
.../Codec/Messaging/HeaderTypeCodecTest.cs | 233 ++
.../Messaging/MessageAnnotationsTypeCodecTest.cs | 268 +-
.../Codec/Messaging/ModifiedTypeCodecTest.cs | 8 +-
.../Codec/Messaging/RejectedTypeCodecTest.cs | 4 +-
.../Codec/Primitives/ArrayTypeCodecTest.cs | 320 +++
.../Codec/Primitives/BinaryTypeCodecTest.cs | 74 +
.../Codec/Primitives/BooleanTypeCodecTest.cs | 441 +++-
.../Codec/Primitives/ByteTypeCodecTest.cs | 189 ++
.../Codec/Primitives/CharacterTypeCodecTests.cs | 103 +
.../Codec/Primitives/DoubleTypeCodecTest.cs | 39 +
.../Codec/Primitives/FloatTypeCodecTest.cs | 39 +
.../Codec/Primitives/IntegerTypeCodecTest.cs | 81 +-
.../Codec/Primitives/ListTypeCodecTest.cs | 466 +++-
.../Codec/Primitives/LongTypeCodecTest.cs | 81 +-
.../Codec/Primitives/MapTypeCodecTest.cs | 323 ++-
.../Codec/Primitives/NullTypeCodecTest.cs | 229 +-
.../Codec/Primitives/ShortTypeCodecTest.cs | 39 +
.../Codec/Primitives/StringTypeCodecTest.cs | 109 +
.../Codec/Primitives/SymbolTypeCodecTest.cs | 109 +
.../Primitives/UnsignedIntegerTypeCodecTest.cs | 186 ++
.../Codec/Primitives/UnsignedLongTypeCodecTest.cs | 196 +-
.../Codec/Security/SaslChallengeTypeCodecTest.cs | 112 +
.../Codec/Security/SaslInitTypeCodecTest.cs | 30 +-
.../Codec/Security/SaslMechanismsTypeCodecTest.cs | 190 +-
.../Codec/Security/SaslOutcomeTypeCodecTest.cs | 112 +
.../Codec/Security/SaslResponseTypeCodecTest.cs | 112 +
.../Codec/UnknownDescribedTypeCodecTest.cs | 478 ++++
.../Engine/Implementation/ProtonDecodeErrorTest.cs | 30 +-
.../Engine/Implementation/ProtonReceiverTest.cs | 205 +-
.../Engine/Implementation/ProtonSessionTest.cs | 85 +
.../Implementation/Sasl/ProtonSaslHandlerTest.cs | 28 +-
.../Implementation/Sasl/ProtonSaslServerTest.cs | 8 +-
.../Engine/Sasl/Client/AbstractMechanismTest.cs | 2 +-
.../Engine/Sasl/Client/SaslMechanismsTest.cs | 2 +-
test/Proton.Tests/Types/Security/SaslInitTest.cs | 3 +-
.../Types/Security/SaslMechanismsTest.cs | 4 +-
test/Proton.Tests/Types/SymbolTest.cs | 166 ++
.../Utilities/UnsettledDictionaryTest.cs | 2592 ++++++++++++++++++++
174 files changed, 15507 insertions(+), 4097 deletions(-)
diff --git a/.gitignore b/.gitignore
index 20e91b6..14cec8b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,6 +53,7 @@ bld/
.vscode/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
+*.lscache
# Visual Studio 2017 auto generated files
Generated\ Files/
diff --git a/src/Proton.Client/Client/DecodeOptions.cs b/src/Proton.Client/Client/DecodeOptions.cs
new file mode 100644
index 0000000..185d8ae
--- /dev/null
+++ b/src/Proton.Client/Client/DecodeOptions.cs
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+using Apache.Qpid.Proton.Codec.Decoders;
+
+namespace Apache.Qpid.Proton.Client
+{
+ public class DecodeOptions : ICloneable
+ {
+ /// <summary>
+ /// Creates a default Decode options instance.
+ /// </summary>
+ public DecodeOptions() : base()
+ {
+ }
+
+ /// <summary>
+ /// Create a new Decode options instance whose settings are copied from the instance provided.
+ /// </summary>
+ /// <param name="other">The decode options instance to copy</param>
+ public DecodeOptions(DecodeOptions other) : base()
+ {
+ other?.CopyInto(this);
+ }
+
+ /// <summary>
+ /// Clone this options instance, changes to the cloned options are not reflected
+ /// in this options instance.
+ /// </summary>
+ /// <returns>A deep copy of this options instance.</returns>
+ public object Clone()
+ {
+ return CopyInto(new DecodeOptions());
+ }
+
+ internal DecodeOptions CopyInto(DecodeOptions other)
+ {
+ other.MaxZeroWidthArrayElements = MaxZeroWidthArrayElements;
+ other.DepthLimit = DepthLimit;
+
+ return other;
+ }
+
+ /// <summary>
+ /// The configured maximum number of elements that can be decoded from an array
+ /// encoded with the zero width AMQP types (Null, UInt0. ULong0, List0, Boolean_False
+ /// and Boolean_True). These are uncommon encodings and can lead to small encodings
+ /// with large memory costs at decode which makes them discouraged for normal use.
+ /// It is recommended that for implementations that implement this limit configuration
+ /// the default be zero meaning zero width array encodings are disabled and will always
+ /// throw a NotImplementedException.
+ /// </summary>
+ public uint MaxZeroWidthArrayElements { get; set; } = ProtonDecoderState.DefaultMaxZeroWidthArrayElements;
+
+ /// <summary>
+ /// Access the configured maximum depth that nested types such as Lists, Maps and Arrays
+ /// can have before a DecodeException is thrown to allow the decoder to error
+ /// in cases where the depth of encoding exceeds what the environment is thought to be
+ /// able to support.
+ /// </summary>
+ public uint DepthLimit { get; set; } = ProtonDecoderState.DefaultMaxDecodeDepth;
+
+ }
+}
\ No newline at end of file
diff --git a/src/Proton.Client/Client/IDelivery.cs b/src/Proton.Client/Client/IDelivery.cs
index c0d8d11..b272954 100644
--- a/src/Proton.Client/Client/IDelivery.cs
+++ b/src/Proton.Client/Client/IDelivery.cs
@@ -53,6 +53,30 @@ namespace Apache.Qpid.Proton.Client
/// <returns>the decoded message from the delivery payload</returns>
IMessage<object> Message();
+ /// <summary>
+ /// Decodes the payload of the delivery and returns a new message.
+ ///
+ /// Calling this message claims the payload of the delivery for the returned Message
+ /// and excludes use of the RawInputStream method of the delivery object. Calling the
+ /// RawInputStream method after calling this method throws ClientIllegalStateException.
+ ///
+ /// The default implementation simply calls the normal message API without any options
+ /// to preserve backwards compatibility.
+ /// </summary>
+ /// <remarks>
+ /// If the incoming message carried any delivery annotations they can be accessed
+ /// via the Annotations method. Re-sending the returned message will not also
+ /// send the incoming delivery annotations, the sender must include them in the
+ /// sender's send call if they are to be forwarded onto the next recipient.
+ /// </remarks>
+ /// <typeparam name="T">Body type of the message</typeparam>
+ /// <param name="options">The decode options to use when decoding the message</param>
+ /// <returns>the decoded message from the delivery payload</returns>
+ IMessage<object> Message(DecodeOptions options)
+ {
+ return Message();
+ }
+
/// <summary>
/// Create and return an read-only Stream that reads the raw payload bytes of the
/// given delivery. Calling this method claims the payload of the delivery for the
diff --git a/src/Proton.Client/Client/IStreamDelivery.cs b/src/Proton.Client/Client/IStreamDelivery.cs
index 7261de3..3bb5309 100644
--- a/src/Proton.Client/Client/IStreamDelivery.cs
+++ b/src/Proton.Client/Client/IStreamDelivery.cs
@@ -54,6 +54,28 @@ namespace Apache.Qpid.Proton.Client
/// <returns>the decoded message from the delivery payload</returns>
IStreamReceiverMessage Message();
+ /// <summary>
+ /// Returns a stream receiver message type that will perform a decode of message
+ /// payload as portions of the streamed message arrive. The message API is inherently
+ /// a blocking API as the decoder will need to wait in some cases to decode a full
+ /// section the incoming message when it is requested.
+ ///
+ /// The default implementation of this method simply calls the original bare message
+ /// to preserve backwards compatibility.
+ /// </summary>
+ /// <remarks>
+ /// If the incoming message carried any delivery annotations they can be accessed
+ /// via the Annotations method. Re-sending the returned message will not also
+ /// send the incoming delivery annotations, the sender must include them in the
+ /// sender's send call if they are to be forwarded onto the next recipient.
+ /// </remarks>
+ /// <typeparam name="T">Body type of the message</typeparam>
+ /// <returns>the decoded message from the delivery payload</returns>
+ IStreamReceiverMessage Message(StreamDecodeOptions options)
+ {
+ return Message();
+ }
+
/// <summary>
/// Decodes the delivery payload and returns a dictionary containing a copy of any
/// associated delivery annotations that were transmitted with the message payload.
diff --git a/src/Proton.Client/Client/Implementation/ClientConnection.cs b/src/Proton.Client/Client/Implementation/ClientConnection.cs
index 751286e..a62727f 100644
--- a/src/Proton.Client/Client/Implementation/ClientConnection.cs
+++ b/src/Proton.Client/Client/Implementation/ClientConnection.cs
@@ -1002,8 +1002,7 @@ namespace Apache.Qpid.Proton.Client.Implementation
if (options.SaslOptions.SaslEnabled)
{
- SaslMechanismSelector mechSelector = new(
- ClientConversionSupport.ToSymbolSet(options.SaslOptions.AllowedMechanisms));
+ SaslMechanismSelector mechSelector = new(options.SaslOptions.AllowedMechanisms);
engine.SaslDriver.Client().Authenticator =
new SaslAuthenticator(mechSelector, new ClientSaslCredentialsProvider(this));
diff --git a/src/Proton.Client/Client/Implementation/ClientConversionSupport.cs b/src/Proton.Client/Client/Implementation/ClientConversionSupport.cs
index 31b7c21..f047825 100644
--- a/src/Proton.Client/Client/Implementation/ClientConversionSupport.cs
+++ b/src/Proton.Client/Client/Implementation/ClientConversionSupport.cs
@@ -44,6 +44,33 @@ namespace Apache.Qpid.Proton.Client.Implementation
return result;
}
+ /// <summary>
+ /// Convert the given string array into an array of Symbol instances
+ /// </summary>
+ /// <param name="stringArray"></param>
+ /// <returns></returns>
+ public static Symbol[] ToSaslSymbolArray(string[] stringArray)
+ {
+ Symbol[] result = null;
+
+ if (stringArray != null)
+ {
+ result = new Symbol[stringArray.Length];
+ for (int i = 0; i < stringArray.Length; ++i)
+ {
+ result[i] = Symbol.SaslLookup(stringArray[i]);
+ }
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Convert the given string array into an array of Symbol instances using the
+ /// SASL Symbol cache as the source of symbol values.
+ /// </summary>
+ /// <param name="stringArray"></param>
+ /// <returns></returns>
public static Symbol[] ToSymbolArray(IEnumerable<DeliveryStateType> stateTypeArray)
{
Symbol[] result = null;
@@ -96,6 +123,26 @@ namespace Apache.Qpid.Proton.Client.Implementation
return result;
}
+ public static Dictionary<Symbol, object> ToSaslSymbolKeyedMap<V>(IEnumerable<KeyValuePair<string, V>> stringsMap)
+ {
+ Dictionary<Symbol, object> result;
+
+ if (stringsMap != null)
+ {
+ result = new Dictionary<Symbol, object>();
+ foreach (KeyValuePair<string, V> entry in stringsMap)
+ {
+ result.Add(Symbol.SaslLookup(entry.Key), entry.Value);
+ }
+ }
+ else
+ {
+ result = null;
+ }
+
+ return result;
+ }
+
public static Dictionary<string, object> ToStringKeyedMap<V>(IEnumerable<KeyValuePair<Symbol, V>> symbolMap)
{
Dictionary<string, object> result;
@@ -141,6 +188,31 @@ namespace Apache.Qpid.Proton.Client.Implementation
return result;
}
+ /// <summary>
+ /// Converts an enumeration of string values into a set of Symbol values.
+ /// </summary>
+ /// <param name="strings">an enumeration of string values</param>
+ /// <returns>a set of Symbol value that match the input strings</returns>
+ public static ISet<Symbol> ToSaslSymbolSet(in IEnumerable<string> strings)
+ {
+ ISet<Symbol> result;
+
+ if (strings != null)
+ {
+ result = new HashSet<Symbol>();
+ foreach (string value in strings)
+ {
+ result.Add(Symbol.SaslLookup(value));
+ }
+ }
+ else
+ {
+ result = null;
+ }
+
+ return result;
+ }
+
/// <summary>
/// Converts an enumeration of Symbol values into a set of string values.
/// </summary>
diff --git a/src/Proton.Client/Client/Implementation/ClientDelivery.cs b/src/Proton.Client/Client/Implementation/ClientDelivery.cs
index 45a4bb4..b16efeb 100644
--- a/src/Proton.Client/Client/Implementation/ClientDelivery.cs
+++ b/src/Proton.Client/Client/Implementation/ClientDelivery.cs
@@ -104,6 +104,22 @@ namespace Apache.Qpid.Proton.Client.Implementation
return message;
}
+ public IMessage<object> Message(DecodeOptions options)
+ {
+ if (rawInputStream != null)
+ {
+ throw new ClientIllegalStateException("Cannot access Delivery Annotations API after requesting an InputStream");
+ }
+
+ IMessage<object> message = cachedMessage;
+ if (message == null && payload.IsReadable)
+ {
+ message = cachedMessage = ClientMessageSupport.DecodeMessage(payload, SetDeliveryAnnotations, options);
+ }
+
+ return message;
+ }
+
public IDelivery Disposition(IDeliveryState state, bool settled)
{
return receiver.DispositionAsync(this, state?.AsProtonType(), settled).ConfigureAwait(false).GetAwaiter().GetResult();
diff --git a/src/Proton.Client/Client/Implementation/ClientMessageSupport.cs b/src/Proton.Client/Client/Implementation/ClientMessageSupport.cs
index 9c35139..c3e0423 100644
--- a/src/Proton.Client/Client/Implementation/ClientMessageSupport.cs
+++ b/src/Proton.Client/Client/Implementation/ClientMessageSupport.cs
@@ -119,35 +119,42 @@ namespace Apache.Qpid.Proton.Client.Implementation
ApplicationProperties applicationProperties = message.ApplicationProperties;
Footer footer = message.Footer;
- if (header != null)
+ try
{
- encoder.WriteObject(buffer, encoderState, header);
- }
- if (deliveryAnnotations != null)
- {
- encoder.WriteObject(buffer, encoderState, new DeliveryAnnotations(ClientConversionSupport.ToSymbolKeyedMap(deliveryAnnotations)));
- }
- if (messageAnnotations != null)
- {
- encoder.WriteObject(buffer, encoderState, messageAnnotations);
- }
- if (properties != null)
- {
- encoder.WriteObject(buffer, encoderState, properties);
- }
- if (applicationProperties != null)
- {
- encoder.WriteObject(buffer, encoderState, applicationProperties);
- }
+ if (header != null)
+ {
+ encoder.WriteObject(buffer, encoderState, header);
+ }
+ if (deliveryAnnotations != null)
+ {
+ encoder.WriteObject(buffer, encoderState, new DeliveryAnnotations(ClientConversionSupport.ToSymbolKeyedMap(deliveryAnnotations)));
+ }
+ if (messageAnnotations != null)
+ {
+ encoder.WriteObject(buffer, encoderState, messageAnnotations);
+ }
+ if (properties != null)
+ {
+ encoder.WriteObject(buffer, encoderState, properties);
+ }
+ if (applicationProperties != null)
+ {
+ encoder.WriteObject(buffer, encoderState, applicationProperties);
+ }
- message.ForEachBodySection(section => encoder.WriteObject(buffer, encoderState, section));
+ message.ForEachBodySection(section => encoder.WriteObject(buffer, encoderState, section));
- if (footer != null)
+ if (footer != null)
+ {
+ encoder.WriteObject(buffer, encoderState, footer);
+ }
+
+ return buffer;
+ }
+ finally
{
- encoder.WriteObject(buffer, encoderState, footer);
+ encoderState.Reset();
}
-
- return buffer;
}
#endregion
@@ -159,15 +166,34 @@ namespace Apache.Qpid.Proton.Client.Implementation
return DecodeMessage(DEFAULT_DECODER, DEFAULT_DECODER.NewDecoderState(), buffer, daConsumer);
}
+ public static ClientMessage<object> DecodeMessage(IProtonBuffer buffer, Action<DeliveryAnnotations> daConsumer, DecodeOptions options)
+ {
+ IDecoderState state = DEFAULT_DECODER.NewDecoderState();
+
+ state.DepthLimit = options.DepthLimit;
+ state.MaxZeroWidthArrayElements = options.MaxZeroWidthArrayElements;
+
+ return DecodeMessage(DEFAULT_DECODER, state, buffer, daConsumer);
+ }
+
public static ClientMessage<object> DecodeMessage(IDecoder decoder, IProtonBuffer buffer, Action<DeliveryAnnotations> daConsumer)
{
return DecodeMessage(decoder, decoder.NewDecoderState(), buffer, daConsumer);
}
+ public static ClientMessage<object> DecodeMessage(IDecoder decoder, IProtonBuffer buffer, Action<DeliveryAnnotations> daConsumer, DecodeOptions options)
+ {
+ IDecoderState state = decoder.NewDecoderState();
+
+ state.DepthLimit = options.DepthLimit;
+ state.MaxZeroWidthArrayElements = options.MaxZeroWidthArrayElements;
+
+ return DecodeMessage(decoder, state, buffer, daConsumer);
+ }
+
public static ClientMessage<object> DecodeMessage(IDecoder decoder, IDecoderState decoderState,
IProtonBuffer buffer, Action<DeliveryAnnotations> daConsumer)
{
-
ClientMessage<object> message = new();
ISection section;
@@ -182,6 +208,10 @@ namespace Apache.Qpid.Proton.Client.Implementation
{
throw ClientExceptionSupport.CreateNonFatalOrPassthrough(e);
}
+ finally
+ {
+ decoderState.Reset();
+ }
switch (section.Type)
{
diff --git a/src/Proton.Client/Client/Implementation/ClientStreamDelivery.cs b/src/Proton.Client/Client/Implementation/ClientStreamDelivery.cs
index 2b4895b..cc51e4d 100644
--- a/src/Proton.Client/Client/Implementation/ClientStreamDelivery.cs
+++ b/src/Proton.Client/Client/Implementation/ClientStreamDelivery.cs
@@ -112,6 +112,11 @@ namespace Apache.Qpid.Proton.Client.Implementation
}
public IStreamReceiverMessage Message()
+ {
+ return Message(new StreamDecodeOptions());
+ }
+
+ public IStreamReceiverMessage Message(StreamDecodeOptions options)
{
if (rawInputStream != null && message == null)
{
@@ -120,7 +125,7 @@ namespace Apache.Qpid.Proton.Client.Implementation
if (message == null)
{
- message = new ClientStreamReceiverMessage(receiver, this, rawInputStream = new RawDeliveryInputStream(this));
+ message = new ClientStreamReceiverMessage(receiver, this, options, rawInputStream = new RawDeliveryInputStream(this));
}
return message;
diff --git a/src/Proton.Client/Client/Implementation/ClientStreamReceiverMessage.cs b/src/Proton.Client/Client/Implementation/ClientStreamReceiverMessage.cs
index bffddec..19562fc 100644
--- a/src/Proton.Client/Client/Implementation/ClientStreamReceiverMessage.cs
+++ b/src/Proton.Client/Client/Implementation/ClientStreamReceiverMessage.cs
@@ -51,7 +51,7 @@ namespace Apache.Qpid.Proton.Client.Implementation
private StreamState currentState = StreamState.IDLE;
private MessageBodyInputStream bodyStream;
- internal ClientStreamReceiverMessage(ClientStreamReceiver receiver, ClientStreamDelivery delivery, Stream deliveryStream)
+ internal ClientStreamReceiverMessage(ClientStreamReceiver receiver, ClientStreamDelivery delivery, StreamDecodeOptions decodeOptions, Stream deliveryStream)
{
this.receiver = receiver;
this.delivery = delivery;
@@ -60,6 +60,16 @@ namespace Apache.Qpid.Proton.Client.Implementation
this.protonDecoder = ProtonStreamDecoderFactory.Create();
this.decoderState = protonDecoder.NewDecoderState();
+
+ // Configure the decoder state here which will then apply to all decode operations
+ decoderState.DepthLimit = decodeOptions.DepthLimit;
+ decoderState.MaxZeroWidthArrayElements = decodeOptions.MaxZeroWidthArrayElements;
+ decoderState.MaxStringSize = decodeOptions.MaxStringSize;
+ decoderState.MaxArraySize = decodeOptions.MaxArraySize;
+ decoderState.MaxListSize = decodeOptions.MaxListSize;
+ decoderState.MaxMapSize = decodeOptions.MaxMapSize;
+ decoderState.MaxBinarySize = decodeOptions.MaxBinarySize;
+ decoderState.MaxSymbolSize = decodeOptions.MaxSymbolSize;
}
public IStreamDelivery Delivery => delivery;
diff --git a/src/Proton.Client/Client/StreamDecodeOptions.cs b/src/Proton.Client/Client/StreamDecodeOptions.cs
new file mode 100644
index 0000000..87cff97
--- /dev/null
+++ b/src/Proton.Client/Client/StreamDecodeOptions.cs
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+using Apache.Qpid.Proton.Codec;
+using Apache.Qpid.Proton.Codec.Decoders;
+
+namespace Apache.Qpid.Proton.Client
+{
+ public class StreamDecodeOptions : ICloneable
+ {
+ /// <summary>
+ /// A default used to limit reads from a stream for types that encode a count or
+ /// size of encoded elements.
+ /// </summary>
+ protected static readonly uint DefaultMaxAllocationLimit = int.MaxValue - 8;
+
+ /// <summary>
+ /// Creates a default Decode options instance.
+ /// </summary>
+ public StreamDecodeOptions() : base()
+ {
+ }
+
+ /// <summary>
+ /// Create a new Decode options instance whose settings are copied from the instance provided.
+ /// </summary>
+ /// <param name="other">The decode options instance to copy</param>
+ public StreamDecodeOptions(StreamDecodeOptions other) : base()
+ {
+ other?.CopyInto(this);
+ }
+
+ /// <summary>
+ /// Clone this options instance, changes to the cloned options are not reflected
+ /// in this options instance.
+ /// </summary>
+ /// <returns>A deep copy of this options instance.</returns>
+ public object Clone()
+ {
+ return CopyInto(new StreamDecodeOptions());
+ }
+
+ internal StreamDecodeOptions CopyInto(StreamDecodeOptions other)
+ {
+ other.MaxZeroWidthArrayElements = MaxZeroWidthArrayElements;
+ other.DepthLimit = DepthLimit;
+
+ return other;
+ }
+
+ /// <summary>
+ /// The configured maximum number of elements that can be decoded from an array
+ /// encoded with the zero width AMQP types (Null, UInt0. ULong0, List0, Boolean_False
+ /// and Boolean_True). These are uncommon encodings and can lead to small encodings
+ /// with large memory costs at decode which makes them discouraged for normal use.
+ /// It is recommended that for implementations that implement this limit configuration
+ /// the default be zero meaning zero width array encodings are disabled and will always
+ /// throw a NotImplementedException.
+ /// </summary>
+ public uint MaxZeroWidthArrayElements { get; set; } = ProtonStreamDecoderState.DefaultMaxZeroWidthArrayElements;
+
+ /// <summary>
+ /// Access the configured maximum depth that nested types such as Lists, Maps and Arrays
+ /// can have before a DecodeException is thrown to allow the decoder to error
+ /// in cases where the depth of encoding exceeds what the environment is thought to be
+ /// able to support.
+ /// </summary>
+ public uint DepthLimit { get; set; } = ProtonStreamDecoderState.DefaultMaxDecodeDepth;
+
+ /// <summary>
+ /// The configured maximum size of an encoded string that can be decoded before an error is thrown.
+ /// </summary>
+ public uint MaxStringSize { get; set; } = DefaultMaxAllocationLimit;
+
+ /// <summary>
+ /// The configured maximum size of an encoded array that can be decoded before an error is thrown.
+ /// </summary>
+ public uint MaxArraySize { get; set; } = DefaultMaxAllocationLimit;
+
+ /// <summary>
+ /// The configured maximum size of an encoded Binary that can be decoded before an error is thrown.
+ /// </summary>
+ public uint MaxBinarySize { get; set; } = DefaultMaxAllocationLimit;
+
+ /// <summary>
+ /// The configured maximum size of an encoded Symbol that can be decoded before an error is thrown.
+ /// </summary>
+ public uint MaxSymbolSize { get; set; } = DefaultMaxAllocationLimit;
+
+ /// <summary>
+ /// The configured maximum encoded list size that can be decoded before an error is thrown.
+ /// </summary>
+ public uint MaxListSize { get; set; } = DefaultMaxAllocationLimit;
+
+ /// <summary>
+ /// The configured maximum encoded map size that can be decoded before an error is thrown.
+ /// </summary>
+ public uint MaxMapSize { get; set; } = DefaultMaxAllocationLimit;
+
+ }
+}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/AbstractDescribedListTypeDecoder.cs b/src/Proton/Codec/Decoders/AbstractDescribedListTypeDecoder.cs
new file mode 100644
index 0000000..0666fc8
--- /dev/null
+++ b/src/Proton/Codec/Decoders/AbstractDescribedListTypeDecoder.cs
@@ -0,0 +1,232 @@
+/*
+ * 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.
+ */
+
+using System;
+using System.IO;
+using Apache.Qpid.Proton.Buffer;
+using Apache.Qpid.Proton.Codec.Decoders.Primitives;
+using Apache.Qpid.Proton.Types;
+
+namespace Apache.Qpid.Proton.Codec.Decoders
+{
+ public abstract class AbstractDescribedListTypeDecoder : AbstractDescribedTypeDecoder
+ {
+ public sealed override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ {
+ state.IncreaseDepth();
+
+ try
+ {
+ ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+
+ return ReadSingle(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
+ }
+
+ public sealed override object ReadValue(Stream stream, IStreamDecoderState state)
+ {
+ state.IncreaseDepth();
+
+ try
+ {
+ IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+
+ return ReadSingle(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
+ }
+
+ public sealed override void SkipValue(IProtonBuffer buffer, IDecoderState state)
+ {
+ CheckIsExpectedType<IListTypeDecoder>(state.Decoder.ReadNextTypeDecoder(buffer, state)).SkipValue(buffer, state);
+ }
+
+ public sealed override void SkipValue(Stream stream, IStreamDecoderState state)
+ {
+ CheckIsExpectedType<IListTypeDecoder>(state.Decoder.ReadNextTypeDecoder(stream, state)).SkipValue(stream, state);
+ }
+
+ public sealed override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
+
+ if (listDecoder.IsZeroWidth)
+ {
+ if (count > state.MaxZeroWidthArrayElements)
+ {
+ throw new DecodeException(
+ "Array element count " + count + " is specified to be greater than limit for zero sized " +
+ "encoded array types (" + state.MaxZeroWidthArrayElements + ")");
+ }
+ }
+ else if (count > buffer.ReadableBytes)
+ {
+ throw new DecodeException(
+ "Array encoded element count " + count + " is specified to be greater than the " +
+ "amount of data available " + buffer.ReadableBytes);
+ }
+
+ Array result = Array.CreateInstance(DecodesType, count);
+ for (int i = 0; i < count; ++i)
+ {
+ result.SetValue(ReadSingle(buffer, state, listDecoder), i);
+ }
+
+ return result;
+ }
+
+ public sealed override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ {
+ IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+ IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
+
+ if (listDecoder.IsZeroWidth && count > state.MaxZeroWidthArrayElements)
+ {
+ throw new DecodeException(
+ "Array element count " + count + " is specified to be greater than limit for zero sized " +
+ "encoded array types (" + state.MaxZeroWidthArrayElements + ")");
+ }
+ else if (count > state.MaxArraySize)
+ {
+ throw new DecodeException(
+ "Array encoded element count " + count + " is specified to be greater than the " +
+ "configured max array size " + state.MaxArraySize);
+ }
+
+ Array result = Array.CreateInstance(DecodesType, count);
+ for (int i = 0; i < count; ++i)
+ {
+ result.SetValue(ReadSingle(stream, state, listDecoder), i);
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Gets the minimum number of elements this described list is allowed to carry.
+ /// </summary>
+ protected abstract int MinListElements { get; }
+
+ /// <summary>
+ /// Gets the maximum number of elements this described list is allowed to carry.
+ /// </summary>
+ protected abstract int MaxListElements { get; }
+
+ protected virtual object ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ {
+ int size = listDecoder.ReadSize(buffer, state);
+ long expectedEndPos = buffer.ReadOffset + size;
+
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoded size is specified to be greater than the amount " +
+ "of data available s:({0}) r:({1})", (uint) size, buffer.ReadableBytes));
+ }
+
+ int count = listDecoder.ReadCount(buffer, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoded count is specified to be greater than the reported encoded size " +
+ "s:({0}) c:({1})", size, (uint) count));
+ }
+
+ if (count < MinListElements)
+ {
+ throw new DecodeException(String.Format(
+ "Not enough list elements indicated in the encoded count, expected {0} but got {1}",
+ MinListElements, count));
+ }
+
+ if (count > MaxListElements)
+ {
+ throw new DecodeException(String.Format(
+ "To many elements indicated in the encoded count, maximum {0} but got {1}",
+ MaxListElements, count));
+ }
+
+ object type = ReadType(count, buffer, state.Decoder, state);
+
+ if (buffer.ReadOffset != expectedEndPos)
+ {
+ throw new DecodeException("List decoding did not read the expected amount of bytes: " + size);
+ }
+
+ return type;
+ }
+
+ protected virtual object ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ {
+ int size = listDecoder.ReadSize(stream, state);
+
+ if (size > state.MaxListSize || size < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoded size is specified to be greater than the configured maximum " +
+ "List size allowed s:({0}) c:({1})", (uint) size, state.MaxListSize));
+ }
+
+ int count = listDecoder.ReadCount(stream, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoded count is specified to be greater than the reported encoded size " +
+ "s:(%d) c:(%d)", size, (uint) count));
+ }
+
+ if (count < MinListElements)
+ {
+ throw new DecodeException(String.Format(
+ "Not enough list elements indicated in the encoded count, expected {0} but got {1}",
+ MinListElements, count));
+ }
+
+ if (count > MaxListElements)
+ {
+ throw new DecodeException(String.Format(
+ "To many elements indicated in the encoded count, maximum {0} but got {1}",
+ MaxListElements, count));
+ }
+
+ return ReadType(count, stream, state.Decoder, state);
+ }
+
+ /// <summary>
+ /// Reads the actual type from the byte stream with the given number of encoded list elements populated
+ /// </summary>
+ /// <returns>The decoded described type</returns>
+ protected abstract object ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state);
+
+ /// <summary>
+ /// Reads the actual type from the byte stream with the given number of encoded list elements populated
+ /// </summary>
+ /// <returns>The decoded described type</returns>
+ protected abstract object ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state);
+
+ }
+}
diff --git a/src/Proton/Codec/Decoders/AbstractDescribedMapTypeDecoder.cs b/src/Proton/Codec/Decoders/AbstractDescribedMapTypeDecoder.cs
new file mode 100644
index 0000000..0a58a72
--- /dev/null
+++ b/src/Proton/Codec/Decoders/AbstractDescribedMapTypeDecoder.cs
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Apache.Qpid.Proton.Buffer;
+using Apache.Qpid.Proton.Codec.Decoders.Primitives;
+using Apache.Qpid.Proton.Types;
+
+namespace Apache.Qpid.Proton.Codec.Decoders
+{
+ public abstract class AbstractDescribedMapTypeDecoder<K> : AbstractDescribedTypeDecoder
+ {
+ private static readonly int MAX_MAP_PREALLOCATION = 256;
+
+ public sealed override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ {
+ state.IncreaseDepth();
+
+ try
+ {
+ IMapTypeDecoder mapTypeDecoder =
+ CheckIsExpectedTypeAndCast<IMapTypeDecoder>(state.Decoder.ReadNextTypeDecoder(buffer, state));
+
+ return CreateDescribed(ReadMap(buffer, state, mapTypeDecoder));
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
+ }
+
+ public sealed override object ReadValue(Stream stream, IStreamDecoderState state)
+ {
+ state.IncreaseDepth();
+
+ try
+ {
+ IMapTypeDecoder mapTypeDecoder =
+ CheckIsExpectedTypeAndCast<IMapTypeDecoder>(state.Decoder.ReadNextTypeDecoder(stream, state));
+
+ return CreateDescribed(ReadMap(stream, state, mapTypeDecoder));
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
+ }
+
+ public sealed override void SkipValue(IProtonBuffer buffer, IDecoderState state)
+ {
+ CheckIsExpectedType<IMapTypeDecoder>(state.Decoder.ReadNextTypeDecoder(buffer, state)).SkipValue(buffer, state);
+ }
+
+ public sealed override void SkipValue(Stream stream, IStreamDecoderState state)
+ {
+ CheckIsExpectedType<IMapTypeDecoder>(state.Decoder.ReadNextTypeDecoder(stream, state)).SkipValue(stream, state);
+ }
+
+ public sealed override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+
+ ValidateArrayConstraints(count, buffer, state, decoder);
+
+ Array result = Array.CreateInstance(DecodesType, count);
+ for (int i = 0; i < count; ++i)
+ {
+ result.SetValue(CreateDescribed(ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder))), i);
+ }
+
+ return result;
+ }
+
+ public sealed override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ {
+ IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+
+ ValidateArrayConstraints(count, stream, state, decoder);
+
+ Array result = Array.CreateInstance(DecodesType, count);
+ for (int i = 0; i < count; ++i)
+ {
+ result.SetValue(CreateDescribed(ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder))), i);
+ }
+
+ return result;
+ }
+
+ protected abstract object CreateDescribed(IDictionary<K, object> map);
+
+ protected abstract K ReadKey(IProtonBuffer buffer, IDecoder decoder, IDecoderState state);
+
+ protected abstract K ReadKey(Stream stream, IStreamDecoder decoder, IStreamDecoderState state);
+
+ private IDictionary<K, Object> ReadMap(IProtonBuffer buffer, IDecoderState state, IMapTypeDecoder mapDecoder)
+ {
+ int size = mapDecoder.ReadSize(buffer, state);
+ long expectedEndPos = buffer.ReadOffset + size;
+ int count = ValidateAndGetCount(size, buffer, state, mapDecoder);
+ IDecoder decoder = state.Decoder;
+ int entries = count / 2;
+
+ // Count include both key and value so we must include that in the loop
+ IDictionary<K, Object> map = new Dictionary<K, object>(Math.Min(MAX_MAP_PREALLOCATION, entries));
+
+ for (int i = 0; i < entries; i++)
+ {
+ map.TryAdd(ReadKey(buffer, decoder, state), decoder.ReadObject(buffer, state));
+ }
+
+ if (buffer.ReadOffset != expectedEndPos)
+ {
+ throw new DecodeException("Map decoding did not read the expected amount of bytes: " + size);
+ }
+
+ return map;
+ }
+
+ private IDictionary<K, Object> ReadMap(Stream stream, IStreamDecoderState state, IMapTypeDecoder mapDecoder)
+ {
+ int size = mapDecoder.ReadSize(stream, state);
+ int count = ValidateAndGetCount(size, stream, state, mapDecoder);
+ IStreamDecoder decoder = state.Decoder;
+ int entries = count / 2;
+
+ // Count include both key and value so we must include that in the loop
+ IDictionary<K, Object> map = new Dictionary<K, object>(Math.Min(MAX_MAP_PREALLOCATION, entries));
+
+ for (int i = 0; i < entries; i++)
+ {
+ map.TryAdd(ReadKey(stream, decoder, state), decoder.ReadObject(stream, state));
+ }
+
+ return map;
+ }
+
+ protected static int ValidateAndGetCount(int size, IProtonBuffer buffer, IDecoderState state, IMapTypeDecoder decoder)
+ {
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded size is specified to be greater than the amount " +
+ "of data available s:({0}) r:({1})", (uint) size, buffer.ReadableBytes));
+ }
+
+ int count = decoder.ReadCount(buffer, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded count is specified to be greater than the reported encoded size " +
+ "s:({0}) c:({1})", size, (uint) count));
+ }
+
+ if (count % 2 != 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded number of elements {0} is not an even number.", count));
+ }
+
+ return count;
+ }
+
+ protected static int ValidateAndGetCount(int size, Stream stream, IStreamDecoderState state, IMapTypeDecoder decoder)
+ {
+ if (size > state.MaxMapSize || size < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded size is specified to be greater than the configured maximum " +
+ "map size allowed s:({0}) c:({1})", (uint) size, state.MaxMapSize));
+ }
+
+ int count = decoder.ReadCount(stream, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded count is specified to be greater than the reported encoded size " +
+ "s:({0}) c:({1})", size, (uint) count));
+ }
+
+ if (count % 2 != 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded number of elements {0} is not an even number.", count));
+ }
+
+ return count;
+ }
+
+ protected static void ValidateArrayConstraints(int count, IProtonBuffer buffer, IDecoderState state, ITypeDecoder decoder)
+ {
+ if (decoder.GetType() == typeof(void))
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded array count {0} is specified to be greater than limit for zero sized encoded array types (%d)",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+ else
+ {
+ if (count > buffer.ReadableBytes || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded array count {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) count, buffer.ReadableBytes));
+ }
+ }
+ }
+
+ protected static void ValidateArrayConstraints(int count, Stream stream, IStreamDecoderState state, IStreamTypeDecoder decoder)
+ {
+ if (decoder.GetType() == typeof(void))
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Map encoded array count {0} is specified to be greater than limit for zero sized encoded array types (%d)",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+ else if (count > state.MaxArraySize || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Array encoded length {0} is specified to be greater than the amount " +
+ "of the configured max array length ({1})", (uint) count, state.MaxStringSize));
+ }
+ }
+ }
+}
diff --git a/src/Proton/Codec/Decoders/AbstractDescribedTypeDecoder.cs b/src/Proton/Codec/Decoders/AbstractDescribedTypeDecoder.cs
index 903db6b..67b2d4e 100644
--- a/src/Proton/Codec/Decoders/AbstractDescribedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/AbstractDescribedTypeDecoder.cs
@@ -75,22 +75,26 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return (T)actual;
}
- protected static void CheckIsExpectedType<T>(ITypeDecoder actual)
+ protected static ITypeDecoder CheckIsExpectedType<T>(ITypeDecoder actual)
{
if (!typeof(T).IsAssignableFrom(actual.GetType()))
{
throw new DecodeException(
"Expected " + typeof(T) + "encoding but got decoder for type: " + actual.GetType().Name);
}
+
+ return actual;
}
- protected static void CheckIsExpectedType<T>(IStreamTypeDecoder actual)
+ protected static IStreamTypeDecoder CheckIsExpectedType<T>(IStreamTypeDecoder actual)
{
if (!typeof(T).IsAssignableFrom(actual.GetType()))
{
throw new DecodeException(
"Expected " + typeof(T) + "encoding but got decoder for type: " + actual.GetType().Name);
}
+
+ return actual;
}
}
}
diff --git a/src/Proton/Codec/Decoders/AbstractPrimitiveTypeDecoder.cs b/src/Proton/Codec/Decoders/AbstractPrimitiveTypeDecoder.cs
index 69204f5..92679ac 100644
--- a/src/Proton/Codec/Decoders/AbstractPrimitiveTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/AbstractPrimitiveTypeDecoder.cs
@@ -23,10 +23,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public abstract class AbstractPrimitiveTypeDecoder : IPrimitiveTypeDecoder
{
- public bool IsArrayType => false;
+ public virtual bool IsArrayType => false;
- public Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
+ public virtual bool IsZeroWidth => false;
+
+ public virtual Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
{
+ ValidateArrayPreconditions(buffer, state, count);
+
Array array = Array.CreateInstance(DecodesType, count);
for (int i = 0; i < count; ++i)
{
@@ -36,8 +40,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return array;
}
- public Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ public virtual Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
{
+ ValidateArrayPreconditions(stream, state, count);
+
Array array = Array.CreateInstance(DecodesType, count);
for (int i = 0; i < count; ++i)
{
@@ -47,6 +53,26 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return array;
}
+ protected virtual void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > buffer.ReadableBytes || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array count indicated {0} is greater than the amount of data available to decode ({1})",
+ (uint) count, buffer.ReadableBytes));
+ }
+ }
+
+ protected virtual void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxArraySize || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array count indicated {0} is greater than the amount of the configured max array size ({1})",
+ (uint) count, state.MaxArraySize));
+ }
+ }
+
#region Interface methods handed off to the subclass
public abstract EncodingCodes EncodingCode { get; }
diff --git a/src/Proton/Codec/Decoders/IPrimitiveArrayTypeDecoder.cs b/src/Proton/Codec/Decoders/IPrimitiveArrayTypeDecoder.cs
index f6efaae..65d768b 100644
--- a/src/Proton/Codec/Decoders/IPrimitiveArrayTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/IPrimitiveArrayTypeDecoder.cs
@@ -15,6 +15,10 @@
* limitations under the License.
*/
+using System;
+using System.IO;
+using Apache.Qpid.Proton.Buffer;
+
namespace Apache.Qpid.Proton.Codec
{
/// <summary>
@@ -22,5 +26,35 @@ namespace Apache.Qpid.Proton.Codec
/// </summary>
public interface IPrimitiveArrayTypeDecoder : IPrimitiveTypeDecoder
{
+ /// <summary>
+ /// Reads the given array from the bytes in the buffer but only if the type encoding
+ /// of the given array matches the given Type filter. This allows the caller to
+ /// effectively limit if the given array is decoded at all if the type encoding is
+ /// not a match and also can act to limit an array to only a single level as the type
+ /// encoding of nested arrays will not be the value type until the bottom of the array
+ /// is reached. To allow all types and any array nesting the caller should pass the
+ /// object Type.
+ /// </summary>
+ /// <param name="buffer"></param>
+ /// <param name="state"></param>
+ /// <param name="ofType"></param>
+ /// <returns>An array containing elements of the given type</returns>
+ object ReadValue(IProtonBuffer buffer, IDecoderState state, Type ofType);
+
+ /// <summary>
+ /// Reads the given array from the bytes in the buffer but only if the type encoding
+ /// of the given array matches the given Type filter. This allows the caller to
+ /// effectively limit if the given array is decoded at all if the type encoding is
+ /// not a match and also can act to limit an array to only a single level as the type
+ /// encoding of nested arrays will not be the value type until the bottom of the array
+ /// is reached. To allow all types and any array nesting the caller should pass the
+ /// object Type.
+ /// </summary>
+ /// <param name="stream"></param>
+ /// <param name="state"></param>
+ /// <param name="ofType"></param>
+ /// <returns>An array containing elements of the given type</returns>
+ object ReadValue(Stream stream, IStreamDecoderState state, Type ofType);
+
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/IPrimitiveTypeDecoder.cs b/src/Proton/Codec/Decoders/IPrimitiveTypeDecoder.cs
index 125c252..95f3283 100644
--- a/src/Proton/Codec/Decoders/IPrimitiveTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/IPrimitiveTypeDecoder.cs
@@ -27,5 +27,9 @@ namespace Apache.Qpid.Proton.Codec
/// </summary>
EncodingCodes EncodingCode { get; }
+ /// <summary>
+ /// Returns true if this decoder return types that encode as zero width elements.
+ /// </summary>
+ bool IsZeroWidth { get; }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/AcceptedTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/AcceptedTypeDecoder.cs
index d7609cf..b8dd432 100644
--- a/src/Proton/Codec/Decoders/Messaging/AcceptedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/AcceptedTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class AcceptedTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class AcceptedTypeDecoder : AbstractDescribedListTypeDecoder
{
public override Symbol DescriptorSymbol => Accepted.DescriptorSymbol;
@@ -32,78 +32,32 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Accepted);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => 0;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => 0;
+ protected sealed override Accepted ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder decoder)
+ {
decoder.SkipValue(buffer, state);
return Accepted.Instance;
}
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Accepted[] result = new Accepted[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(buffer, state);
- result[i] = Accepted.Instance;
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected sealed override Accepted ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder decoder)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
decoder.SkipValue(stream, state);
return Accepted.Instance;
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override Accepted ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Accepted[] result = new Accepted[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(stream, state);
- result[i] = Accepted.Instance;
- }
-
- return result;
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override Accepted ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/AmqpSequenceTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/AmqpSequenceTypeDecoder.cs
index 3af4dca..36e54b2 100644
--- a/src/Proton/Codec/Decoders/Messaging/AmqpSequenceTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/AmqpSequenceTypeDecoder.cs
@@ -33,7 +33,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(AmqpSequence);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ public override AmqpSequence ReadValue(IProtonBuffer buffer, IDecoderState state)
{
ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
IListTypeDecoder valueDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
@@ -59,14 +59,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
+ CheckIsExpectedType<IListTypeDecoder>(state.Decoder.ReadNextTypeDecoder(buffer, state)).SkipValue(buffer, state);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ public override AmqpSequence ReadValue(Stream stream, IStreamDecoderState state)
{
IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
IListTypeDecoder valueDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
@@ -92,11 +88,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ CheckIsExpectedType<IListTypeDecoder>(state.Decoder.ReadNextTypeDecoder(stream, state)).SkipValue(stream, state);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/AmqpValueTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/AmqpValueTypeDecoder.cs
index afd0555..49e05d6 100644
--- a/src/Proton/Codec/Decoders/Messaging/AmqpValueTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/AmqpValueTypeDecoder.cs
@@ -31,10 +31,18 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(AmqpValue);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ public override AmqpValue ReadValue(IProtonBuffer buffer, IDecoderState state)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- return new AmqpValue(decoder.ReadValue(buffer, state));
+ state.IncreaseDepth();
+
+ try
+ {
+ return new AmqpValue(state.Decoder.ReadNextTypeDecoder(buffer, state).ReadValue(buffer, state));
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
@@ -53,13 +61,30 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- state.Decoder.ReadNextTypeDecoder(buffer, state).SkipValue(buffer, state);
+ state.IncreaseDepth();
+
+ try
+ {
+ state.Decoder.ReadNextTypeDecoder(buffer, state).SkipValue(buffer, state);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ public override AmqpValue ReadValue(Stream stream, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- return new AmqpValue(decoder.ReadValue(stream, state));
+ state.IncreaseDepth();
+
+ try
+ {
+ return new AmqpValue(state.Decoder.ReadNextTypeDecoder(stream, state).ReadValue(stream, state));
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
@@ -78,7 +103,16 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- state.Decoder.ReadNextTypeDecoder(stream, state).SkipValue(stream, state);
+ state.IncreaseDepth();
+
+ try
+ {
+ state.Decoder.ReadNextTypeDecoder(stream, state).SkipValue(stream, state);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/ApplicationPropertiesTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/ApplicationPropertiesTypeDecoder.cs
index aecd636..544b773 100644
--- a/src/Proton/Codec/Decoders/Messaging/ApplicationPropertiesTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/ApplicationPropertiesTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class ApplicationPropertiesTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class ApplicationPropertiesTypeDecoder : AbstractDescribedMapTypeDecoder<string>
{
public override Symbol DescriptorSymbol => ApplicationProperties.DescriptorSymbol;
@@ -33,141 +33,19 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(ApplicationProperties);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ protected override ApplicationProperties CreateDescribed(IDictionary<string, object> map)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new ApplicationProperties();
- }
-
- return new ApplicationProperties(ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- ApplicationProperties[] result = new ApplicationProperties[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new ApplicationProperties();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new ApplicationProperties(
- ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(buffer, state);
- }
- }
-
- private static IDictionary<string, object> ReadMap(IProtonBuffer buffer, IDecoderState state, IMapTypeDecoder mapDecoder)
- {
- int size = mapDecoder.ReadSize(buffer, state);
- int count = mapDecoder.ReadCount(buffer, state);
-
- if (count > buffer.ReadableBytes)
- {
- throw new DecodeException(string.Format(
- "Map encoded size {0} is specified to be greater than the amount " +
- "of data available ({1})", size, buffer.ReadableBytes));
- }
-
- IDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<string, object> map = new Dictionary<string, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- string key = decoder.ReadString(buffer, state);
- object value = decoder.ReadObject(buffer, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return new ApplicationProperties(map);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected override string ReadKey(IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new ApplicationProperties();
- }
-
- return new ApplicationProperties(ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
+ return decoder.ReadString(buffer, state);
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override string ReadKey(Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- ApplicationProperties[] result = new ApplicationProperties[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new ApplicationProperties();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new ApplicationProperties(
- ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(stream, state);
- }
- }
-
- private static IDictionary<string, object> ReadMap(Stream stream, IStreamDecoderState state, IMapTypeDecoder mapDecoder)
- {
- _ = mapDecoder.ReadSize(stream, state);
- int count = mapDecoder.ReadCount(stream, state);
-
- IStreamDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<string, object> map = new Dictionary<string, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- string key = decoder.ReadString(stream, state);
- object value = decoder.ReadObject(stream, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return decoder.ReadString(stream, state);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/DataTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/DataTypeDecoder.cs
index a46d491..812382e 100644
--- a/src/Proton/Codec/Decoders/Messaging/DataTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/DataTypeDecoder.cs
@@ -34,7 +34,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Data);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ public override Data ReadValue(IProtonBuffer buffer, IDecoderState state)
{
EncodingCodes encodingCode = (EncodingCodes)buffer.ReadByte();
int size;
@@ -88,14 +88,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IBinaryTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
+ CheckIsExpectedType<IBinaryTypeDecoder>(state.Decoder.ReadNextTypeDecoder(buffer, state)).SkipValue(buffer, state);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ public override Data ReadValue(Stream stream, IStreamDecoderState state)
{
EncodingCodes encodingCode = (EncodingCodes)ProtonStreamReadUtils.ReadByte(stream);
int size;
@@ -114,6 +110,12 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
throw new DecodeException("Expected Binary type but found encoding: " + encodingCode);
}
+ if (size > state.MaxBinarySize)
+ {
+ throw new DecodeException("Binary data size " + size + " is specified to be greater than the " +
+ "configured max binary size (" + state.MaxBinarySize + ")");
+ }
+
return new Data(ProtonByteBufferAllocator.Instance.Wrap(ProtonStreamReadUtils.ReadBytes(stream, size)));
}
@@ -134,11 +136,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IBinaryTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ CheckIsExpectedType<IBinaryTypeDecoder>(state.Decoder.ReadNextTypeDecoder(stream, state)).SkipValue(stream, state);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/DeleteOnCloseTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/DeleteOnCloseTypeDecoder.cs
index 4a3a6a3..daeaf2d 100644
--- a/src/Proton/Codec/Decoders/Messaging/DeleteOnCloseTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/DeleteOnCloseTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class DeleteOnCloseTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeleteOnCloseTypeDecoder : AbstractDescribedListTypeDecoder
{
public override Symbol DescriptorSymbol => DeleteOnClose.DescriptorSymbol;
@@ -32,78 +32,32 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(DeleteOnClose);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => 0;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => 0;
+ protected sealed override DeleteOnClose ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder decoder)
+ {
decoder.SkipValue(buffer, state);
return DeleteOnClose.Instance;
}
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnClose[] result = new DeleteOnClose[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(buffer, state);
- result[i] = DeleteOnClose.Instance;
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected sealed override DeleteOnClose ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder decoder)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
decoder.SkipValue(stream, state);
return DeleteOnClose.Instance;
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override object ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnClose[] result = new DeleteOnClose[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(stream, state);
- result[i] = DeleteOnClose.Instance;
- }
-
- return result;
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override object ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksOrMessagesTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksOrMessagesTypeDecoder.cs
index 16a7df6..492e278 100644
--- a/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksOrMessagesTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksOrMessagesTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class DeleteOnNoLinksOrMessagesTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeleteOnNoLinksOrMessagesTypeDecoder : AbstractDescribedListTypeDecoder
{
public override Symbol DescriptorSymbol => DeleteOnNoLinksOrMessages.DescriptorSymbol;
@@ -32,78 +32,32 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(DeleteOnNoLinksOrMessages);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => 0;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => 0;
+ protected sealed override object ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder decoder)
+ {
decoder.SkipValue(buffer, state);
return DeleteOnNoLinksOrMessages.Instance;
}
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnNoLinksOrMessages[] result = new DeleteOnNoLinksOrMessages[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(buffer, state);
- result[i] = DeleteOnNoLinksOrMessages.Instance;
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected sealed override object ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder decoder)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
decoder.SkipValue(stream, state);
return DeleteOnNoLinksOrMessages.Instance;
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override object ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnNoLinksOrMessages[] result = new DeleteOnNoLinksOrMessages[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(stream, state);
- result[i] = DeleteOnNoLinksOrMessages.Instance;
- }
-
- return result;
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override object ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksTypeDecoder.cs
index e53ea01..28d2180 100644
--- a/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/DeleteOnNoLinksTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class DeleteOnNoLinksTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeleteOnNoLinksTypeDecoder : AbstractDescribedListTypeDecoder
{
public override Symbol DescriptorSymbol => DeleteOnNoLinks.DescriptorSymbol;
@@ -32,78 +32,32 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(DeleteOnNoLinks);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => 0;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => 0;
+ protected sealed override object ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder decoder)
+ {
decoder.SkipValue(buffer, state);
return DeleteOnNoLinks.Instance;
}
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnNoLinks[] result = new DeleteOnNoLinks[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(buffer, state);
- result[i] = DeleteOnNoLinks.Instance;
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected sealed override object ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder decoder)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
decoder.SkipValue(stream, state);
return DeleteOnNoLinks.Instance;
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override object ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnNoLinks[] result = new DeleteOnNoLinks[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(stream, state);
- result[i] = DeleteOnNoLinks.Instance;
- }
-
- return result;
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override object ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/DeleteOnNoMessagesTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/DeleteOnNoMessagesTypeDecoder.cs
index 2b56d15..8c8fd90 100644
--- a/src/Proton/Codec/Decoders/Messaging/DeleteOnNoMessagesTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/DeleteOnNoMessagesTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class DeleteOnNoMessagesTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeleteOnNoMessagesTypeDecoder : AbstractDescribedListTypeDecoder
{
public override Symbol DescriptorSymbol => DeleteOnNoMessages.DescriptorSymbol;
@@ -32,78 +32,32 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(DeleteOnNoMessages);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => 0;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => 0;
+ protected sealed override DeleteOnNoMessages ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder decoder)
+ {
decoder.SkipValue(buffer, state);
return DeleteOnNoMessages.Instance;
}
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnNoMessages[] result = new DeleteOnNoMessages[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(buffer, state);
- result[i] = DeleteOnNoMessages.Instance;
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected sealed override DeleteOnNoMessages ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder decoder)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
decoder.SkipValue(stream, state);
return DeleteOnNoMessages.Instance;
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override DeleteOnNoMessages ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- DeleteOnNoMessages[] result = new DeleteOnNoMessages[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(stream, state);
- result[i] = DeleteOnNoMessages.Instance;
- }
-
- return result;
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override DeleteOnNoMessages ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/DeliveryAnnotationsTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/DeliveryAnnotationsTypeDecoder.cs
index e24c59b..c490df3 100644
--- a/src/Proton/Codec/Decoders/Messaging/DeliveryAnnotationsTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/DeliveryAnnotationsTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class DeliveryAnnotationsTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeliveryAnnotationsTypeDecoder : AbstractDescribedMapTypeDecoder<Symbol>
{
public override Symbol DescriptorSymbol => DeliveryAnnotations.DescriptorSymbol;
@@ -33,141 +33,19 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(DeliveryAnnotations);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ protected override DeliveryAnnotations CreateDescribed(IDictionary<Symbol, object> map)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new DeliveryAnnotations();
- }
-
- return new DeliveryAnnotations(ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- DeliveryAnnotations[] result = new DeliveryAnnotations[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new DeliveryAnnotations();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new DeliveryAnnotations(
- ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(buffer, state);
- }
- }
-
- private static IDictionary<Symbol, object> ReadMap(IProtonBuffer buffer, IDecoderState state, IMapTypeDecoder mapDecoder)
- {
- int size = mapDecoder.ReadSize(buffer, state);
- int count = mapDecoder.ReadCount(buffer, state);
-
- if (count > buffer.ReadableBytes)
- {
- throw new DecodeException(string.Format(
- "Map encoded size {0} is specified to be greater than the amount " +
- "of data available ({1})", size, buffer.ReadableBytes));
- }
-
- IDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<Symbol, object> map = new Dictionary<Symbol, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- Symbol key = decoder.ReadSymbol(buffer, state);
- object value = decoder.ReadObject(buffer, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return new DeliveryAnnotations(map);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected override Symbol ReadKey(IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new DeliveryAnnotations();
- }
-
- return new DeliveryAnnotations(ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
+ return decoder.ReadSymbol(buffer, state);
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override Symbol ReadKey(Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- DeliveryAnnotations[] result = new DeliveryAnnotations[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new DeliveryAnnotations();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new DeliveryAnnotations(
- ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(stream, state);
- }
- }
-
- private static IDictionary<Symbol, object> ReadMap(Stream stream, IStreamDecoderState state, IMapTypeDecoder mapDecoder)
- {
- _ = mapDecoder.ReadSize(stream, state);
- int count = mapDecoder.ReadCount(stream, state);
-
- IStreamDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<Symbol, object> map = new Dictionary<Symbol, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- Symbol key = decoder.ReadSymbol(stream, state);
- object value = decoder.ReadObject(stream, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return decoder.ReadSymbol(stream, state);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/FooterTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/FooterTypeDecoder.cs
index 05203c3..434e039 100644
--- a/src/Proton/Codec/Decoders/Messaging/FooterTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/FooterTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class FooterTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class FooterTypeDecoder : AbstractDescribedMapTypeDecoder<Symbol>
{
public override Symbol DescriptorSymbol => Footer.DescriptorSymbol;
@@ -33,141 +33,19 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Footer);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ protected override Footer CreateDescribed(IDictionary<Symbol, object> map)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new Footer();
- }
-
- return new Footer(ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- Footer[] result = new Footer[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new Footer();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new Footer(
- ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(buffer, state);
- }
- }
-
- private static IDictionary<Symbol, object> ReadMap(IProtonBuffer buffer, IDecoderState state, IMapTypeDecoder mapDecoder)
- {
- int size = mapDecoder.ReadSize(buffer, state);
- int count = mapDecoder.ReadCount(buffer, state);
-
- if (count > buffer.ReadableBytes)
- {
- throw new DecodeException(string.Format(
- "Map encoded size {0} is specified to be greater than the amount " +
- "of data available ({1})", size, buffer.ReadableBytes));
- }
-
- IDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<Symbol, object> map = new Dictionary<Symbol, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- Symbol key = decoder.ReadSymbol(buffer, state);
- object value = decoder.ReadObject(buffer, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return new Footer(map);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected override Symbol ReadKey(IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new Footer();
- }
-
- return new Footer(ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
+ return decoder.ReadSymbol(buffer, state);
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override Symbol ReadKey(Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- Footer[] result = new Footer[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new Footer();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new Footer(
- ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(stream, state);
- }
- }
-
- private static IDictionary<Symbol, object> ReadMap(Stream stream, IStreamDecoderState state, IMapTypeDecoder mapDecoder)
- {
- _ = mapDecoder.ReadSize(stream, state);
- int count = mapDecoder.ReadCount(stream, state);
-
- IStreamDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<Symbol, object> map = new Dictionary<Symbol, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- Symbol key = decoder.ReadSymbol(stream, state);
- object value = decoder.ReadObject(stream, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return decoder.ReadSymbol(stream, state);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/HeaderTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/HeaderTypeDecoder.cs
index 74e5b67..2a39614 100644
--- a/src/Proton/Codec/Decoders/Messaging/HeaderTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/HeaderTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class HeaderTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class HeaderTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinHeaderListEntries = 0;
private static readonly int MaxHeaderListEntries = 5;
@@ -35,54 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Header);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadHeader(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Header[] result = new Header[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadHeader(buffer, state, listDecoder);
- }
+ protected override int MinListElements => MinHeaderListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxHeaderListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Header ReadHeader(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Header ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Header result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinHeaderListEntries)
- {
- throw new DecodeException("Not enough entries in Header list encoding: " + count);
- }
-
- if (count > MaxHeaderListEntries)
- {
- throw new DecodeException("To many entries in Header list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -118,54 +78,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadHeader(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Header[] result = new Header[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadHeader(stream, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Header ReadHeader(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Header ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Header result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinHeaderListEntries)
- {
- throw new DecodeException("Not enough entries in Header list encoding: " + count);
- }
-
- if (count > MaxHeaderListEntries)
- {
- throw new DecodeException("To many entries in Header list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Messaging/MessageAnnotationsTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/MessageAnnotationsTypeDecoder.cs
index 29066ab..0a0d075 100644
--- a/src/Proton/Codec/Decoders/Messaging/MessageAnnotationsTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/MessageAnnotationsTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class MessageAnnotationsTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class MessageAnnotationsTypeDecoder : AbstractDescribedMapTypeDecoder<Symbol>
{
public override Symbol DescriptorSymbol => MessageAnnotations.DescriptorSymbol;
@@ -33,141 +33,19 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(MessageAnnotations);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
+ protected override MessageAnnotations CreateDescribed(IDictionary<Symbol, object> map)
{
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new MessageAnnotations();
- }
-
- return new MessageAnnotations(ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- MessageAnnotations[] result = new MessageAnnotations[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new MessageAnnotations();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new MessageAnnotations(
- ReadMap(buffer, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(buffer, state);
- }
- }
-
- private static IDictionary<Symbol, object> ReadMap(IProtonBuffer buffer, IDecoderState state, IMapTypeDecoder mapDecoder)
- {
- int size = mapDecoder.ReadSize(buffer, state);
- int count = mapDecoder.ReadCount(buffer, state);
-
- if (count > buffer.ReadableBytes)
- {
- throw new DecodeException(string.Format(
- "Map encoded size {0} is specified to be greater than the amount " +
- "of data available ({1})", size, buffer.ReadableBytes));
- }
-
- IDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<Symbol, object> map = new Dictionary<Symbol, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- Symbol key = decoder.ReadSymbol(buffer, state);
- object value = decoder.ReadObject(buffer, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return new MessageAnnotations(map);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected override Symbol ReadKey(IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- if (decoder is NullTypeDecoder)
- {
- return new MessageAnnotations();
- }
-
- return new MessageAnnotations(ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
+ return decoder.ReadSymbol(buffer, state);
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override Symbol ReadKey(Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- MessageAnnotations[] result = new MessageAnnotations[count];
-
- if (decoder is NullTypeDecoder)
- {
- for (int i = 0; i < count; ++i)
- {
- result[i] = new MessageAnnotations();
- }
- return result;
- }
-
- for (int i = 0; i < count; ++i)
- {
- result[i] = new MessageAnnotations(
- ReadMap(stream, state, CheckIsExpectedTypeAndCast<IMapTypeDecoder>(decoder)));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- if (decoder is not NullTypeDecoder)
- {
- CheckIsExpectedType<IMapTypeDecoder>(decoder);
- decoder.SkipValue(stream, state);
- }
- }
-
- private static IDictionary<Symbol, object> ReadMap(Stream stream, IStreamDecoderState state, IMapTypeDecoder mapDecoder)
- {
- _ = mapDecoder.ReadSize(stream, state);
- int count = mapDecoder.ReadCount(stream, state);
-
- IStreamDecoder decoder = state.Decoder;
-
- // Count include both key and value so we must include that in the loop
- IDictionary<Symbol, object> map = new Dictionary<Symbol, object>(count);
- for (int i = 0; i < count / 2; i++)
- {
- Symbol key = decoder.ReadSymbol(stream, state);
- object value = decoder.ReadObject(stream, state);
-
- map.Add(key, value);
- }
-
- return map;
+ return decoder.ReadSymbol(stream, state);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/ModifiedTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/ModifiedTypeDecoder.cs
index 313077e..842a21a 100644
--- a/src/Proton/Codec/Decoders/Messaging/ModifiedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/ModifiedTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class ModifiedTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class ModifiedTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinModifiedListEntries = 0;
private static readonly int MaxModifiedListEntries = 3;
@@ -35,54 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Modified);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadModified(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Modified[] result = new Modified[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadModified(buffer, state, listDecoder);
- }
+ protected override int MinListElements => MinModifiedListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxModifiedListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Modified ReadModified(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Modified ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Modified result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinModifiedListEntries)
- {
- throw new DecodeException("Not enough entries in Modified list encoding: " + count);
- }
-
- if (count > MaxModifiedListEntries)
- {
- throw new DecodeException("To many entries in Modified list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -112,54 +72,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadModified(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Modified[] result = new Modified[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadModified(stream, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Modified ReadModified(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Modified ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Modified result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinModifiedListEntries)
- {
- throw new DecodeException("Not enough entries in Modified list encoding: " + count);
- }
-
- if (count > MaxModifiedListEntries)
- {
- throw new DecodeException("To many entries in Modified list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Messaging/PropertiesTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/PropertiesTypeDecoder.cs
index eb4409f..fe3f830 100644
--- a/src/Proton/Codec/Decoders/Messaging/PropertiesTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/PropertiesTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class PropertiesTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class PropertiesTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinPropertiesListEntries = 0;
private static readonly int MaxPropertiesListEntries = 13;
@@ -35,54 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Properties);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadProperties(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Properties[] result = new Properties[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadProperties(buffer, state, listDecoder);
- }
+ protected override int MinListElements => MinPropertiesListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxPropertiesListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Properties ReadProperties(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Properties ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Properties result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinPropertiesListEntries)
- {
- throw new DecodeException("Not enough entries in Properties list encoding: " + count);
- }
-
- if (count > MaxPropertiesListEntries)
- {
- throw new DecodeException("To many entries in Properties list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -142,54 +102,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadProperties(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Properties[] result = new Properties[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadProperties(stream, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Properties ReadProperties(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Properties ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Properties result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinPropertiesListEntries)
- {
- throw new DecodeException("Not enough entries in Properties list encoding: " + count);
- }
-
- if (count > MaxPropertiesListEntries)
- {
- throw new DecodeException("To many entries in Properties list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Messaging/ReceivedTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/ReceivedTypeDecoder.cs
index 5289887..3f0d578 100644
--- a/src/Proton/Codec/Decoders/Messaging/ReceivedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/ReceivedTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class ReceivedTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class ReceivedTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int RequiredReceivedListEntries = 2;
@@ -34,49 +34,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Received);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadReceived(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Received[] result = new Received[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadReceived(buffer, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => RequiredReceivedListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
+ protected override int MaxListElements => RequiredReceivedListEntries;
- private static Received ReadReceived(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Received ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Received result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count != RequiredReceivedListEntries)
- {
- throw new DecodeException("Invalid number of entries in Received list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -103,49 +68,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadReceived(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Received[] result = new Received[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadReceived(stream, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Received ReadReceived(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Received ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Received result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count != RequiredReceivedListEntries)
- {
- throw new DecodeException("Invalid number of entries in Received list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Messaging/RejectedTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/RejectedTypeDecoder.cs
index 3106475..3e37539 100644
--- a/src/Proton/Codec/Decoders/Messaging/RejectedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/RejectedTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class RejectedTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class RejectedTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinRejectedListEntries = 0;
private static readonly int MaxRejectedListEntries = 1;
@@ -36,123 +36,29 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Rejected);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadRejected(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Rejected[] result = new Rejected[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadRejected(buffer, state, listDecoder);
- }
+ protected override int MinListElements => MinRejectedListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxRejectedListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Rejected ReadRejected(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Rejected ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Rejected result = new Rejected();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinRejectedListEntries)
- {
- throw new DecodeException("Not enough entries in Rejected list encoding: " + count);
- }
-
- if (count > MaxRejectedListEntries)
- {
- throw new DecodeException("To many entries in Rejected list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
- {
- switch (index)
- {
- case 0:
- result.Error = state.Decoder.ReadObject<ErrorCondition>(buffer, state);
- break;
- }
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadRejected(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Rejected[] result = new Rejected[count];
- for (int i = 0; i < count; ++i)
+ if (count == 1)
{
- result[i] = ReadRejected(stream, state, listDecoder);
+ result.Error = state.Decoder.ReadObject<ErrorCondition>(buffer, state);
}
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Rejected ReadRejected(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Rejected ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Rejected result = new Rejected();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinRejectedListEntries)
- {
- throw new DecodeException("Not enough entries in Rejected list encoding: " + count);
- }
-
- if (count > MaxRejectedListEntries)
- {
- throw new DecodeException("To many entries in Rejected list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
+ if (count == 1)
{
- switch (index)
- {
- case 0:
- result.Error = state.Decoder.ReadObject<ErrorCondition>(stream, state);
- break;
- }
+ result.Error = state.Decoder.ReadObject<ErrorCondition>(stream, state);
}
return result;
diff --git a/src/Proton/Codec/Decoders/Messaging/ReleasedTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/ReleasedTypeDecoder.cs
index 1ebcceb..885b0a3 100644
--- a/src/Proton/Codec/Decoders/Messaging/ReleasedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/ReleasedTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class ReleasedTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class ReleasedTypeDecoder : AbstractDescribedListTypeDecoder
{
public override Symbol DescriptorSymbol => Released.DescriptorSymbol;
@@ -32,78 +32,32 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Released);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => 0;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => 0;
+ protected sealed override Released ReadSingle(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder decoder)
+ {
decoder.SkipValue(buffer, state);
return Released.Instance;
}
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Released[] result = new Released[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(buffer, state);
- result[i] = Released.Instance;
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected sealed override Released ReadSingle(Stream stream, IStreamDecoderState state, IListTypeDecoder decoder)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
decoder.SkipValue(stream, state);
return Released.Instance;
}
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ protected override object ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Released[] result = new Released[count];
-
- for (int i = 0; i < count; ++i)
- {
- decoder.SkipValue(stream, state);
- result[i] = Released.Instance;
- }
-
- return result;
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override object ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
+ throw new NotImplementedException("Should not be called for this AMQP type");
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Messaging/SourceTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/SourceTypeDecoder.cs
index 3a0586e..3ab9ff0 100644
--- a/src/Proton/Codec/Decoders/Messaging/SourceTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/SourceTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class SourceTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class SourceTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinSourceListEntries = 0;
private static readonly int MaxSourceListEntries = 11;
@@ -35,54 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Source);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadSource(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Source[] result = new Source[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadSource(buffer, state, listDecoder);
- }
+ protected override int MinListElements => MinSourceListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxSourceListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Source ReadSource(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Source ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Source result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinSourceListEntries)
- {
- throw new DecodeException("Not enough entries in Source list encoding: " + count);
- }
-
- if (count > MaxSourceListEntries)
- {
- throw new DecodeException("To many entries in Source list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
switch (index)
@@ -128,54 +88,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadSource(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Source[] result = new Source[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadSource(stream, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Source ReadSource(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Source ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Source result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinSourceListEntries)
- {
- throw new DecodeException("Not enough entries in Source list encoding: " + count);
- }
-
- if (count > MaxSourceListEntries)
- {
- throw new DecodeException("To many entries in Source list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
switch (index)
diff --git a/src/Proton/Codec/Decoders/Messaging/TargetTypeDecoder.cs b/src/Proton/Codec/Decoders/Messaging/TargetTypeDecoder.cs
index 1898ba5..80ba729 100644
--- a/src/Proton/Codec/Decoders/Messaging/TargetTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Messaging/TargetTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
{
- public sealed class TargetTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class TargetTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinTargetListEntries = 0;
private static readonly int MaxTargetListEntries = 7;
@@ -35,54 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
public override Type DecodesType => typeof(Target);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadTarget(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Target[] result = new Target[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadTarget(buffer, state, listDecoder);
- }
+ protected override int MinListElements => MinTargetListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxTargetListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Target ReadTarget(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Target ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Target result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinTargetListEntries)
- {
- throw new DecodeException("Not enough entries in Target list encoding: " + count);
- }
-
- if (count > MaxTargetListEntries)
- {
- throw new DecodeException("To many entries in Target list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
switch (index)
@@ -116,54 +76,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Messaging
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadTarget(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- IListTypeDecoder listDecoder = CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder);
-
- Target[] result = new Target[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadTarget(stream, state, listDecoder);
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Target ReadTarget(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Target ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Target result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinTargetListEntries)
- {
- throw new DecodeException("Not enough entries in Target list encoding: " + count);
- }
-
- if (count > MaxTargetListEntries)
- {
- throw new DecodeException("To many entries in Target list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
switch (index)
diff --git a/src/Proton/Codec/Decoders/Primitives/AbstractArrayTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/AbstractArrayTypeDecoder.cs
index 5ddacfc..d1ee35e 100644
--- a/src/Proton/Codec/Decoders/Primitives/AbstractArrayTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/AbstractArrayTypeDecoder.cs
@@ -25,76 +25,160 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
public override Type DecodesType => typeof(Array);
+ public override bool IsArrayType => true;
+
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
{
- int size = ReadSize(buffer, state);
- int count = ReadCount(buffer, state);
+ return ReadValue(buffer, state, typeof(object));
+ }
- if (EncodingCode == EncodingCodes.Array32)
- {
- size -= 8; // 4 bytes each for size and count;
- }
- else
- {
- size -= 2; // 1 byte each for size and count;
- }
+ public object ReadValue(IProtonBuffer buffer, IDecoderState state, Type ofType)
+ {
+ state.IncreaseDepth();
- if (size > buffer.ReadableBytes)
+ try
{
- throw new DecodeException(string.Format(
- "Array size indicated {0} is greater than the amount of data available to decode ({1})",
- size, buffer.ReadableBytes));
- }
+ int size = ReadSize(buffer, state);
+
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of data available to decode ({1})",
+ (uint) size, buffer.ReadableBytes));
+ }
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ long startOffset = buffer.ReadOffset;
+ int count = ReadCount(buffer, state);
- if (decoder is IPrimitiveArrayTypeDecoder arrayDecoder)
- {
- object[] array = new object[count];
- for (int i = 0; i < count; i++)
+ ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+
+ if (!decoder.DecodesType.IsAssignableTo(ofType))
+ {
+ throw new DecodeException(String.Format(
+ "Unexpected type {0}. Expected a type assignable to {1}", decoder.DecodesType,ofType.Name));
+ }
+
+ Array array;
+
+ if (decoder is IPrimitiveArrayTypeDecoder arrayDecoder)
+ {
+ if (count > buffer.ReadableBytes || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array count indicated {0} is greater than the amount of data available to decode ({1})",
+ (uint) count, buffer.ReadableBytes));
+ }
+
+ array = Array.CreateInstance(decoder.DecodesType, count);
+
+ for (int i = 0; i < count; i++)
+ {
+ array.SetValue(arrayDecoder.ReadValue(buffer, state), i);
+ }
+ }
+ else
+ {
+ array = decoder.ReadArrayElements(buffer, state, count);
+ }
+
+ if (buffer.ReadOffset - startOffset != size)
{
- array[i] = arrayDecoder.ReadValue(buffer, state);
+ throw new DecodeException(
+ "Encoded size indicates the array encoding should have been " + size +
+ " bytes but the actual bytes read was " + (buffer.ReadOffset - startOffset));
}
return array;
}
- else
+ finally
{
- return decoder.ReadArrayElements(buffer, state, count);
+ state.DecreaseDepth();
}
}
public override object ReadValue(Stream stream, IStreamDecoderState state)
{
- _ = ReadSize(stream, state);
- int count = ReadCount(stream, state);
+ return ReadValue(stream, state, typeof(object));
+ }
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+ public object ReadValue(Stream stream, IStreamDecoderState state, Type ofType)
+ {
+ state.IncreaseDepth();
- if (decoder is IPrimitiveArrayTypeDecoder arrayDecoder)
+ try
{
- object[] array = new object[count];
- for (int i = 0; i < count; i++)
+ int size = ReadSize(stream, state);
+
+ if (size > state.MaxArraySize || size < 0)
{
- array[i] = arrayDecoder.ReadValue(stream, state);
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the maximum encoded length to decode ({1})",
+ (uint) size, state.MaxArraySize));
}
- return array;
+ int count = ReadCount(stream, state);
+
+ IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+
+ if (!decoder.DecodesType.IsAssignableTo(ofType))
+ {
+ throw new DecodeException(String.Format(
+ "Unexpected type {0}. Expected a type assignable to {1}", decoder.DecodesType,ofType.Name));
+ }
+
+ if (decoder is IPrimitiveArrayTypeDecoder arrayDecoder)
+ {
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array length indicated {0} is greater than the encoded array size ({1})", (uint) count, size));
+ }
+
+ object[] array = new object[count];
+ for (int i = 0; i < count; i++)
+ {
+ array[i] = arrayDecoder.ReadValue(stream, state);
+ }
+
+ return array;
+ }
+ else
+ {
+ return decoder.ReadArrayElements(stream, state, count);
+ }
}
- else
+ finally
{
- return decoder.ReadArrayElements(stream, state, count);
+ state.DecreaseDepth();
}
}
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- buffer.SkipBytes(ReadSize(buffer, state));
+ int size = ReadSize(buffer, state);
+
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of data available to decode ({1})",
+ (uint) size, buffer.ReadableBytes));
+ }
+
+ buffer.SkipBytes(size);
}
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- ProtonStreamReadUtils.SkipBytes(stream, ReadSize(stream, state));
+ int size = ReadSize(stream, state);
+
+ if (size > state.MaxArraySize || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the maximum encoded length to decode ({1})",
+ (uint) size, state.MaxArraySize));
+ }
+
+ ProtonStreamReadUtils.SkipBytes(stream, size);
}
protected abstract int ReadSize(IProtonBuffer buffer, IDecoderState state);
diff --git a/src/Proton/Codec/Decoders/Primitives/AbstractBinaryDecoder.cs b/src/Proton/Codec/Decoders/Primitives/AbstractBinaryDecoder.cs
index 6a1ef27..a38cfe3 100644
--- a/src/Proton/Codec/Decoders/Primitives/AbstractBinaryDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/AbstractBinaryDecoder.cs
@@ -29,11 +29,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
int length = ReadSize(buffer, state);
- if (length > buffer.ReadableBytes)
+ if (length > buffer.ReadableBytes || length < 0)
{
throw new DecodeException(
- string.Format("Binary data size {0} is specified to be greater than the amount " +
- "of data available ({1})", length, buffer.ReadableBytes));
+ string.Format("Binary data size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) length, buffer.ReadableBytes));
}
IProtonBuffer payload = buffer.Copy(buffer.ReadOffset, length);
@@ -45,10 +45,19 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override object ReadValue(Stream stream, IStreamDecoderState state)
{
+ int length = ReadSize(stream, state);
+
+ if (length > state.MaxBinarySize || length < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Binary encoded length is specified to be greater than the maximum allowed length " +
+ "l:(%d) m:(%d)", (uint) length, state.MaxBinarySize));
+ }
+
try
{
return ProtonByteBufferAllocator.Instance.Wrap(
- ProtonStreamReadUtils.ReadBytes(stream, ReadSize(stream, state)));
+ ProtonStreamReadUtils.ReadBytes(stream, length));
}
catch (IOException ex)
{
@@ -60,11 +69,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
int length = ReadSize(buffer, state);
- if (length > buffer.ReadableBytes)
+ if (length > buffer.ReadableBytes || length < 0)
{
throw new DecodeException(
string.Format("Binary data size {0} is specified to be greater than the amount " +
- "of data available ({1})", length, buffer.ReadableBytes));
+ "of data available ({1})", (uint) length, buffer.ReadableBytes));
}
buffer.SkipBytes(length);
@@ -72,18 +81,16 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- try
- {
- ProtonStreamReadUtils.SkipBytes(stream, ReadSize(stream, state));
- }
- catch (ArgumentOutOfRangeException ex)
- {
- throw new DecodeException("Error while skipping Binary payload bytes", ex);
- }
- catch (IOException ex)
+ int length = ReadSize(stream, state);
+
+ if (length > state.MaxBinarySize || length < 0)
{
- throw new DecodeException("Error while skipping Binary payload bytes", ex);
+ throw new DecodeException(String.Format(
+ "Binary encoded length is specified to be greater than the maximum allowed length " +
+ "l:(%d) m:(%d)", length, state.MaxBinarySize));
}
+
+ ProtonStreamReadUtils.SkipBytes(stream, (uint) length);
}
#region BinaryTypeDecoder abstract methods
diff --git a/src/Proton/Codec/Decoders/Primitives/AbstractListTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/AbstractListTypeDecoder.cs
index a48d08b..f149a9e 100644
--- a/src/Proton/Codec/Decoders/Primitives/AbstractListTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/AbstractListTypeDecoder.cs
@@ -29,50 +29,91 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
/// </summary>
public abstract class AbstractListTypeDecoder : AbstractPrimitiveTypeDecoder, IListTypeDecoder
{
+ private static readonly int MAX_LIST_PREALLOCATION = 256;
+
public override Type DecodesType => typeof(IList);
public IList<T> ReadList<T>(IProtonBuffer buffer, IDecoderState state)
{
- int size = ReadSize(buffer, state);
+ state.IncreaseDepth();
- // Ensure we do not allocate an array of size greater then the available data, otherwise there is a risk for an OOM error
- if (size > buffer.ReadableBytes)
+ try
{
- throw new DecodeException(string.Format(
- "List element size {0} is specified to be greater than the amount " +
- "of data available ({1})", size, buffer.ReadableBytes));
+ int size = ReadSize(buffer, state);
+ long expectedEndPos = buffer.ReadOffset + size;
+
+ // Ensure we do not allocate an array of size greater then the available data, otherwise there is a risk for an OOM error
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "List element size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) size, buffer.ReadableBytes));
+ }
+
+ int count = ReadCount(buffer, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoded element count is specified to be greater than the encoded size " +
+ "s:(%d) c:(%d)", size, count));
+ }
+
+ IList<T> list = new List<T>(Math.Min(MAX_LIST_PREALLOCATION, count));
+ for (int i = 0; i < count; i++)
+ {
+ list.Add(state.Decoder.ReadObject<T>(buffer, state));
+ }
+
+ if (buffer.ReadOffset != expectedEndPos)
+ {
+ throw new DecodeException("List decoding did not read the expected amount of bytes: " + size);
+ }
+
+ return list;
}
-
- int count = ReadCount(buffer, state);
-
- if (count > buffer.ReadableBytes)
+ finally
{
- throw new DecodeException(string.Format(
- "List encoded element count {0} is specified to be greater than the amount " +
- "of data available ({1})", count, buffer.ReadableBytes));
+ state.DecreaseDepth();
}
-
- IList<T> list = new List<T>(count);
- for (int i = 0; i < count; i++)
- {
- list.Add(state.Decoder.ReadObject<T>(buffer, state));
- }
-
- return list;
}
public IList<T> ReadList<T>(Stream stream, IStreamDecoderState state)
{
- ReadSize(stream, state);
- int count = ReadCount(stream, state);
+ state.IncreaseDepth();
- IList<T> list = new List<T>(count);
- for (int i = 0; i < count; i++)
+ try
{
- list.Add(state.Decoder.ReadObject<T>(stream, state));
+ int size = ReadSize(stream, state);
+
+ if (size > state.MaxListSize || size < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoding size is specified to be greater than the maximum allowed size " +
+ "c:(%d) m:(%d)", (uint) size, state.MaxListSize));
+ }
+
+ int count = ReadCount(stream, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoded element count is specified to be greater than the encoded size " +
+ "s:(%d) c:(%d)", size, count));
+ }
+
+ IList<T> list = new List<T>(Math.Min(MAX_LIST_PREALLOCATION, count));
+ for (int i = 0; i < count; i++)
+ {
+ list.Add(state.Decoder.ReadObject<T>(stream, state));
+ }
+
+ return list;
+ }
+ finally
+ {
+ state.DecreaseDepth();
}
-
- return list;
}
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
@@ -87,18 +128,47 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- buffer.SkipBytes(ReadSize(buffer, state));
+ int size = ReadSize(buffer, state);
+
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "List element size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) size, buffer.ReadableBytes));
+ }
+
+ state.IncreaseDepth();
+
+ try
+ {
+ buffer.SkipBytes(size);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
+ int size = ReadSize(stream, state);
+
+ if (size > state.MaxListSize || size < 0)
+ {
+ throw new DecodeException(String.Format(
+ "List encoding size is specified to be greater than the maximum allowed size " +
+ "c:(%d) m:(%d)", (uint) size, state.MaxListSize));
+ }
+
+ state.IncreaseDepth();
+
try
{
- ProtonStreamReadUtils.SkipBytes(stream, ReadSize(stream, state));
+ ProtonStreamReadUtils.SkipBytes(stream, size);
}
- catch (IOException ex)
+ finally
{
- throw new DecodeException("Error while reading List payload bytes", ex);
+ state.DecreaseDepth();
}
}
diff --git a/src/Proton/Codec/Decoders/Primitives/AbstractMapTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/AbstractMapTypeDecoder.cs
index e2d1136..3358039 100644
--- a/src/Proton/Codec/Decoders/Primitives/AbstractMapTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/AbstractMapTypeDecoder.cs
@@ -29,63 +29,110 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
/// </summary>
public abstract class AbstractMapTypeDecoder : AbstractPrimitiveTypeDecoder, IMapTypeDecoder
{
+ private static readonly int MAX_MAP_PREALLOCATION = 256;
+
public override Type DecodesType => typeof(IDictionary);
public IDictionary<K, V> ReadMap<K, V>(IProtonBuffer buffer, IDecoderState state)
{
- int size = ReadSize(buffer, state);
-
- // Ensure we do not allocate an array of size greater then the available data, otherwise there is a risk for an OOM error
- if (size > buffer.ReadableBytes)
- {
- throw new DecodeException(string.Format(
- "Map element size {0} is specified to be greater than the amount " +
- "of data available ({1})", size, buffer.ReadableBytes));
- }
+ state.IncreaseDepth();
- int count = ReadCount(buffer, state);
-
- if (count % 2 != 0)
+ try
{
- throw new DecodeException(string.Format(
- "Map encoded number of elements {0} is not an even number.", count));
+ int size = ReadSize(buffer, state);
+ long expectedEndPos = buffer.ReadOffset + size;
+
+ // Ensure we do not allocate an array of size greater then the available data, otherwise there is a risk for an OOM error
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map element size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) size, buffer.ReadableBytes));
+ }
+
+ int count = ReadCount(buffer, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map element count {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) count, size));
+ }
+
+ if (count % 2 != 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map encoded number of elements {0} is not an even number.", count));
+ }
+
+ int elements = count / 2;
+ IDictionary<K, V> map = new Dictionary<K, V>(Math.Min(MAX_MAP_PREALLOCATION, elements));
+ for (int i = 0; i < elements; i++)
+ {
+ K key = state.Decoder.ReadObject<K>(buffer, state);
+ V value = state.Decoder.ReadObject<V>(buffer, state);
+
+ map.Add(key, value);
+ }
+
+ if (buffer.ReadOffset != expectedEndPos)
+ {
+ throw new DecodeException("Map decoding did not read the expected amount of bytes: " + size);
+ }
+
+ return map;
}
-
- // Count include both key and value so we must include that in the loop
- IDictionary<K, V> map = new Dictionary<K, V>(count);
- for (int i = 0; i < count / 2; i++)
+ finally
{
- K key = state.Decoder.ReadObject<K>(buffer, state);
- V value = state.Decoder.ReadObject<V>(buffer, state);
-
- map.Add(key, value);
+ state.DecreaseDepth();
}
-
- return map;
}
public IDictionary<K, V> ReadMap<K, V>(Stream stream, IStreamDecoderState state)
{
- ReadSize(stream, state);
- int count = ReadCount(stream, state);
+ state.IncreaseDepth();
- if (count % 2 != 0)
+ try
{
- throw new DecodeException(string.Format(
- "Map encoded number of elements {0} is not an even number.", count));
+ int size = ReadSize(stream, state);
+
+ if (size > state.MaxMapSize || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map encoding size {0} is specified to be greater than the maximum " +
+ "allowed size value ({1})", (uint) size, state.MaxMapSize));
+ }
+
+ int count = ReadCount(stream, state);
+
+ if (count > size || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map element count {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) count, size));
+ }
+
+ if (count % 2 != 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map encoded number of elements {0} is not an even number.", count));
+ }
+
+ int elements = count / 2;
+ IDictionary<K, V> map = new Dictionary<K, V>(Math.Min(MAX_MAP_PREALLOCATION, elements));
+ for (int i = 0; i < elements; i++)
+ {
+ K key = state.Decoder.ReadObject<K>(stream, state);
+ V value = state.Decoder.ReadObject<V>(stream, state);
+ map.Add(key, value);
+ }
+
+ return map;
}
-
- // Count include both key and value so we must include that in the loop
- IDictionary<K, V> map = new Dictionary<K, V>(count);
- for (int i = 0; i < count / 2; i++)
+ finally
{
- K key = state.Decoder.ReadObject<K>(stream, state);
- V value = state.Decoder.ReadObject<V>(stream, state);
-
- map.Add(key, value);
+ state.DecreaseDepth();
}
-
- return map;
}
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
@@ -100,18 +147,48 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- buffer.SkipBytes(ReadSize(buffer, state));
+ int size = ReadSize(buffer, state);
+
+ // Ensure we do not allocate an array of size greater then the available data, otherwise there is a risk for an OOM error
+ if (size > buffer.ReadableBytes || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map element size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) size, buffer.ReadableBytes));
+ }
+
+ state.IncreaseDepth();
+
+ try
+ {
+ buffer.SkipBytes(size);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
+ int size = ReadSize(stream, state);
+
+ if (size > state.MaxMapSize || size < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Map encoding size {0} is specified to be greater than the maximum " +
+ "allowed size value ({1})", (uint) size, state.MaxMapSize));
+ }
+
+ state.IncreaseDepth();
+
try
{
- ProtonStreamReadUtils.SkipBytes(stream, ReadSize(stream, state));
+ ProtonStreamReadUtils.SkipBytes(stream, size);
}
- catch (IOException ex)
+ finally
{
- throw new DecodeException("Error while reading List payload bytes", ex);
+ state.DecreaseDepth();
}
}
diff --git a/src/Proton/Codec/Decoders/Primitives/AbstractStringTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/AbstractStringTypeDecoder.cs
index 579c539..16ab578 100644
--- a/src/Proton/Codec/Decoders/Primitives/AbstractStringTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/AbstractStringTypeDecoder.cs
@@ -30,11 +30,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
int length = ReadSize(buffer, state);
- if (length > buffer.ReadableBytes)
+ if (length > buffer.ReadableBytes || length < 0)
{
throw new DecodeException(string.Format(
- "String encoded size {0} is specified to be greater than the amount " +
- "of data available ({1})", length, buffer.ReadableBytes));
+ "String encoded size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) length, buffer.ReadableBytes));
}
if (length != 0)
@@ -51,6 +51,13 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
int length = ReadSize(stream, state);
+ if (length > state.MaxStringSize || length < 0)
+ {
+ throw new DecodeException(string.Format(
+ "String encoded size {0} is specified to be greater than the amount " +
+ "allowed by configuration ({1})", (uint) length, state.MaxStringSize));
+ }
+
if (length != 0)
{
return state.DecodeUtf8(stream, length);
@@ -63,19 +70,30 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- buffer.SkipBytes(ReadSize(buffer, state));
+ int length = ReadSize(buffer, state);
+
+ if (length > buffer.ReadableBytes || length < 0)
+ {
+ throw new DecodeException(string.Format(
+ "String encoded size {0} is specified to be greater than the amount " +
+ "of data available ({1})", (uint) length, buffer.ReadableBytes));
+ }
+
+ buffer.SkipBytes(length);
}
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- try
- {
- ProtonStreamReadUtils.SkipBytes(stream, ReadSize(stream, state));
- }
- catch (IOException ex)
+ int length = ReadSize(stream, state);
+
+ if (length > state.MaxStringSize || length < 0)
{
- throw new DecodeException("Error while reading String payload bytes", ex);
+ throw new DecodeException(string.Format(
+ "String encoded size {0} is specified to be greater than the amount " +
+ "allowed by configuration ({1})", (uint) length, state.MaxStringSize));
}
+
+ ProtonStreamReadUtils.SkipBytes(stream, length);
}
protected abstract int ReadSize(IProtonBuffer buffer, IDecoderState state);
diff --git a/src/Proton/Codec/Decoders/Primitives/AbstractSymbolTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/AbstractSymbolTypeDecoder.cs
index 4fa7bf2..f4af667 100644
--- a/src/Proton/Codec/Decoders/Primitives/AbstractSymbolTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/AbstractSymbolTypeDecoder.cs
@@ -39,18 +39,18 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
return Symbol.Lookup("");
}
- if (length > buffer.ReadableBytes)
+ if (length > buffer.ReadableBytes || length < 0)
{
throw new DecodeException(string.Format(
"Symbol encoded size {0} is specified to be greater than the amount " +
- "of data available {1}", length, buffer.ReadableBytes));
+ "of data available {1}", (uint) length, buffer.ReadableBytes));
}
IProtonBuffer symbolBuffer = buffer.Copy(buffer.ReadOffset, length);
buffer.SkipBytes(length);
- return Symbol.Lookup(symbolBuffer);
+ return SymbolLookup(symbolBuffer, true);
}
public override Symbol ReadValue(Stream stream, IStreamDecoderState state)
@@ -62,6 +62,13 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
return Symbol.Lookup("");
}
+ if (length > state.MaxSymbolSize || length < 0)
+ {
+ throw new DecodeException(String.Format(
+ "Binary encoded length is specified to be greater than the maximum allowed length " +
+ "l:(%d) m:(%d)", (uint) length, state.MaxSymbolSize));
+ }
+
byte[] symbolBytes;
try
@@ -73,29 +80,52 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
throw new DecodeException("Error while reading Symbol payload bytes", ex);
}
- return Symbol.Lookup(ProtonByteBufferAllocator.Instance.Wrap(symbolBytes));
+ return SymbolLookup(ProtonByteBufferAllocator.Instance.Wrap(symbolBytes), false);
}
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- buffer.SkipBytes(ReadSize(buffer, state));
+ int length = ReadSize(buffer, state);
+
+ if (length > buffer.ReadableBytes || length < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Symbol encoded size {0} is specified to be greater than the amount " +
+ "of data available {1}", (uint) length, buffer.ReadableBytes));
+ }
+
+ buffer.SkipBytes(length);
}
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- try
- {
- ProtonStreamReadUtils.SkipBytes(stream, ReadSize(stream, state));
- }
- catch (IOException ex)
+ int length = ReadSize(stream, state);
+
+ if (length > state.MaxSymbolSize || length < 0)
{
- throw new DecodeException("Error while reading String payload bytes", ex);
+ throw new DecodeException(String.Format(
+ "Binary encoded length is specified to be greater than the maximum allowed length " +
+ "l:(%d) m:(%d)", (uint) length, state.MaxSymbolSize));
}
+
+ ProtonStreamReadUtils.SkipBytes(stream, length);
}
protected abstract int ReadSize(IProtonBuffer buffer, IDecoderState state);
protected abstract int ReadSize(Stream stream, IStreamDecoderState state);
+ /// <summary>
+ /// Gets a singleton Symbol instance that matches the given IProtonBuffer byte view
+ /// of the Symbol. A subclass can override this to produce the Symbol singleton from
+ /// a source other than the default which is the general symbol cache.
+ /// </summary>
+ /// <param name="buffer"></param>
+ /// <param name="copyOnCreate"></param>
+ /// <returns>A Symbol object that is backed by the value in the buffer</returns>
+ protected virtual Symbol SymbolLookup(IProtonBuffer buffer, bool copyOnCreate)
+ {
+ return Symbol.Lookup(buffer, copyOnCreate);
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/BooleanFalseTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/BooleanFalseTypeDecoder.cs
index aee6d1a..df69626 100644
--- a/src/Proton/Codec/Decoders/Primitives/BooleanFalseTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/BooleanFalseTypeDecoder.cs
@@ -27,6 +27,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override Type DecodesType => typeof(bool);
+ public override bool IsZeroWidth => true;
+
public override object ReadValue(IProtonBuffer buffer, IDecoderState state) => false;
public override object ReadValue(Stream stream, IStreamDecoderState state) => false;
@@ -38,5 +40,25 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
}
+
+ protected override void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/BooleanTrueTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/BooleanTrueTypeDecoder.cs
index d56c57b..9489d89 100644
--- a/src/Proton/Codec/Decoders/Primitives/BooleanTrueTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/BooleanTrueTypeDecoder.cs
@@ -27,6 +27,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override Type DecodesType => typeof(bool);
+ public override bool IsZeroWidth => true;
+
public override object ReadValue(IProtonBuffer buffer, IDecoderState state) => true;
public override object ReadValue(Stream stream, IStreamDecoderState state) => true;
@@ -38,5 +40,25 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
}
+
+ protected override void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/List0TypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/List0TypeDecoder.cs
index edfd17f..6f9eb5f 100644
--- a/src/Proton/Codec/Decoders/Primitives/List0TypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/List0TypeDecoder.cs
@@ -29,6 +29,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override Type DecodesType => typeof(IList);
+ public override bool IsZeroWidth => true;
+
public int ReadCount(IProtonBuffer buffer, IDecoderState state)
{
return 0;
@@ -41,12 +43,30 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public IList<T> ReadList<T>(IProtonBuffer buffer, IDecoderState state)
{
- return (IList<T>) Array.Empty<T>();
+ state.IncreaseDepth();
+
+ try
+ {
+ return (IList<T>)Array.Empty<T>();
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public IList<T> ReadList<T>(Stream stream, IStreamDecoderState state)
{
- return (IList<T>) Array.Empty<T>();
+ state.IncreaseDepth();
+
+ try
+ {
+ return (IList<T>)Array.Empty<T>();
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public int ReadSize(IProtonBuffer buffer, IDecoderState state)
@@ -61,20 +81,74 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
{
- return (IList) Array.Empty<object>();
+ state.IncreaseDepth();
+
+ try
+ {
+ return (IList) Array.Empty<object>();
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override object ReadValue(Stream stream, IStreamDecoderState state)
{
- return (IList) Array.Empty<object>();
+ state.IncreaseDepth();
+
+ try
+ {
+ return (IList) Array.Empty<object>();
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
+ try
+ {
+ state.IncreaseDepth();
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
+ try
+ {
+ state.IncreaseDepth();
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
index dca1ea2..c99837c 100644
--- a/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
@@ -27,6 +27,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override Type DecodesType => typeof(void);
+ public override bool IsZeroWidth => true;
+
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
{
return null;
@@ -44,5 +46,39 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
}
+
+ public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ ValidateArrayPreconditions(buffer, state, count);
+
+ return new object[count];
+ }
+
+ public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
+ {
+ ValidateArrayPreconditions(stream, state, count);
+
+ return new object[count];
+ }
+
+ protected override void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/SaslSymbol32TypeDecoder.cs
similarity index 68%
copy from src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
copy to src/Proton/Codec/Decoders/Primitives/SaslSymbol32TypeDecoder.cs
index dca1ea2..9f5ffc6 100644
--- a/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/SaslSymbol32TypeDecoder.cs
@@ -15,34 +15,29 @@
* limitations under the License.
*/
-using System;
using System.IO;
using Apache.Qpid.Proton.Buffer;
+using Apache.Qpid.Proton.Types;
namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
- public sealed class NullTypeDecoder : AbstractPrimitiveTypeDecoder
+ public sealed class SaslSymbol32TypeDecoder : AbstractSymbolTypeDecoder
{
- public override EncodingCodes EncodingCode => EncodingCodes.Null;
+ public override EncodingCodes EncodingCode => EncodingCodes.Sym32;
- public override Type DecodesType => typeof(void);
-
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- return null;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected override int ReadSize(IProtonBuffer buffer, IDecoderState state)
{
- return null;
+ return buffer.ReadInt();
}
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
+ protected override int ReadSize(Stream stream, IStreamDecoderState state)
{
+ return ProtonStreamReadUtils.ReadInt(stream);
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override Symbol SymbolLookup(IProtonBuffer buffer, bool copyOnCreate)
{
+ return Symbol.SaslLookup(buffer, copyOnCreate);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/SaslSymbol8TypeDecoder.cs
similarity index 68%
copy from src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
copy to src/Proton/Codec/Decoders/Primitives/SaslSymbol8TypeDecoder.cs
index dca1ea2..bd85378 100644
--- a/src/Proton/Codec/Decoders/Primitives/NullTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/SaslSymbol8TypeDecoder.cs
@@ -15,34 +15,29 @@
* limitations under the License.
*/
-using System;
using System.IO;
using Apache.Qpid.Proton.Buffer;
+using Apache.Qpid.Proton.Types;
namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
{
- public sealed class NullTypeDecoder : AbstractPrimitiveTypeDecoder
+ public sealed class SaslSymbol8TypeDecoder : AbstractSymbolTypeDecoder
{
- public override EncodingCodes EncodingCode => EncodingCodes.Null;
+ public override EncodingCodes EncodingCode => EncodingCodes.Sym8;
- public override Type DecodesType => typeof(void);
-
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- return null;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
+ protected override int ReadSize(IProtonBuffer buffer, IDecoderState state)
{
- return null;
+ return buffer.ReadUnsignedByte();
}
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
+ protected override int ReadSize(Stream stream, IStreamDecoderState state)
{
+ return ProtonStreamReadUtils.ReadUnsignedByte(stream);
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
+ protected override Symbol SymbolLookup(IProtonBuffer buffer, bool copyOnCreate)
{
+ return Symbol.SaslLookup(buffer, copyOnCreate);
}
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/UnsignedInteger0TypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/UnsignedInteger0TypeDecoder.cs
index 336f53c..0721ba3 100644
--- a/src/Proton/Codec/Decoders/Primitives/UnsignedInteger0TypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/UnsignedInteger0TypeDecoder.cs
@@ -27,9 +27,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override Type DecodesType => typeof(uint);
+ public override bool IsZeroWidth => true;
+
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
{
- return (uint) 0;
+ return (uint)0;
}
public override object ReadValue(Stream stream, IStreamDecoderState state)
@@ -44,5 +46,25 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
}
+
+ protected override void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/Primitives/UnsignedLong0TypeDecoder.cs b/src/Proton/Codec/Decoders/Primitives/UnsignedLong0TypeDecoder.cs
index 36e18db..e4e1b2c 100644
--- a/src/Proton/Codec/Decoders/Primitives/UnsignedLong0TypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Primitives/UnsignedLong0TypeDecoder.cs
@@ -27,9 +27,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override Type DecodesType => typeof(ulong);
+ public override bool IsZeroWidth => true;
+
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
{
- return (ulong) 0;
+ return (ulong)0;
}
public override object ReadValue(Stream stream, IStreamDecoderState state)
@@ -44,5 +46,25 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Primitives
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
}
+
+ protected override void ValidateArrayPreconditions(IProtonBuffer buffer, IDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
+
+ protected override void ValidateArrayPreconditions(Stream stream, IStreamDecoderState state, int count)
+ {
+ if (count > state.MaxZeroWidthArrayElements || count < 0)
+ {
+ throw new DecodeException(string.Format(
+ "Array size indicated {0} is greater than the amount of elements allowed for zero sized primitives ({1})",
+ (uint) count, state.MaxZeroWidthArrayElements));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Codec/Decoders/ProtonDecoder.cs b/src/Proton/Codec/Decoders/ProtonDecoder.cs
index fc09b30..8c5baf4 100644
--- a/src/Proton/Codec/Decoders/ProtonDecoder.cs
+++ b/src/Proton/Codec/Decoders/ProtonDecoder.cs
@@ -25,6 +25,18 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public sealed class ProtonDecoder : IDecoder
{
+ /// <summary>
+ /// The number of unknown described type decoders that are cached for performance
+ /// but limited for memory protection.
+ /// </summary>
+ public static readonly int UnknownDescribedTypeCacheLimit = 16;
+
+ /// <summary>
+ /// If the descriptor for an unknown described type is a Symbol then it must have a
+ /// length shorter than this value to be cached for future lookup.
+ /// </summary>
+ public static readonly int UnknownDescribedTypeDescriptorSizeLimit = 64;
+
/// <summary>
/// The decoders for primitives are fixed and cannot be altered by users who want
/// to register custom decoders. The decoders created here are stateless and can be
@@ -32,6 +44,12 @@ namespace Apache.Qpid.Proton.Codec.Decoders
/// </summary>
private static readonly IPrimitiveTypeDecoder[] primitiveDecoders = new IPrimitiveTypeDecoder[256];
+ public enum DecoderMode
+ {
+ Sasl,
+ Default
+ }
+
static ProtonDecoder()
{
primitiveDecoders[(int)EncodingCodes.Boolean] = new BooleanTypeDecoder();
@@ -77,6 +95,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders
// Initialize the locally used primitive type decoders for the main API
symbol8Decoder = (Symbol8TypeDecoder)primitiveDecoders[(int)EncodingCodes.Sym8];
symbol32Decoder = (Symbol32TypeDecoder)primitiveDecoders[(int)EncodingCodes.Sym32];
+ saslSymbol8Decoder = new SaslSymbol8TypeDecoder();
+ saslSymbol32Decoder = new SaslSymbol32TypeDecoder();
binary8Decoder = (Binary8TypeDecoder)primitiveDecoders[(int)EncodingCodes.VBin8];
binary32Decoder = (Binary32TypeDecoder)primitiveDecoders[(int)EncodingCodes.VBin32];
list8Decoder = (List8TypeDecoder)primitiveDecoders[(int)EncodingCodes.List8];
@@ -94,14 +114,28 @@ namespace Apache.Qpid.Proton.Codec.Decoders
private readonly IDictionary<object, IDescribedTypeDecoder> describedTypeDecoders =
new Dictionary<object, IDescribedTypeDecoder>();
+ /// <summary>
+ /// Registry of decoders for described types which are not registered which can be updated with a
+ /// limited number of cached decoders to speed up processing
+ /// </summary>
+ private readonly IDictionary<object, IDescribedTypeDecoder> unknownDescribedTypeDecoders =
+ new Dictionary<object, IDescribedTypeDecoder>();
+
/// <summary>
/// Quick access to decoders that handle AMQP types like Transfer, Properties etc.
/// </summary>
private readonly IDescribedTypeDecoder[] amqpTypeDecoders = new IDescribedTypeDecoder[256];
+ /// <summary>
+ /// User supplied callback to decode descriptors that are reserved types.
+ /// </summary>
+ private readonly Func<IProtonBuffer, IDecoderState, object> reservedDescriptorDecoder;
+
// Internal Decoders used to prevent user to access Proton specific decoding methods
private static readonly Symbol8TypeDecoder symbol8Decoder;
private static readonly Symbol32TypeDecoder symbol32Decoder;
+ private static readonly SaslSymbol8TypeDecoder saslSymbol8Decoder;
+ private static readonly SaslSymbol32TypeDecoder saslSymbol32Decoder;
private static readonly Binary8TypeDecoder binary8Decoder;
private static readonly Binary32TypeDecoder binary32Decoder;
private static readonly List8TypeDecoder list8Decoder;
@@ -113,6 +147,44 @@ namespace Apache.Qpid.Proton.Codec.Decoders
private ProtonDecoderState cachedDecoderState;
+ private readonly DecoderMode decoderMode;
+ private readonly IPrimitiveTypeDecoder[] localPrimitiveDecoders;
+ private readonly AbstractSymbolTypeDecoder localSymbol8Decoder;
+ private readonly AbstractSymbolTypeDecoder localSymbol32Decoder;
+
+ public ProtonDecoder() : this(DecoderMode.Default)
+ {
+ }
+
+ public ProtonDecoder(DecoderMode mode) : this(mode, null)
+ {
+ }
+
+ public ProtonDecoder(Func<IProtonBuffer, IDecoderState, object> descriptorDecoder) : this(DecoderMode.Default, descriptorDecoder)
+ {
+ }
+
+ public ProtonDecoder(DecoderMode mode, Func<IProtonBuffer, IDecoderState, object> descriptorDecoder)
+ {
+ decoderMode = mode;
+ reservedDescriptorDecoder = descriptorDecoder;
+
+ if (decoderMode == DecoderMode.Sasl)
+ {
+ localSymbol8Decoder = saslSymbol8Decoder;
+ localSymbol32Decoder = saslSymbol32Decoder;
+ localPrimitiveDecoders = (IPrimitiveTypeDecoder[])primitiveDecoders.Clone();
+ localPrimitiveDecoders[(int)EncodingCodes.Sym8] = saslSymbol8Decoder;
+ localPrimitiveDecoders[(int)EncodingCodes.Sym32] = saslSymbol32Decoder;
+ }
+ else
+ {
+ localSymbol8Decoder = symbol8Decoder;
+ localSymbol32Decoder = symbol32Decoder;
+ localPrimitiveDecoders = primitiveDecoders;
+ }
+ }
+
public IDecoderState NewDecoderState()
{
return new ProtonDecoderState(this);
@@ -492,8 +564,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return encodingCode switch
{
- EncodingCodes.Sym8 => symbol8Decoder.ReadValue(buffer, state),
- EncodingCodes.Sym32 => symbol32Decoder.ReadValue(buffer, state),
+ EncodingCodes.Sym8 => localSymbol8Decoder.ReadValue(buffer, state),
+ EncodingCodes.Sym32 => localSymbol32Decoder.ReadValue(buffer, state),
EncodingCodes.Null => null,
_ => throw new DecodeException("Expected Symbol type but found encoding: " + encodingCode),
};
@@ -569,9 +641,9 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public T ReadObject<T>(IProtonBuffer buffer, IDecoderState state)
{
- object result = ReadObject(buffer, state);
+ ITypeDecoder decoder = ReadNextTypeDecoder(buffer, state);
- if (result == null)
+ if (decoder.DecodesType == typeof(void))
{
if (typeof(T).IsValueType)
{
@@ -582,44 +654,48 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return default;
}
}
- else if (result.GetType().IsAssignableTo(typeof(T)))
+ else if (decoder.IsArrayType)
+ {
+ return (T)((IPrimitiveArrayTypeDecoder)decoder).ReadValue(buffer, state, typeof(T));
+ }
+ else if (decoder.DecodesType.IsAssignableTo(typeof(T)))
{
- return (T)result;
+ return (T)decoder.ReadValue(buffer, state);
}
else
{
- throw SignalUnexpectedType(result, typeof(T));
+ throw SignalUnexpectedType(decoder.DecodesType, typeof(T));
}
}
public T[] ReadMultiple<T>(IProtonBuffer buffer, IDecoderState state)
{
- object val = ReadObject(buffer, state);
+ ITypeDecoder decoder = ReadNextTypeDecoder(buffer, state);
- if (val == null)
+ if (decoder.DecodesType == typeof(void))
{
- return null;
- }
- else if (val.GetType().IsArray)
- {
- if (typeof(T).IsAssignableFrom(val.GetType().GetElementType()))
+ if (typeof(T).IsValueType)
{
- return (T[])val;
+ throw SignalUnexpectedType(typeof(T));
}
else
{
- throw SignalUnexpectedType(val, typeof(T).MakeArrayType());
+ return default;
}
}
- else if (typeof(T).IsAssignableFrom(val.GetType()))
+ else if (decoder.IsArrayType)
+ {
+ return (T[])((IPrimitiveArrayTypeDecoder)decoder).ReadValue(buffer, state, typeof(T));
+ }
+ else if (decoder.DecodesType.IsAssignableTo(typeof(T)))
{
T[] array = (T[])Array.CreateInstance(typeof(T), 1);
- array[0] = (T)val;
+ array[0] = (T) decoder.ReadValue(buffer, state);
return array;
}
else
{
- throw SignalUnexpectedType(val, typeof(T).MakeArrayType());
+ throw SignalUnexpectedType(decoder.DecodesType, typeof(T));
}
}
@@ -665,7 +741,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
}
else
{
- return primitiveDecoders[(byte)encodingCode];
+ return localPrimitiveDecoders[(byte)encodingCode];
}
}
@@ -680,13 +756,47 @@ namespace Apache.Qpid.Proton.Codec.Decoders
}
catch (Exception)
{
- buffer.ReadOffset = readPos;
- descriptor = ReadObject(buffer, state);
+ try
+ {
+ buffer.ReadOffset = readPos;
+ descriptor = ReadSymbol(buffer, state);
+ }
+ catch (Exception)
+ {
+ buffer.ReadOffset = readPos;
+ if (decoderMode != DecoderMode.Sasl)
+ {
+ if (reservedDescriptorDecoder != null)
+ {
+ state.IncreaseDepth();
+ try
+ {
+ descriptor = reservedDescriptorDecoder.Invoke(buffer, state);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
+ }
+ else
+ {
+ throw new DecodeException(String.Format(
+ "Cannot decode a type that is using a reserved type descriptor: {}", PeekNextTypeDecoder(buffer, state).DecodesType));
+ }
+ }
+ else
+ {
+ throw new DecodeException("Cannot decode reserved descriptor type in SASL mode.");
+ }
+ }
}
if (!describedTypeDecoders.TryGetValue(descriptor, out IDescribedTypeDecoder typeDecoder))
{
- typeDecoder = HandleUnknownDescribedType(descriptor);
+ if (!unknownDescribedTypeDecoders.TryGetValue(descriptor, out typeDecoder))
+ {
+ typeDecoder = HandleUnknownDescribedType(descriptor);
+ }
}
return typeDecoder;
@@ -733,22 +843,42 @@ namespace Apache.Qpid.Proton.Codec.Decoders
}
}
- private static InvalidCastException SignalUnexpectedType(in Type type)
+ private static DecodeException SignalUnexpectedType(in Type type)
{
- return new InvalidCastException(
+ return new DecodeException(
"Unexpected null decoding, Expected " + type.Name + ".");
}
- private static InvalidCastException SignalUnexpectedType(in object val, in Type type)
+ private static DecodeException SignalUnexpectedType(in object val, in Type type)
{
- return new InvalidCastException(
+ return new DecodeException(
"Unexpected type " + val.GetType().Name + ". Expected " + type.Name + ".");
}
private IDescribedTypeDecoder HandleUnknownDescribedType(in object descriptor)
{
+ if (DecoderMode.Sasl == decoderMode)
+ {
+ throw new DecodeException("Cannot decode unknown described types from a SASL mode decoder");
+ }
+
+ bool canCache;
+
+ if (descriptor is Symbol symbol && symbol.Length > UnknownDescribedTypeDescriptorSizeLimit)
+ {
+ canCache = false;
+ }
+ else
+ {
+ canCache = descriptor is ulong;
+ }
+
UnknownDescribedTypeDecoder typeDecoder = new(descriptor);
- describedTypeDecoders.Add(descriptor, typeDecoder);
+
+ if (canCache && unknownDescribedTypeDecoders.Count < UnknownDescribedTypeCacheLimit)
+ {
+ unknownDescribedTypeDecoders.Add(descriptor, typeDecoder);
+ }
return typeDecoder;
}
diff --git a/src/Proton/Codec/Decoders/ProtonDecoderFactory.cs b/src/Proton/Codec/Decoders/ProtonDecoderFactory.cs
index 20440f4..3a548a3 100644
--- a/src/Proton/Codec/Decoders/ProtonDecoderFactory.cs
+++ b/src/Proton/Codec/Decoders/ProtonDecoderFactory.cs
@@ -29,7 +29,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public static ProtonDecoder Create()
{
- ProtonDecoder decoder = new();
+ ProtonDecoder decoder = new(ProtonDecoder.DecoderMode.Default);
AddMessagingTypeDecoders(decoder);
AddTransactionTypeDecoders(decoder);
@@ -40,7 +40,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public static ProtonDecoder CreateSasl()
{
- ProtonDecoder decoder = new();
+ ProtonDecoder decoder = new(ProtonDecoder.DecoderMode.Sasl);
AddSaslTypeDecoders(decoder);
diff --git a/src/Proton/Codec/Decoders/ProtonDecoderState.cs b/src/Proton/Codec/Decoders/ProtonDecoderState.cs
index b5cf861..a060e8b 100644
--- a/src/Proton/Codec/Decoders/ProtonDecoderState.cs
+++ b/src/Proton/Codec/Decoders/ProtonDecoderState.cs
@@ -22,8 +22,22 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public class ProtonDecoderState : IDecoderState
{
+ /// <summary>
+ /// The default number of elements a zero width array encoding is allowed to have
+ /// before an decoder exception is thrown.
+ /// </summary>
+ public static readonly uint DefaultMaxZeroWidthArrayElements = 0;
+
+ /// <summary>
+ /// The default maximum depth the decoder will allow before triggering an DecodeException when the
+ /// state depth value is increased during a decode process of complex types that can next objects.
+ /// </summary>
+ public static readonly uint DefaultMaxDecodeDepth = 32;
+
private readonly ProtonDecoder decoder;
+ private uint decodeDepth;
+
public ProtonDecoderState(ProtonDecoder decoder)
{
this.decoder = decoder;
@@ -38,7 +52,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public void Reset()
{
- // Nothing needed yet.
+ decodeDepth = 0;
}
public IDecoder Decoder
@@ -46,8 +60,39 @@ namespace Apache.Qpid.Proton.Codec.Decoders
get { return this.decoder; }
}
+ public uint MaxZeroWidthArrayElements { get; set; } = DefaultMaxZeroWidthArrayElements;
+
+ public uint DepthLimit { get; set; } = DefaultMaxDecodeDepth;
+
+ public void IncreaseDepth()
+ {
+ if (++decodeDepth > DepthLimit)
+ {
+ --decodeDepth; // Unwind decrement to ensure the depth returns to zero.
+ throw new DecodeException(
+ "The nesting of types in the object being decoded exceeded the configured limit: " + DepthLimit);
+ }
+ }
+
+ public void DecreaseDepth()
+ {
+ decodeDepth = decodeDepth > 0 ? decodeDepth - 1 : 0;
+ }
+
public string DecodeUtf8(IProtonBuffer buffer, int length)
{
+ if (length < 0)
+ {
+ throw new DecodeException("Specified UTF length:" + length + " cannot be negative.");
+ }
+
+ if (length > buffer.ReadableBytes)
+ {
+ throw new DecodeException(string.Format(
+ "String encoded size %d is specified to be greater than the amount " +
+ "of data available (%d)", length, buffer.ReadableBytes));
+ }
+
if (Utf8Decoder == null)
{
return InternalDecode(buffer, length);
diff --git a/src/Proton/Codec/Decoders/ProtonStreamDecoder.cs b/src/Proton/Codec/Decoders/ProtonStreamDecoder.cs
index 8bb36cc..e3663bf 100644
--- a/src/Proton/Codec/Decoders/ProtonStreamDecoder.cs
+++ b/src/Proton/Codec/Decoders/ProtonStreamDecoder.cs
@@ -26,6 +26,18 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public sealed class ProtonStreamDecoder : IStreamDecoder
{
+ /// <summary>
+ /// The number of unknown described type decoders that are cached for performance
+ /// but limited for memory protection.
+ /// </summary>
+ public static readonly int UnknownDescribedTypeCacheLimit = 16;
+
+ /// <summary>
+ /// If the descriptor for an unknown described type is a Symbol then it must have a
+ /// length shorter than this value to be cached for future lookup.
+ /// </summary>
+ public static readonly int UnknownDescribedTypeDescriptorSizeLimit = 64;
+
/// <summary>
/// The decoders for primitives are fixed and cannot be altered by users who want
/// to register custom decoders. The decoders created here are stateless and can be
@@ -33,6 +45,12 @@ namespace Apache.Qpid.Proton.Codec.Decoders
/// </summary>
private static readonly IPrimitiveTypeDecoder[] primitiveDecoders = new IPrimitiveTypeDecoder[256];
+ public enum DecoderMode
+ {
+ Sasl,
+ Default
+ }
+
static ProtonStreamDecoder()
{
primitiveDecoders[(int)EncodingCodes.Boolean] = new BooleanTypeDecoder();
@@ -78,6 +96,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders
// Initialize the locally used primitive type decoders for the main API
symbol8Decoder = (Symbol8TypeDecoder)primitiveDecoders[(int)EncodingCodes.Sym8];
symbol32Decoder = (Symbol32TypeDecoder)primitiveDecoders[(int)EncodingCodes.Sym32];
+ saslSymbol8Decoder = new SaslSymbol8TypeDecoder();
+ saslSymbol32Decoder = new SaslSymbol32TypeDecoder();
binary8Decoder = (Binary8TypeDecoder)primitiveDecoders[(int)EncodingCodes.VBin8];
binary32Decoder = (Binary32TypeDecoder)primitiveDecoders[(int)EncodingCodes.VBin32];
list8Decoder = (List8TypeDecoder)primitiveDecoders[(int)EncodingCodes.List8];
@@ -95,6 +115,13 @@ namespace Apache.Qpid.Proton.Codec.Decoders
private readonly IDictionary<object, IStreamDescribedTypeDecoder> describedTypeDecoders =
new Dictionary<object, IStreamDescribedTypeDecoder>();
+ /// <summary>
+ /// Registry of decoders for described types which are not registered which can be updated with a
+ /// limited number of cached decoders to speed up processing
+ /// </summary>
+ private readonly IDictionary<object, IStreamDescribedTypeDecoder> unknownDescribedTypeDecoders =
+ new Dictionary<object, IStreamDescribedTypeDecoder>();
+
/// <summary>
/// Quick access to decoders that handle AMQP types like Transfer, Properties etc.
/// </summary>
@@ -103,6 +130,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders
// Internal Decoders used to prevent user to access Proton specific decoding methods
private static readonly Symbol8TypeDecoder symbol8Decoder;
private static readonly Symbol32TypeDecoder symbol32Decoder;
+ private static readonly SaslSymbol8TypeDecoder saslSymbol8Decoder;
+ private static readonly SaslSymbol32TypeDecoder saslSymbol32Decoder;
private static readonly Binary8TypeDecoder binary8Decoder;
private static readonly Binary32TypeDecoder binary32Decoder;
private static readonly List8TypeDecoder list8Decoder;
@@ -112,6 +141,35 @@ namespace Apache.Qpid.Proton.Codec.Decoders
private static readonly String8TypeDecoder string8Decoder;
private static readonly String32TypeDecoder string32Decoder;
+ private readonly DecoderMode decoderMode;
+ private readonly IPrimitiveTypeDecoder[] localPrimitiveDecoders;
+ private readonly AbstractSymbolTypeDecoder localSymbol8Decoder;
+ private readonly AbstractSymbolTypeDecoder localSymbol32Decoder;
+
+ public ProtonStreamDecoder() : this(DecoderMode.Default)
+ {
+ }
+
+ public ProtonStreamDecoder(DecoderMode mode)
+ {
+ decoderMode = mode;
+
+ if (decoderMode == DecoderMode.Sasl)
+ {
+ localSymbol8Decoder = saslSymbol8Decoder;
+ localSymbol32Decoder = saslSymbol32Decoder;
+ localPrimitiveDecoders = (IPrimitiveTypeDecoder[])primitiveDecoders.Clone();
+ localPrimitiveDecoders[(int)EncodingCodes.Sym8] = saslSymbol8Decoder;
+ localPrimitiveDecoders[(int)EncodingCodes.Sym32] = saslSymbol32Decoder;
+ }
+ else
+ {
+ localSymbol8Decoder = symbol8Decoder;
+ localSymbol32Decoder = symbol32Decoder;
+ localPrimitiveDecoders = primitiveDecoders;
+ }
+ }
+
private ProtonStreamDecoderState cachedDecoderState;
public IStreamDecoderState NewDecoderState()
@@ -493,8 +551,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return encodingCode switch
{
- EncodingCodes.Sym8 => symbol8Decoder.ReadValue(stream, state),
- EncodingCodes.Sym32 => symbol32Decoder.ReadValue(stream, state),
+ EncodingCodes.Sym8 => localSymbol8Decoder.ReadValue(stream, state),
+ EncodingCodes.Sym32 => localSymbol32Decoder.ReadValue(stream, state),
EncodingCodes.Null => null,
_ => throw new DecodeException("Expected Symbol type but found encoding: " + encodingCode),
};
@@ -570,9 +628,9 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public T ReadObject<T>(Stream stream, IStreamDecoderState state)
{
- object result = ReadObject(stream, state);
+ IStreamTypeDecoder decoder = ReadNextTypeDecoder(stream, state);
- if (result == null)
+ if (decoder.DecodesType == typeof(void))
{
if (typeof(T).IsValueType)
{
@@ -583,44 +641,48 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return default;
}
}
- else if (result.GetType().IsAssignableTo(typeof(T)))
+ else if (decoder.IsArrayType)
+ {
+ return (T)((IPrimitiveArrayTypeDecoder)decoder).ReadValue(stream, state, typeof(T));
+ }
+ else if (decoder.DecodesType.IsAssignableTo(typeof(T)))
{
- return (T)result;
+ return (T)decoder.ReadValue(stream, state);
}
else
{
- throw SignalUnexpectedType(result, typeof(T));
+ throw SignalUnexpectedType(decoder.DecodesType, typeof(T));
}
}
public T[] ReadMultiple<T>(Stream stream, IStreamDecoderState state)
{
- object val = ReadObject(stream, state);
+ IStreamTypeDecoder decoder = ReadNextTypeDecoder(stream, state);
- if (val == null)
+ if (decoder.DecodesType == typeof(void))
{
- return null;
- }
- else if (val.GetType().IsArray)
- {
- if (typeof(T).IsAssignableFrom(val.GetType().GetElementType()))
+ if (typeof(T).IsValueType)
{
- return (T[])val;
+ throw SignalUnexpectedType(typeof(T));
}
else
{
- throw SignalUnexpectedType(val, typeof(T).MakeArrayType());
+ return default;
}
}
- else if (typeof(T).IsAssignableFrom(val.GetType()))
+ else if (decoder.IsArrayType)
+ {
+ return (T[])((IPrimitiveArrayTypeDecoder)decoder).ReadValue(stream, state, typeof(T));
+ }
+ else if (decoder.DecodesType.IsAssignableTo(typeof(T)))
{
T[] array = (T[])Array.CreateInstance(typeof(T), 1);
- array[0] = (T)val;
+ array[0] = (T) decoder.ReadValue(stream, state);
return array;
}
else
{
- throw SignalUnexpectedType(val, typeof(T).MakeArrayType());
+ throw SignalUnexpectedType(decoder.DecodesType, typeof(T));
}
}
@@ -673,7 +735,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
}
else
{
- return primitiveDecoders[(byte)encodingCode];
+ return localPrimitiveDecoders[(byte)encodingCode];
}
}
@@ -688,9 +750,13 @@ namespace Apache.Qpid.Proton.Codec.Decoders
EncodingCodes.Sym32 => symbol32Decoder.ReadValue(stream, state),
_ => throw new DecodeException("Expected Descriptor type but found encoding: " + encodingCode),
};
+
if (!describedTypeDecoders.TryGetValue(descriptor, out IStreamDescribedTypeDecoder streamTypeDecoder))
{
- streamTypeDecoder = HandleUnknownDescribedType(descriptor);
+ if (!unknownDescribedTypeDecoders.TryGetValue(descriptor, out streamTypeDecoder))
+ {
+ streamTypeDecoder = HandleUnknownDescribedType(descriptor);
+ }
}
return streamTypeDecoder;
@@ -739,22 +805,42 @@ namespace Apache.Qpid.Proton.Codec.Decoders
return this;
}
- private static InvalidCastException SignalUnexpectedType(in Type type)
+ private static DecodeException SignalUnexpectedType(in Type type)
{
- return new InvalidCastException(
+ return new DecodeException(
"Unexpected null decoding, Expected " + type.Name + ".");
}
- private static InvalidCastException SignalUnexpectedType(in object val, in Type type)
+ private static DecodeException SignalUnexpectedType(in object val, in Type type)
{
- return new InvalidCastException(
+ return new DecodeException(
"Unexpected type " + val.GetType().Name + ". Expected " + type.Name + ".");
}
private IStreamDescribedTypeDecoder HandleUnknownDescribedType(in object descriptor)
{
+ if (DecoderMode.Sasl == decoderMode)
+ {
+ throw new DecodeException("Cannot decode unknown described types from a SASL mode decoder");
+ }
+
+ bool canCache;
+
+ if (descriptor is Symbol symbol && symbol.Length > UnknownDescribedTypeDescriptorSizeLimit)
+ {
+ canCache = false;
+ }
+ else
+ {
+ canCache = descriptor is ulong;
+ }
+
IStreamDescribedTypeDecoder typeDecoder = new UnknownDescribedTypeDecoder(descriptor);
- describedTypeDecoders.Add(descriptor, (UnknownDescribedTypeDecoder)typeDecoder);
+
+ if (canCache && unknownDescribedTypeDecoders.Count < UnknownDescribedTypeCacheLimit)
+ {
+ unknownDescribedTypeDecoders.Add(descriptor, typeDecoder);
+ }
return typeDecoder;
}
diff --git a/src/Proton/Codec/Decoders/ProtonStreamDecoderFactory.cs b/src/Proton/Codec/Decoders/ProtonStreamDecoderFactory.cs
index 7014b5c..861d8b2 100644
--- a/src/Proton/Codec/Decoders/ProtonStreamDecoderFactory.cs
+++ b/src/Proton/Codec/Decoders/ProtonStreamDecoderFactory.cs
@@ -29,7 +29,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public static ProtonStreamDecoder Create()
{
- ProtonStreamDecoder decoder = new();
+ ProtonStreamDecoder decoder = new(ProtonStreamDecoder.DecoderMode.Default);
AddMessagingTypeDecoders(decoder);
AddTransactionTypeDecoders(decoder);
@@ -40,7 +40,7 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public static ProtonStreamDecoder CreateSasl()
{
- ProtonStreamDecoder decoder = new();
+ ProtonStreamDecoder decoder = new(ProtonStreamDecoder.DecoderMode.Sasl);
AddSaslTypeDecoders(decoder);
diff --git a/src/Proton/Codec/Decoders/ProtonStreamDecoderState.cs b/src/Proton/Codec/Decoders/ProtonStreamDecoderState.cs
index 7c266d0..e51675e 100644
--- a/src/Proton/Codec/Decoders/ProtonStreamDecoderState.cs
+++ b/src/Proton/Codec/Decoders/ProtonStreamDecoderState.cs
@@ -22,10 +22,24 @@ namespace Apache.Qpid.Proton.Codec.Decoders
{
public class ProtonStreamDecoderState : IStreamDecoderState
{
+ /// <summary>
+ /// The default number of elements a zero width array encoding is allowed to have
+ /// before an decoder exception is thrown.
+ /// </summary>
+ public static readonly uint DefaultMaxZeroWidthArrayElements = 0;
+
+ /// <summary>
+ /// The default maximum depth the decoder will allow before triggering an DecodeException when the
+ /// state depth value is increased during a decode process of complex types that can next objects.
+ /// </summary>
+ public static readonly uint DefaultMaxDecodeDepth = 32;
+
private readonly ProtonStreamDecoder decoder;
public IStreamDecoder Decoder => decoder;
+ private uint decodeDepth;
+
public ProtonStreamDecoderState(ProtonStreamDecoder parent) : base()
{
this.decoder = parent;
@@ -38,13 +52,56 @@ namespace Apache.Qpid.Proton.Codec.Decoders
/// </summary>
public IUtf8StreamDecoder Utf8Decoder { get; set; }
+ public uint MaxZeroWidthArrayElements { get; set; } = DefaultMaxZeroWidthArrayElements;
+
+ public uint MaxStringSize { get; set; } = IStreamDecoderState.DefaultMaxAllocationLimit;
+
+ public uint MaxArraySize { get; set; } = IStreamDecoderState.DefaultMaxAllocationLimit;
+
+ public uint MaxBinarySize { get; set; } = IStreamDecoderState.DefaultMaxAllocationLimit;
+
+ public uint MaxSymbolSize { get; set; } = IStreamDecoderState.DefaultMaxAllocationLimit;
+
+ public uint MaxListSize { get; set; } = IStreamDecoderState.DefaultMaxAllocationLimit;
+
+ public uint MaxMapSize { get; set; } = IStreamDecoderState.DefaultMaxAllocationLimit;
+
public void Reset()
{
- throw new NotImplementedException();
+ decodeDepth = 0;
+ }
+
+ public uint DepthLimit { get; set; } = DefaultMaxDecodeDepth;
+
+ public void IncreaseDepth()
+ {
+ if (++decodeDepth > DepthLimit)
+ {
+ --decodeDepth; // Unwind decrement to ensure the depth returns to zero.
+ throw new DecodeException(
+ "The nesting of types in the object being decoded exceeded the configured limit: " + DepthLimit);
+ }
+ }
+
+ public void DecreaseDepth()
+ {
+ decodeDepth = decodeDepth > 0 ? decodeDepth - 1 : 0;
}
public string DecodeUtf8(Stream stream, int length)
{
+ if (length < 0)
+ {
+ throw new DecodeException("Specified UTF length:" + length + " cannot be negative.");
+ }
+
+ if (length > MaxStringSize)
+ {
+ throw new DecodeException(string.Format(
+ "String encoded size %d is specified to be greater than the amount " +
+ "of data available (%d)", length, MaxStringSize));
+ }
+
if (Utf8Decoder == null)
{
return InternalDecode(stream, length);
diff --git a/src/Proton/Codec/Decoders/ProtonStreamReadUtils.cs b/src/Proton/Codec/Decoders/ProtonStreamReadUtils.cs
index 3e04ef3..8b97324 100644
--- a/src/Proton/Codec/Decoders/ProtonStreamReadUtils.cs
+++ b/src/Proton/Codec/Decoders/ProtonStreamReadUtils.cs
@@ -287,6 +287,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders
throw new DecodeException("Stream was not able to skip the requested amount of bytes: " + amount);
}
}
+ catch (ArgumentOutOfRangeException ex)
+ {
+ throw new DecodeException(
+ string.Format("Error while attempting to skip {0} bytes in the given InputStream", amount), ex);
+ }
catch (IOException ex)
{
throw new DecodeException(
diff --git a/src/Proton/Codec/Decoders/Security/SaslChallengeTypeDecoder.cs b/src/Proton/Codec/Decoders/Security/SaslChallengeTypeDecoder.cs
index 2895451..719f4ba 100644
--- a/src/Proton/Codec/Decoders/Security/SaslChallengeTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Security/SaslChallengeTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Security;
namespace Apache.Qpid.Proton.Codec.Decoders.Security
{
- public sealed class SaslChallengeTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class SaslChallengeTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int RequiredListEntries = 1;
@@ -34,102 +34,24 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Security
public override Type DecodesType => typeof(SaslChallenge);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslChallenge[] result = new SaslChallenge[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => RequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => RequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static SaslChallenge ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslChallenge ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
SaslChallenge result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count != RequiredListEntries)
- {
- throw new DecodeException("SASL Challenge must contain at least one entry: " + count);
- }
- else
- {
- result.Challenge = state.Decoder.ReadBinary(buffer, state);
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslChallenge[] result = new SaslChallenge[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ result.Challenge = state.Decoder.ReadBinary(buffer, state);
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static SaslChallenge ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslChallenge ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
SaslChallenge result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count != RequiredListEntries)
- {
- throw new DecodeException("SASL Challenge must contain at least one entry: " + count);
- }
- else
- {
- result.Challenge = state.Decoder.ReadBinary(stream, state);
- }
+ result.Challenge = state.Decoder.ReadBinary(stream, state);
return result;
}
diff --git a/src/Proton/Codec/Decoders/Security/SaslInitTypeDecoder.cs b/src/Proton/Codec/Decoders/Security/SaslInitTypeDecoder.cs
index f9004b5..42639d5 100644
--- a/src/Proton/Codec/Decoders/Security/SaslInitTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Security/SaslInitTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Security;
namespace Apache.Qpid.Proton.Codec.Decoders.Security
{
- public sealed class SaslInitTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class SaslInitTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinListEntries = 0;
private static readonly int MaxListEntries = 3;
@@ -35,55 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Security
public override Type DecodesType => typeof(SaslInit);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslInit[] result = new SaslInit[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
+ protected override int MinListElements => MinListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
+ protected override int MaxListElements => MaxListEntries;
- private static SaslInit ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslInit ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
SaslInit result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinListEntries)
- {
- throw new DecodeException("Not enough entries in SaslInit list encoding: " + count);
- }
-
- if (count > MaxListEntries)
- {
- throw new DecodeException("To many entries in SaslInit list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
switch (index)
@@ -103,55 +62,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Security
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslInit[] result = new SaslInit[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static SaslInit ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslInit ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
SaslInit result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinListEntries)
- {
- throw new DecodeException("Not enough entries in SaslInit list encoding: " + count);
- }
-
- if (count > MaxListEntries)
- {
- throw new DecodeException("To many entries in SaslInit list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
switch (index)
diff --git a/src/Proton/Codec/Decoders/Security/SaslMechanismsTypeDecoder.cs b/src/Proton/Codec/Decoders/Security/SaslMechanismsTypeDecoder.cs
index acedaba..65e3319 100644
--- a/src/Proton/Codec/Decoders/Security/SaslMechanismsTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Security/SaslMechanismsTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Security;
namespace Apache.Qpid.Proton.Codec.Decoders.Security
{
- public sealed class SaslMechanismsTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class SaslMechanismsTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int RequiredListEntries = 1;
@@ -34,102 +34,24 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Security
public override Type DecodesType => typeof(SaslMechanisms);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslMechanisms[] result = new SaslMechanisms[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => RequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => RequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static SaslMechanisms ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslMechanisms ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
SaslMechanisms result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count != RequiredListEntries)
- {
- throw new DecodeException("SASL Mechanisms must contain at least one entry: " + count);
- }
- else
- {
- result.Mechanisms = state.Decoder.ReadMultiple<Symbol>(buffer, state);
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslMechanisms[] result = new SaslMechanisms[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ result.Mechanisms = state.Decoder.ReadMultiple<Symbol>(buffer, state);
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static SaslMechanisms ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslMechanisms ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
SaslMechanisms result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count != RequiredListEntries)
- {
- throw new DecodeException("SASL Mechanisms must contain at least one entry: " + count);
- }
- else
- {
- result.Mechanisms = state.Decoder.ReadMultiple<Symbol>(stream, state);
- }
+ result.Mechanisms = state.Decoder.ReadMultiple<Symbol>(stream, state);
return result;
}
diff --git a/src/Proton/Codec/Decoders/Security/SaslOutcomeTypeDecoder.cs b/src/Proton/Codec/Decoders/Security/SaslOutcomeTypeDecoder.cs
index e863cca..cacd25c 100644
--- a/src/Proton/Codec/Decoders/Security/SaslOutcomeTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Security/SaslOutcomeTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Security;
namespace Apache.Qpid.Proton.Codec.Decoders.Security
{
- public sealed class SaslOutcomeTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class SaslOutcomeTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinListEntries = 1;
private static readonly int MaxListEntries = 2;
@@ -35,131 +35,33 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Security
public override Type DecodesType => typeof(SaslOutcome);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MinListElements => MinListEntries;
- SaslOutcome[] result = new SaslOutcome[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
+ protected override int MaxListElements => MaxListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static SaslOutcome ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslOutcome ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
SaslOutcome result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinListEntries)
- {
- throw new DecodeException("Not enough entries in SaslOutcome list encoding: " + count);
- }
-
- if (count > MaxListEntries)
- {
- throw new DecodeException("To many entries in SaslOutcome list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
- {
- switch (index)
- {
- case 0:
- result.Code = (SaslCode)state.Decoder.ReadUnsignedByte(buffer, state);
- break;
- case 1:
- result.AdditionalData = state.Decoder.ReadBinary(buffer, state);
- break;
- }
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ result.Code = (SaslCode)state.Decoder.ReadUnsignedByte(buffer, state);
- SaslOutcome[] result = new SaslOutcome[count];
- for (int i = 0; i < count; ++i)
+ if (count == 2)
{
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
+ result.AdditionalData = state.Decoder.ReadBinary(buffer, state);
}
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static SaslOutcome ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslOutcome ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
SaslOutcome result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- // Don't decode anything if things already look wrong.
- if (count < MinListEntries)
- {
- throw new DecodeException("Not enough entries in SaslOutcome list encoding: " + count);
- }
-
- if (count > MaxListEntries)
- {
- throw new DecodeException("To many entries in SaslOutcome list encoding: " + count);
- }
+ result.Code = (SaslCode)state.Decoder.ReadUnsignedByte(stream, state);
- for (int index = 0; index < count; ++index)
+ if (count == 2)
{
- switch (index)
- {
- case 0:
- result.Code = (SaslCode)state.Decoder.ReadUnsignedByte(stream, state);
- break;
- case 1:
- result.AdditionalData = state.Decoder.ReadBinary(stream, state);
- break;
- }
+ result.AdditionalData = state.Decoder.ReadBinary(stream, state);
}
return result;
diff --git a/src/Proton/Codec/Decoders/Security/SaslResponseTypeDecoder.cs b/src/Proton/Codec/Decoders/Security/SaslResponseTypeDecoder.cs
index b6afef4..96b3fb0 100644
--- a/src/Proton/Codec/Decoders/Security/SaslResponseTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Security/SaslResponseTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Security;
namespace Apache.Qpid.Proton.Codec.Decoders.Security
{
- public sealed class SaslResponseTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class SaslResponseTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int RequiredListEntries = 1;
@@ -34,102 +34,24 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Security
public override Type DecodesType => typeof(SaslResponse);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslResponse[] result = new SaslResponse[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => RequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => RequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static SaslResponse ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslResponse ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
SaslResponse result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count != RequiredListEntries)
- {
- throw new DecodeException("SASL Response must contain at least one entry: " + count);
- }
- else
- {
- result.Response = state.Decoder.ReadBinary(buffer, state);
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- SaslResponse[] result = new SaslResponse[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ result.Response = state.Decoder.ReadBinary(buffer, state);
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static SaslResponse ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override SaslResponse ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
SaslResponse result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count != RequiredListEntries)
- {
- throw new DecodeException("SASL Response must contain at least one entry: " + count);
- }
- else
- {
- result.Response = state.Decoder.ReadBinary(stream, state);
- }
+ result.Response = state.Decoder.ReadBinary(stream, state);
return result;
}
diff --git a/src/Proton/Codec/Decoders/Transactions/CoordinatorTypeDecoder.cs b/src/Proton/Codec/Decoders/Transactions/CoordinatorTypeDecoder.cs
index d2ac1a4..9c4a48a 100644
--- a/src/Proton/Codec/Decoders/Transactions/CoordinatorTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transactions/CoordinatorTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transactions;
namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
{
- public sealed class CoordinatorTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class CoordinatorTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinRequiredListEntries = 0;
private static readonly int MaxRequiredListEntries = 1;
@@ -35,53 +35,15 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
public override Type DecodesType => typeof(Coordinator);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Coordinator[] result = new Coordinator[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => MinRequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => MaxRequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static Coordinator ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Coordinator ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Coordinator result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in Coordinator list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Coordinator list encoding: " + count);
- }
- else if (count == 1)
+ if (count == 1)
{
result.Capabilities = state.Decoder.ReadMultiple<Symbol>(buffer, state);
}
@@ -89,53 +51,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Coordinator[] result = new Coordinator[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Coordinator ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Coordinator ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Coordinator result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in Coordinator list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Coordinator list encoding: " + count);
- }
- else if (count == 1)
+ if (count == 1)
{
result.Capabilities = state.Decoder.ReadMultiple<Symbol>(stream, state);
}
diff --git a/src/Proton/Codec/Decoders/Transactions/DeclareTypeDecoder.cs b/src/Proton/Codec/Decoders/Transactions/DeclareTypeDecoder.cs
index a425ca1..71fc341 100644
--- a/src/Proton/Codec/Decoders/Transactions/DeclareTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transactions/DeclareTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transactions;
namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
{
- public sealed class DeclareTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeclareTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinRequiredListEntries = 0;
private static readonly int MaxRequiredListEntries = 1;
@@ -35,53 +35,15 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
public override Type DecodesType => typeof(Declare);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Declare[] result = new Declare[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => MinRequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => MaxRequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static Declare ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Declare ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Declare result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in Declare list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Declare list encoding: " + count);
- }
- else if (count == 1)
+ if (count == 1)
{
result.GlobalTxnId = (IGlobalTxnId)state.Decoder.ReadObject(buffer, state);
}
@@ -89,53 +51,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Declare[] result = new Declare[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Declare ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Declare ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Declare result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in Declare list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Declare list encoding: " + count);
- }
- else if (count == 1)
+ if (count == 1)
{
result.GlobalTxnId = (IGlobalTxnId)state.Decoder.ReadObject(stream, state);
}
diff --git a/src/Proton/Codec/Decoders/Transactions/DeclaredTypeDecoder.cs b/src/Proton/Codec/Decoders/Transactions/DeclaredTypeDecoder.cs
index fd2cfe5..9b6aabd 100644
--- a/src/Proton/Codec/Decoders/Transactions/DeclaredTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transactions/DeclaredTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transactions;
namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
{
- public sealed class DeclaredTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DeclaredTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinRequiredListEntries = 1;
private static readonly int MaxRequiredListEntries = 1;
@@ -35,110 +35,24 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
public override Type DecodesType => typeof(Declared);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Declared[] result = new Declared[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => MinRequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => MaxRequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static Declared ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Declared ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Declared result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("The txn-id field cannot be omitted");
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Declared list encoding: " + count);
- }
- else if (count == 1)
- {
- result.TxnId = state.Decoder.ReadBinary(buffer, state);
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Declared[] result = new Declared[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ result.TxnId = state.Decoder.ReadBinary(buffer, state);
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Declared ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Declared ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Declared result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("The txn-id field cannot be omitted");
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Declared list encoding: " + count);
- }
- else if (count == 1)
- {
- result.TxnId = state.Decoder.ReadBinary(stream, state);
- }
+ result.TxnId = state.Decoder.ReadBinary(stream, state);
return result;
}
diff --git a/src/Proton/Codec/Decoders/Transactions/DischargeTypeDecoder.cs b/src/Proton/Codec/Decoders/Transactions/DischargeTypeDecoder.cs
index 64b5b97..5df5df2 100644
--- a/src/Proton/Codec/Decoders/Transactions/DischargeTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transactions/DischargeTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transactions;
namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
{
- public sealed class DischargeTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DischargeTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinRequiredListEntries = 1;
private static readonly int MaxRequiredListEntries = 2;
@@ -35,127 +35,33 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
public override Type DecodesType => typeof(Discharge);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Discharge[] result = new Discharge[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => MinRequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => MaxRequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static Discharge ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Discharge ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Discharge result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in Discharge list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Discharge list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
- {
- switch (index)
- {
- case 0:
- result.TxnId = state.Decoder.ReadBinary(buffer, state);
- break;
- case 1:
- result.Fail = state.Decoder.ReadBoolean(buffer, state) ?? false;
- break;
- }
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+ result.TxnId = state.Decoder.ReadBinary(buffer, state);
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- Discharge[] result = new Discharge[count];
- for (int i = 0; i < count; ++i)
+ if (count == 2)
{
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
+ result.Fail = state.Decoder.ReadBoolean(buffer, state) ?? false;
}
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Discharge ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Discharge ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Discharge result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in Discharge list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in Discharge list encoding: " + count);
- }
+ result.TxnId = state.Decoder.ReadBinary(stream, state);
- for (int index = 0; index < count; ++index)
+ if (count == 2)
{
- switch (index)
- {
- case 0:
- result.TxnId = state.Decoder.ReadBinary(stream, state);
- break;
- case 1:
- result.Fail = state.Decoder.ReadBoolean(stream, state) ?? false;
- break;
- }
+ result.Fail = state.Decoder.ReadBoolean(stream, state) ?? false;
}
return result;
diff --git a/src/Proton/Codec/Decoders/Transactions/TransactionalStateTypeDecoder.cs b/src/Proton/Codec/Decoders/Transactions/TransactionalStateTypeDecoder.cs
index 7ca6f42..bb2f61a 100644
--- a/src/Proton/Codec/Decoders/Transactions/TransactionalStateTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transactions/TransactionalStateTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
{
- public sealed class TransactionalStateTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class TransactionalStateTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinRequiredListEntries = 1;
private static readonly int MaxRequiredListEntries = 2;
@@ -36,127 +36,33 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transactions
public override Type DecodesType => typeof(TransactionalState);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- TransactionalState[] result = new TransactionalState[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadType(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => MinRequiredListEntries;
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MaxListElements => MaxRequiredListEntries;
- decoder.SkipValue(buffer, state);
- }
-
- private static TransactionalState ReadType(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override TransactionalState ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
TransactionalState result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in TransactionalState list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in TransactionalState list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
- {
- switch (index)
- {
- case 0:
- result.TxnId = state.Decoder.ReadBinary(buffer, state);
- break;
- case 1:
- result.Outcome = state.Decoder.ReadObject<IOutcome>(buffer, state);
- break;
- }
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+ result.TxnId = state.Decoder.ReadBinary(buffer, state);
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- TransactionalState[] result = new TransactionalState[count];
- for (int i = 0; i < count; ++i)
+ if (count == 2)
{
- result[i] = ReadType(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
+ result.Outcome = state.Decoder.ReadObject<IOutcome>(buffer, state);
}
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static TransactionalState ReadType(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override TransactionalState ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
TransactionalState result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinRequiredListEntries)
- {
- throw new DecodeException("Not enough entries in TransactionalState list encoding: " + count);
- }
- else if (count > MaxRequiredListEntries)
- {
- throw new DecodeException("To many entries in TransactionalState list encoding: " + count);
- }
+ result.TxnId = state.Decoder.ReadBinary(stream, state);
- for (int index = 0; index < count; ++index)
+ if (count == 2)
{
- switch (index)
- {
- case 0:
- result.TxnId = state.Decoder.ReadBinary(stream, state);
- break;
- case 1:
- result.Outcome = state.Decoder.ReadObject<IOutcome>(stream, state);
- break;
- }
+ result.Outcome = state.Decoder.ReadObject<IOutcome>(stream, state);
}
return result;
diff --git a/src/Proton/Codec/Decoders/Transport/AttachTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/AttachTypeDecoder.cs
index 9258f5d..f4d52d7 100644
--- a/src/Proton/Codec/Decoders/Transport/AttachTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/AttachTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Messaging;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class AttachTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class AttachTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinAttachListEntries = 3;
private static readonly int MaxAttachListEntries = 14;
@@ -36,52 +36,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Attach);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadAttach(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Attach[] result = new Attach[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadAttach(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinAttachListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxAttachListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Attach ReadAttach(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Attach ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Attach result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinAttachListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxAttachListEntries)
- {
- throw new DecodeException("To many entries in Attach list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -153,52 +115,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadAttach(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Attach[] result = new Attach[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadAttach(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Attach ReadAttach(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Attach ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Attach result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinAttachListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxAttachListEntries)
- {
- throw new DecodeException("To many entries in Attach list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Transport/BeginTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/BeginTypeDecoder.cs
index e9e98e7..c19a642 100644
--- a/src/Proton/Codec/Decoders/Transport/BeginTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/BeginTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class BeginTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class BeginTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinBeginListEntries = 4;
private static readonly int MaxBeginListEntries = 8;
@@ -35,52 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Begin);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadBegin(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Begin[] result = new Begin[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadBegin(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinBeginListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxBeginListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Begin ReadBegin(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Begin ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Begin result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinBeginListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxBeginListEntries)
- {
- throw new DecodeException("To many entries in Begin list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -132,52 +94,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadBegin(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Begin[] result = new Begin[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadBegin(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Begin ReadBegin(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Begin ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Begin result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinBeginListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxBeginListEntries)
- {
- throw new DecodeException("To many entries in Begin list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Transport/CloseTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/CloseTypeDecoder.cs
index 672c957..23e9b23 100644
--- a/src/Proton/Codec/Decoders/Transport/CloseTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/CloseTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class CloseTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class CloseTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinCloseListEntries = 0;
private static readonly int MaxCloseListEntries = 1;
@@ -35,51 +35,15 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Close);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+ protected override int MinListElements => MinCloseListEntries;
- return ReadClose(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MaxListElements => MaxCloseListEntries;
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Close[] result = new Close[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadClose(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Close ReadClose(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Close ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Close result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinCloseListEntries)
- {
- throw new DecodeException("Not enough entries in Close list encoding: " + count);
- }
- else if (count > MaxCloseListEntries)
- {
- throw new DecodeException("To many entries in Close list encoding: " + count);
- }
- else if (count == 1)
+ if (count == 1)
{
result.Error = state.Decoder.ReadObject<ErrorCondition>(buffer, state);
}
@@ -87,51 +51,11 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadClose(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Close[] result = new Close[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadClose(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Close ReadClose(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Close ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Close result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinCloseListEntries)
- {
- throw new DecodeException("Not enough entries in Close list encoding: " + count);
- }
- else if (count > MaxCloseListEntries)
- {
- throw new DecodeException("To many entries in Close list encoding: " + count);
- }
- else if (count == 1)
+ if (count == 1)
{
result.Error = state.Decoder.ReadObject<ErrorCondition>(stream, state);
}
diff --git a/src/Proton/Codec/Decoders/Transport/DetachTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/DetachTypeDecoder.cs
index 86b9083..54e63bd 100644
--- a/src/Proton/Codec/Decoders/Transport/DetachTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/DetachTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class DetachTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DetachTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinDetachListEntries = 1;
private static readonly int MaxDetachListEntries = 3;
@@ -35,52 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Detach);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadDetach(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Detach[] result = new Detach[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadDetach(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinDetachListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxDetachListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Detach ReadDetach(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Detach ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Detach result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinDetachListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxDetachListEntries)
- {
- throw new DecodeException("To many entries in Detach list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -116,52 +78,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadDetach(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Detach[] result = new Detach[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadDetach(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Detach ReadDetach(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Detach ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Detach result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinDetachListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxDetachListEntries)
- {
- throw new DecodeException("To many entries in Detach list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Transport/DispositionTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/DispositionTypeDecoder.cs
index bba9d9f..cb8b5b7 100644
--- a/src/Proton/Codec/Decoders/Transport/DispositionTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/DispositionTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class DispositionTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class DispositionTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinDispositionListEntries = 2;
private static readonly int MaxDispositionListEntries = 6;
@@ -35,52 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Disposition);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadDisposition(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Disposition[] result = new Disposition[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadDisposition(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinDispositionListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxDispositionListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Disposition ReadDisposition(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Disposition ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Disposition result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinDispositionListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxDispositionListEntries)
- {
- throw new DecodeException("To many entries in Disposition list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -125,52 +87,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadDisposition(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Disposition[] result = new Disposition[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadDisposition(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Disposition ReadDisposition(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Disposition ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Disposition result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinDispositionListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxDispositionListEntries)
- {
- throw new DecodeException("To many entries in Disposition list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Transport/EndTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/EndTypeDecoder.cs
index c68eb52..23704d7 100644
--- a/src/Proton/Codec/Decoders/Transport/EndTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/EndTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class EndTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class EndTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinEndListEntries = 0;
private static readonly int MaxEndListEntries = 1;
@@ -35,119 +35,29 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(End);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadEnd(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- End[] result = new End[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadEnd(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinEndListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxEndListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static End ReadEnd(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override End ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
End result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinEndListEntries)
- {
- throw new DecodeException("Not enough entries in End list encoding: " + count);
- }
-
- if (count > MaxEndListEntries)
- {
- throw new DecodeException("To many entries in End list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
- {
- switch (index)
- {
- case 0:
- result.Error = state.Decoder.ReadObject<ErrorCondition>(buffer, state);
- break;
- }
- }
-
- return result;
- }
-
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadEnd(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- End[] result = new End[count];
- for (int i = 0; i < count; ++i)
+ if (count == 1)
{
- result[i] = ReadEnd(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
+ result.Error = state.Decoder.ReadObject<ErrorCondition>(buffer, state);
}
return result;
}
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static End ReadEnd(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override End ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
End result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinEndListEntries)
- {
- throw new DecodeException("Not enough entries in End list encoding: " + count);
- }
-
- if (count > MaxEndListEntries)
- {
- throw new DecodeException("To many entries in End list encoding: " + count);
- }
-
- for (int index = 0; index < count; ++index)
+ if (count == 1)
{
- switch (index)
- {
- case 0:
- result.Error = state.Decoder.ReadObject<ErrorCondition>(stream, state);
- break;
- }
+ result.Error = state.Decoder.ReadObject<ErrorCondition>(stream, state);
}
return result;
diff --git a/src/Proton/Codec/Decoders/Transport/ErrorConditionTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/ErrorConditionTypeDecoder.cs
index ee7a254..45729d7 100644
--- a/src/Proton/Codec/Decoders/Transport/ErrorConditionTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/ErrorConditionTypeDecoder.cs
@@ -25,7 +25,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class ErrorConditionTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class ErrorConditionTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinErrorConditionListEntries = 1;
private static readonly int MaxErrorConditionListEntries = 3;
@@ -36,50 +36,12 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(ErrorCondition);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadErrorCondition(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- ErrorCondition[] result = new ErrorCondition[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadErrorCondition(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
+ protected override int MinListElements => MinErrorConditionListEntries;
- decoder.SkipValue(buffer, state);
- }
+ protected override int MaxListElements => MaxErrorConditionListEntries;
- private static ErrorCondition ReadErrorCondition(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override ErrorCondition ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinErrorConditionListEntries)
- {
- throw new DecodeException("Not enough entries in ErrorCondition list encoding: " + count);
- }
-
- if (count > MaxErrorConditionListEntries)
- {
- throw new DecodeException("To many entries in ErrorCondition list encoding: " + count);
- }
-
Symbol condition = null;
string description = null;
IDictionary<Symbol, object> info = null;
@@ -103,50 +65,8 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return new ErrorCondition(condition, description, info);
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadErrorCondition(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- ErrorCondition[] result = new ErrorCondition[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadErrorCondition(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static ErrorCondition ReadErrorCondition(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override ErrorCondition ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinErrorConditionListEntries)
- {
- throw new DecodeException("Not enough entries in ErrorCondition list encoding: " + count);
- }
-
- if (count > MaxErrorConditionListEntries)
- {
- throw new DecodeException("To many entries in ErrorCondition list encoding: " + count);
- }
-
Symbol condition = null;
string description = null;
IDictionary<Symbol, object> info = null;
diff --git a/src/Proton/Codec/Decoders/Transport/FlowTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/FlowTypeDecoder.cs
index 830fd31..3ad3fbe 100644
--- a/src/Proton/Codec/Decoders/Transport/FlowTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/FlowTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class FlowTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class FlowTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinFlowListEntries = 4;
private static readonly int MaxFlowListEntries = 11;
@@ -35,52 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Flow);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadFlow(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Flow[] result = new Flow[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadFlow(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinFlowListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxFlowListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Flow ReadFlow(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Flow ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Flow result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinFlowListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxFlowListEntries)
- {
- throw new DecodeException("To many entries in Flow list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -141,52 +103,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadFlow(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Flow[] result = new Flow[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadFlow(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Flow ReadFlow(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Flow ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Flow result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinFlowListEntries)
- {
- throw new DecodeException(ErrorForMissingRequiredFields(count));
- }
-
- if (count > MaxFlowListEntries)
- {
- throw new DecodeException("To many entries in Flow list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Transport/OpenTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/OpenTypeDecoder.cs
index 7734a62..ad4fbb6 100644
--- a/src/Proton/Codec/Decoders/Transport/OpenTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/OpenTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class OpenTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class OpenTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinOpenListEntries = 1;
private static readonly int MaxOpenListEntries = 10;
@@ -35,52 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Open);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadOpen(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Open[] result = new Open[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadOpen(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinOpenListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxOpenListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Open ReadOpen(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Open ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Open result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinOpenListEntries)
- {
- throw new DecodeException("The container-id field cannot be omitted from the Open");
- }
-
- if (count > MaxOpenListEntries)
- {
- throw new DecodeException("To many entries in Open list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -136,52 +98,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadOpen(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Open[] result = new Open[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadOpen(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Open ReadOpen(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Open ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Open result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinOpenListEntries)
- {
- throw new DecodeException("The container-id field cannot be omitted from the Open");
- }
-
- if (count > MaxOpenListEntries)
- {
- throw new DecodeException("To many entries in Open list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/Transport/TransferTypeDecoder.cs b/src/Proton/Codec/Decoders/Transport/TransferTypeDecoder.cs
index 904d410..9cbada0 100644
--- a/src/Proton/Codec/Decoders/Transport/TransferTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/Transport/TransferTypeDecoder.cs
@@ -24,7 +24,7 @@ using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Codec.Decoders.Transport
{
- public sealed class TransferTypeDecoder : AbstractDescribedTypeDecoder
+ public sealed class TransferTypeDecoder : AbstractDescribedListTypeDecoder
{
private static readonly int MinTransferListEntries = 1;
private static readonly int MaxTransferListEntries = 11;
@@ -35,52 +35,14 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
public override Type DecodesType => typeof(Transfer);
- public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- return ReadTransfer(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- Transfer[] result = new Transfer[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadTransfer(buffer, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
+ protected override int MinListElements => MinTransferListEntries;
- return result;
- }
+ protected override int MaxListElements => MaxTransferListEntries;
- public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
- {
- ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(buffer, state);
- }
-
- private static Transfer ReadTransfer(IProtonBuffer buffer, IDecoderState state, IListTypeDecoder listDecoder)
+ protected override Transfer ReadType(int count, IProtonBuffer buffer, IDecoder decoder, IDecoderState state)
{
Transfer result = new();
- _ = listDecoder.ReadSize(buffer, state);
- int count = listDecoder.ReadCount(buffer, state);
-
- if (count < MinTransferListEntries)
- {
- throw new DecodeException("The handle field cannot be omitted from the Transfer");
- }
-
- if (count > MaxTransferListEntries)
- {
- throw new DecodeException("To many entries in Transfer list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
@@ -140,52 +102,10 @@ namespace Apache.Qpid.Proton.Codec.Decoders.Transport
return result;
}
- public override object ReadValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- return ReadTransfer(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- Transfer[] result = new Transfer[count];
- for (int i = 0; i < count; ++i)
- {
- result[i] = ReadTransfer(stream, state, CheckIsExpectedTypeAndCast<IListTypeDecoder>(decoder));
- }
-
- return result;
- }
-
- public override void SkipValue(Stream stream, IStreamDecoderState state)
- {
- IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
-
- CheckIsExpectedType<IListTypeDecoder>(decoder);
-
- decoder.SkipValue(stream, state);
- }
-
- private static Transfer ReadTransfer(Stream stream, IStreamDecoderState state, IListTypeDecoder listDecoder)
+ protected override Transfer ReadType(int count, Stream stream, IStreamDecoder decoder, IStreamDecoderState state)
{
Transfer result = new();
- _ = listDecoder.ReadSize(stream, state);
- int count = listDecoder.ReadCount(stream, state);
-
- if (count < MinTransferListEntries)
- {
- throw new DecodeException("The handle field cannot be omitted from the Transfer");
- }
-
- if (count > MaxTransferListEntries)
- {
- throw new DecodeException("To many entries in Transfer list encoding: " + count);
- }
-
for (int index = 0; index < count; ++index)
{
// Peek ahead and see if there is a null in the next slot, if so we don't call
diff --git a/src/Proton/Codec/Decoders/UnknownDescribedTypeDecoder.cs b/src/Proton/Codec/Decoders/UnknownDescribedTypeDecoder.cs
index 3804a97..89bf5d5 100644
--- a/src/Proton/Codec/Decoders/UnknownDescribedTypeDecoder.cs
+++ b/src/Proton/Codec/Decoders/UnknownDescribedTypeDecoder.cs
@@ -18,6 +18,7 @@
using System;
using System.IO;
using Apache.Qpid.Proton.Buffer;
+using Apache.Qpid.Proton.Codec.Decoders.Primitives;
using Apache.Qpid.Proton.Types;
namespace Apache.Qpid.Proton.Codec.Decoders
@@ -40,14 +41,42 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public override object ReadValue(IProtonBuffer buffer, IDecoderState state)
{
ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
- object described = decoder.ReadValue(buffer, state);
- return new UnknownDescribedType(descriptor, described);
+ if (decoder is not IPrimitiveTypeDecoder)
+ {
+ throw new DecodeException("The described value must be an AMQP primitive type.");
+ }
+
+ return new UnknownDescribedType(descriptor, decoder.ReadValue(buffer, state));
}
public override Array ReadArrayElements(IProtonBuffer buffer, IDecoderState state, int count)
{
ITypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(buffer, state);
+
+ if (decoder is IPrimitiveTypeDecoder primitiveDecoder)
+ {
+ if (primitiveDecoder.IsZeroWidth)
+ {
+ if (count > state.MaxZeroWidthArrayElements)
+ {
+ throw new DecodeException(
+ "Array element count " + count + " is specified to be greater than limit for " +
+ "zero sized encoded array types (" + state.MaxZeroWidthArrayElements + ")");
+ }
+ }
+ else if (count > buffer.ReadableBytes)
+ {
+ throw new DecodeException(
+ "Array encoded length " + count + " is specified to be greater than the amount " +
+ "of the remaining readable bytes (" + buffer.ReadableBytes + ")");
+ }
+ }
+ else
+ {
+ throw new DecodeException("The described value must be an AMQP primitive type.");
+ }
+
UnknownDescribedType[] result = new UnknownDescribedType[count];
for (int i = 0; i < count; ++i)
@@ -61,20 +90,57 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public override void SkipValue(IProtonBuffer buffer, IDecoderState state)
{
- state.Decoder.ReadNextTypeDecoder(buffer, state).SkipValue(buffer, state);
+ state.IncreaseDepth();
+
+ try
+ {
+ state.Decoder.ReadNextTypeDecoder(buffer, state).SkipValue(buffer, state);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
public override object ReadValue(Stream stream, IStreamDecoderState state)
{
IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
- object described = decoder.ReadValue(stream, state);
- return new UnknownDescribedType(descriptor, described);
+ if (decoder is not IPrimitiveTypeDecoder)
+ {
+ throw new DecodeException("The described value must be an AMQP primitive type.");
+ }
+
+ return new UnknownDescribedType(descriptor, decoder.ReadValue(stream, state));
}
public override Array ReadArrayElements(Stream stream, IStreamDecoderState state, int count)
{
IStreamTypeDecoder decoder = state.Decoder.ReadNextTypeDecoder(stream, state);
+
+ if (decoder is IPrimitiveTypeDecoder primitiveDecoder)
+ {
+ if (primitiveDecoder.IsZeroWidth)
+ {
+ if (count > state.MaxZeroWidthArrayElements)
+ {
+ throw new DecodeException(
+ "Array element count " + count + " is specified to be greater than limit for " +
+ "zero sized encoded array types (" + state.MaxZeroWidthArrayElements + ")");
+ }
+ }
+ else if (count > state.MaxArraySize)
+ {
+ throw new DecodeException(
+ "Array encoded length " + count + " is specified to be greater than the amount " +
+ "of the configured max array length (" + state.MaxArraySize + ")");
+ }
+ }
+ else
+ {
+ throw new DecodeException("The described value must be an AMQP primitive type.");
+ }
+
UnknownDescribedType[] result = new UnknownDescribedType[count];
for (int i = 0; i < count; ++i)
@@ -88,7 +154,16 @@ namespace Apache.Qpid.Proton.Codec.Decoders
public override void SkipValue(Stream stream, IStreamDecoderState state)
{
- state.Decoder.ReadNextTypeDecoder(stream, state).SkipValue(stream, state);
+ state.IncreaseDepth();
+
+ try
+ {
+ state.Decoder.ReadNextTypeDecoder(stream, state).SkipValue(stream, state);
+ }
+ finally
+ {
+ state.DecreaseDepth();
+ }
}
}
}
diff --git a/src/Proton/Codec/Encoders/AbstractDescribedMapTypeEncoder.cs b/src/Proton/Codec/Encoders/AbstractDescribedMapTypeEncoder.cs
index 5ed21e8..9031771 100644
--- a/src/Proton/Codec/Encoders/AbstractDescribedMapTypeEncoder.cs
+++ b/src/Proton/Codec/Encoders/AbstractDescribedMapTypeEncoder.cs
@@ -40,14 +40,6 @@ namespace Apache.Qpid.Proton.Codec.Encoders
return EncodingCodes.Map32;
}
- /// <summary>
- /// Returns false when the value to be encoded has no Map body and can be
- /// written as a Null body type instead of a Map type.
- /// </summary>
- /// <param name="value">The value that is encoded as a map type</param>
- /// <returns>if the map type needs a map body or can be null</returns>
- protected abstract bool HasMap(M value);
-
/// <summary>
/// Gets the number of elements that will result when this type is encoded
/// into an AMQP Map type.
@@ -78,27 +70,20 @@ namespace Apache.Qpid.Proton.Codec.Encoders
state.Encoder.WriteUnsignedLong(buffer, state, DescriptorCode);
- if (HasMap(value))
- {
- int count = GetMapEntries(value);
- EncodingCodes encodingCode = GetMapEncoding(value);
-
- buffer.EnsureWritable(sizeof(byte));
- buffer.WriteUnsignedByte(((byte)encodingCode));
-
- switch (encodingCode)
- {
- case EncodingCodes.Map8:
- WriteSmallType(buffer, state, value, count);
- break;
- case EncodingCodes.Map32:
- WriteLargeType(buffer, state, value, count);
- break;
- }
- }
- else
+ int count = GetMapEntries(value);
+ EncodingCodes encodingCode = GetMapEncoding(value);
+
+ buffer.EnsureWritable(sizeof(byte));
+ buffer.WriteUnsignedByte(((byte)encodingCode));
+
+ switch (encodingCode)
{
- state.Encoder.WriteNull(buffer, state);
+ case EncodingCodes.Map8:
+ WriteSmallType(buffer, state, value, count);
+ break;
+ case EncodingCodes.Map32:
+ WriteLargeType(buffer, state, value, count);
+ break;
}
}
diff --git a/src/Proton/Codec/Encoders/Messaging/ApplicationPropertiesTypeEncoder.cs b/src/Proton/Codec/Encoders/Messaging/ApplicationPropertiesTypeEncoder.cs
index 03f439a..e4a54ca 100644
--- a/src/Proton/Codec/Encoders/Messaging/ApplicationPropertiesTypeEncoder.cs
+++ b/src/Proton/Codec/Encoders/Messaging/ApplicationPropertiesTypeEncoder.cs
@@ -30,12 +30,12 @@ namespace Apache.Qpid.Proton.Codec.Encoders.Messaging
protected override int GetMapEntries(ApplicationProperties value)
{
- return value?.Value?.Count ?? 0;
- }
+ if (value == null || value.Value == null)
+ {
+ throw new EncodeException("ApplicationProperties must have an assigned Map payload");
+ }
- protected override bool HasMap(ApplicationProperties value)
- {
- return value?.Value != null;
+ return value.Value.Count;
}
protected override void WriteMapEntries(IProtonBuffer buffer, IEncoderState state, ApplicationProperties value)
diff --git a/src/Proton/Codec/Encoders/Messaging/DeliveryAnnotationsTypeEncoder.cs b/src/Proton/Codec/Encoders/Messaging/DeliveryAnnotationsTypeEncoder.cs
index f630c6b..585ec9a 100644
--- a/src/Proton/Codec/Encoders/Messaging/DeliveryAnnotationsTypeEncoder.cs
+++ b/src/Proton/Codec/Encoders/Messaging/DeliveryAnnotationsTypeEncoder.cs
@@ -30,12 +30,12 @@ namespace Apache.Qpid.Proton.Codec.Encoders.Messaging
protected override int GetMapEntries(DeliveryAnnotations value)
{
- return value?.Value?.Count ?? 0;
- }
+ if (value == null || value.Value == null)
+ {
+ throw new EncodeException("DeliveryAnnotations must have an assigned Map payload");
+ }
- protected override bool HasMap(DeliveryAnnotations value)
- {
- return value?.Value != null;
+ return value.Value.Count;
}
protected override void WriteMapEntries(IProtonBuffer buffer, IEncoderState state, DeliveryAnnotations value)
diff --git a/src/Proton/Codec/Encoders/Messaging/FooterTypeEncoder.cs b/src/Proton/Codec/Encoders/Messaging/FooterTypeEncoder.cs
index b784300..d5d8f5e 100644
--- a/src/Proton/Codec/Encoders/Messaging/FooterTypeEncoder.cs
+++ b/src/Proton/Codec/Encoders/Messaging/FooterTypeEncoder.cs
@@ -30,12 +30,12 @@ namespace Apache.Qpid.Proton.Codec.Encoders.Messaging
protected override int GetMapEntries(Footer value)
{
- return value?.Value?.Count ?? 0;
- }
+ if (value == null || value.Value == null)
+ {
+ throw new EncodeException("Footer must have an assigned Map payload");
+ }
- protected override bool HasMap(Footer value)
- {
- return value?.Value != null;
+ return value.Value.Count;
}
protected override void WriteMapEntries(IProtonBuffer buffer, IEncoderState state, Footer value)
diff --git a/src/Proton/Codec/Encoders/Messaging/MessageAnnotationsTypeEncoder.cs b/src/Proton/Codec/Encoders/Messaging/MessageAnnotationsTypeEncoder.cs
index a2ae4f3..e07fb2d 100644
--- a/src/Proton/Codec/Encoders/Messaging/MessageAnnotationsTypeEncoder.cs
+++ b/src/Proton/Codec/Encoders/Messaging/MessageAnnotationsTypeEncoder.cs
@@ -30,12 +30,12 @@ namespace Apache.Qpid.Proton.Codec.Encoders.Messaging
protected override int GetMapEntries(MessageAnnotations value)
{
- return value?.Value?.Count ?? 0;
- }
+ if (value == null || value.Value == null)
+ {
+ throw new EncodeException("MessageAnnotations must have an assigned Map payload");
+ }
- protected override bool HasMap(MessageAnnotations value)
- {
- return value?.Value != null;
+ return value.Value.Count;
}
protected override void WriteMapEntries(IProtonBuffer buffer, IEncoderState state, MessageAnnotations value)
diff --git a/src/Proton/Codec/Encoders/ProtonEncoder.cs b/src/Proton/Codec/Encoders/ProtonEncoder.cs
index b167ac0..72c0e70 100644
--- a/src/Proton/Codec/Encoders/ProtonEncoder.cs
+++ b/src/Proton/Codec/Encoders/ProtonEncoder.cs
@@ -26,6 +26,12 @@ namespace Apache.Qpid.Proton.Codec.Encoders
{
public sealed class ProtonEncoder : IEncoder
{
+ public enum EncoderMode
+ {
+ Sasl,
+ Default
+ }
+
// The encoders for primitives are fixed and cannot be altered by users who want
// to register custom encoders, these encoders are stateless so they can be safely
// made static to reduce overhead of creating and destroying this type.
@@ -91,6 +97,24 @@ namespace Apache.Qpid.Proton.Codec.Encoders
[deliveryTagEncoder.EncodesType] = deliveryTagEncoder
};
+ private readonly Func<string, Symbol> stringToSymbolSupplier;
+
+ public ProtonEncoder() : this(EncoderMode.Default)
+ {
+ }
+
+ public ProtonEncoder(EncoderMode mode)
+ {
+ if (mode == EncoderMode.Sasl)
+ {
+ stringToSymbolSupplier = Symbol.SaslLookup;
+ }
+ else
+ {
+ stringToSymbolSupplier = Symbol.Lookup;
+ }
+ }
+
public IEncoderState NewEncoderState()
{
return new ProtonEncoderState(this);
@@ -270,7 +294,7 @@ namespace Apache.Qpid.Proton.Codec.Encoders
}
else
{
- symbolEncoder.WriteType(buffer, state, Symbol.Lookup(value));
+ symbolEncoder.WriteType(buffer, state, stringToSymbolSupplier.Invoke(value));
}
}
diff --git a/src/Proton/Codec/Encoders/ProtonEncoderFactory.cs b/src/Proton/Codec/Encoders/ProtonEncoderFactory.cs
index 0067517..fc5e91d 100644
--- a/src/Proton/Codec/Encoders/ProtonEncoderFactory.cs
+++ b/src/Proton/Codec/Encoders/ProtonEncoderFactory.cs
@@ -29,7 +29,7 @@ namespace Apache.Qpid.Proton.Codec.Encoders
{
public static ProtonEncoder Create()
{
- ProtonEncoder encoder = new();
+ ProtonEncoder encoder = new(ProtonEncoder.EncoderMode.Default);
AddMessagingTypeEncoders(encoder);
AddTransactionTypeEncoders(encoder);
@@ -40,7 +40,7 @@ namespace Apache.Qpid.Proton.Codec.Encoders
public static ProtonEncoder CreateSasl()
{
- return AddSaslTypeEncoders(new ProtonEncoder());
+ return AddSaslTypeEncoders(new ProtonEncoder(ProtonEncoder.EncoderMode.Sasl));
}
private static ProtonEncoder AddMessagingTypeEncoders(ProtonEncoder encoder)
diff --git a/src/Proton/Codec/IDecoderState.cs b/src/Proton/Codec/IDecoderState.cs
index b29e516..97927be 100644
--- a/src/Proton/Codec/IDecoderState.cs
+++ b/src/Proton/Codec/IDecoderState.cs
@@ -15,6 +15,7 @@
* limitations under the License.
*/
+using System;
using Apache.Qpid.Proton.Buffer;
namespace Apache.Qpid.Proton.Codec
@@ -37,6 +38,51 @@ namespace Apache.Qpid.Proton.Codec
/// </summary>
IDecoder Decoder { get; }
+ /// <summary>
+ /// The configured maximum number of elements that can be decoded from an array
+ /// encoded with the zero width AMQP types (Null, UInt0. ULong0, List0, Boolean_False
+ /// and Boolean_True). These are uncommon encodings and can lead to small encodings
+ /// with large memory costs at decode which makes them discouraged for normal use.
+ /// A value of zero (the default) should be handled by the implementation as meaning
+ /// that only an array of zero width types with zero elements can be decoded.
+ /// </summary>
+ uint MaxZeroWidthArrayElements
+ {
+ get => 0;
+ set => throw new NotImplementedException("Default implementation cannot set an array width limit");
+ }
+
+ /// <summary>
+ /// Access the configured maximum depth that nested types such as Lists, Maps and Arrays
+ /// can have before a DecodeException is thrown to allow the decoder to error
+ /// in cases where the depth of encoding exceeds what the environment is thought to be
+ /// able to support.
+ /// </summary>
+ uint DepthLimit
+ {
+ get => uint.MaxValue;
+ set => throw new NotSupportedException("Depth limits not supported by default");
+ }
+
+ /// <summary>
+ /// During decode of AMQP types which can be comprised of a nesting of other AMQP types
+ /// the such as Lists, Maps and Arrays, the depth is increased to track the amount of
+ /// type nesting that comprises the type being decoded. Implementations can use this
+ /// value to impose limits on the depth of nested objects within complex types and throw
+ /// an DecodeException if that depth value is reached.
+ /// </summary>
+ void IncreaseDepth()
+ {
+ }
+
+ /// <summary>
+ /// Called once decoding of one level of a nested type completes to reduce to the previous
+ /// level before proceeding to the next element on the current level if any.
+ /// </summary>
+ void DecreaseDepth()
+ {
+ }
+
/// <summary>
/// Decodes an encoded UTF-8 string value from the given buffer. The number of bytes
/// that comprise the encoding is provided by the caller, the decoder should not read
diff --git a/src/Proton/Codec/IStreamDecoderState.cs b/src/Proton/Codec/IStreamDecoderState.cs
index 8c26368..2812cc2 100644
--- a/src/Proton/Codec/IStreamDecoderState.cs
+++ b/src/Proton/Codec/IStreamDecoderState.cs
@@ -15,6 +15,7 @@
* limitations under the License.
*/
+using System;
using System.IO;
namespace Apache.Qpid.Proton.Codec
@@ -26,6 +27,12 @@ namespace Apache.Qpid.Proton.Codec
/// </summary>
public interface IStreamDecoderState
{
+ /// <summary>
+ /// A default used to limit reads from a stream for types that encode a count or
+ /// size of encoded elements.
+ /// </summary>
+ protected static readonly uint DefaultMaxAllocationLimit = int.MaxValue - 8;
+
/// <summary>
/// Resets the decoder after a complete decode operation freeing any held
/// resources and preparing for a new decode operation.
@@ -47,5 +54,104 @@ namespace Apache.Qpid.Proton.Codec
/// <returns>A string value decoded from the UTF-8 bytes</returns>
string DecodeUtf8(Stream stream, int length);
+ /// <summary>
+ /// The configured maximum number of elements that can be decoded from an array
+ /// encoded with the zero width AMQP types (Null, UInt0. ULong0, List0, Boolean_False
+ /// and Boolean_True). These are uncommon encodings and can lead to small encodings
+ /// with large memory costs at decode which makes them discouraged for normal use.
+ /// It is recommended that for implementations that implement this limit configuration
+ /// the default be zero meaning zero width array encodings are disabled and will always
+ /// throw a NotImplementedException.
+ /// </summary>
+ uint MaxZeroWidthArrayElements
+ {
+ get => 0;
+ set => throw new NotImplementedException("Default implementation cannot set an array width limit");
+ }
+
+ /// <summary>
+ /// The configured maximum size of an encoded string that can be decoded before an error is thrown.
+ /// </summary>
+ uint MaxStringSize
+ {
+ get => DefaultMaxAllocationLimit;
+ set => throw new NotImplementedException("Default implementation cannot set an configurable size limit");
+ }
+
+ /// <summary>
+ /// The configured maximum size of an encoded array that can be decoded before an error is thrown.
+ /// </summary>
+ uint MaxArraySize
+ {
+ get => DefaultMaxAllocationLimit;
+ set => throw new NotImplementedException("Default implementation cannot set an configurable size limit");
+ }
+
+ /// <summary>
+ /// The configured maximum size of an encoded Binary that can be decoded before an error is thrown.
+ /// </summary>
+ uint MaxBinarySize
+ {
+ get => DefaultMaxAllocationLimit;
+ set => throw new NotImplementedException("Default implementation cannot set an configurable size limit");
+ }
+
+ /// <summary>
+ /// The configured maximum size of an encoded Symbol that can be decoded before an error is thrown.
+ /// </summary>
+ uint MaxSymbolSize
+ {
+ get => DefaultMaxAllocationLimit;
+ set => throw new NotImplementedException("Default implementation cannot set an configurable size limit");
+ }
+
+ /// <summary>
+ /// The configured maximum encoded list size that can be decoded before an error is thrown.
+ /// </summary>
+ uint MaxListSize
+ {
+ get => DefaultMaxAllocationLimit;
+ set => throw new NotImplementedException("Default implementation cannot set an configurable size limit");
+ }
+
+ /// <summary>
+ /// The configured maximum encoded map size that can be decoded before an error is thrown.
+ /// </summary>
+ uint MaxMapSize
+ {
+ get => DefaultMaxAllocationLimit;
+ set => throw new NotImplementedException("Default implementation cannot set an configurable size limit");
+ }
+
+ /// <summary>
+ /// Access the configured maximum depth that nested types such as Lists, Maps and Arrays
+ /// can have before a DecodeException is thrown to allow the decoder to error
+ /// in cases where the depth of encoding exceeds what the environment is thought to be
+ /// able to support.
+ /// </summary>
+ uint DepthLimit
+ {
+ get => uint.MaxValue;
+ set => throw new NotSupportedException("Depth limits not supported by default");
+ }
+
+ /// <summary>
+ /// During decode of AMQP types which can be comprised of a nesting of other AMQP types
+ /// the such as Lists, Maps and Arrays, the depth is increased to track the amount of
+ /// type nesting that comprises the type being decoded. Implementations can use this
+ /// value to impose limits on the depth of nested objects within complex types and throw
+ /// an DecodeException if that depth value is reached.
+ /// </summary>
+ void IncreaseDepth()
+ {
+ }
+
+ /// <summary>
+ /// Called once decoding of one level of a nested type completes to reduce to the previous
+ /// level before proceeding to the next element on the current level if any.
+ /// </summary>
+ void DecreaseDepth()
+ {
+ }
}
}
diff --git a/src/Proton/Engine/Exceptions/ProtocolViolationException.cs b/src/Proton/Engine/Exceptions/ProtocolViolationException.cs
index b4fb1f0..b4985a2 100644
--- a/src/Proton/Engine/Exceptions/ProtocolViolationException.cs
+++ b/src/Proton/Engine/Exceptions/ProtocolViolationException.cs
@@ -17,6 +17,7 @@
using System;
using Apache.Qpid.Proton.Types;
+using Apache.Qpid.Proton.Types.Transport;
namespace Apache.Qpid.Proton.Engine.Exceptions
{
@@ -100,7 +101,7 @@ namespace Apache.Qpid.Proton.Engine.Exceptions
/// <summary>
/// Returns the symbolic error condition that describes the violation error.
/// </summary>
- public Symbol ErrorCondition { get; internal set; }
+ public Symbol ErrorCondition { get; internal set; } = AmqpError.INTERNAL_ERROR;
}
}
\ No newline at end of file
diff --git a/src/Proton/Engine/IEngineConfiguration.cs b/src/Proton/Engine/IEngineConfiguration.cs
index 4b7d533..ce9f9ae 100644
--- a/src/Proton/Engine/IEngineConfiguration.cs
+++ b/src/Proton/Engine/IEngineConfiguration.cs
@@ -15,6 +15,7 @@
* limitations under the License.
*/
+using System;
using Apache.Qpid.Proton.Buffer;
namespace Apache.Qpid.Proton.Engine
@@ -42,5 +43,18 @@ namespace Apache.Qpid.Proton.Engine
/// </summary>
bool TraceFrames { get; set; }
+ /// <summary>
+ /// Sets the configured maximum number of Transfer frames that can make up a single completed
+ /// incoming delivery. If the delivery is not completed within this number of transfer frames the
+ /// engine may either close the associated link or the connection in its entirety. An engine
+ /// implementation may opt not to implement this feature in which case the value should be fixed
+ /// at zero and any assignment should be ignored. If the value is configured as zero then the
+ /// behavior should be to treat that as no limit was assigned.
+ /// </summary>
+ uint MaxTransfersPerDelivery
+ {
+ get => 0;
+ set => throw new NotSupportedException("Default configuration does not support assigning a max transfers value");
+ }
}
}
diff --git a/src/Proton/Engine/Implementation/ProtonConstants.cs b/src/Proton/Engine/Implementation/ProtonConstants.cs
index c051421..ac078cb 100644
--- a/src/Proton/Engine/Implementation/ProtonConstants.cs
+++ b/src/Proton/Engine/Implementation/ProtonConstants.cs
@@ -27,6 +27,12 @@ namespace Apache.Qpid.Proton.Engine.Implementation
/// </summary>
public static readonly uint MinMaxAmqpFrameSize = 512;
+ /// <summary>
+ /// The engine default for the maximum number of transfer performatives allowed
+ /// before a delivery must be completed or the engine will consider it an error.
+ /// </summary>
+ public static readonly uint DefaultMaxTransfersPerDelivery = ushort.MaxValue;
+
/**
* The default AMQP max frame size used by the engine and connection if none is set
* by the client or remote peer.
diff --git a/src/Proton/Engine/Implementation/ProtonEngineConfiguration.cs b/src/Proton/Engine/Implementation/ProtonEngineConfiguration.cs
index 610d6e9..3ad354a 100644
--- a/src/Proton/Engine/Implementation/ProtonEngineConfiguration.cs
+++ b/src/Proton/Engine/Implementation/ProtonEngineConfiguration.cs
@@ -78,6 +78,8 @@ namespace Apache.Qpid.Proton.Engine.Implementation
public uint InboundMaxFrameSize => effectiveMaxInboundFrameSize;
+ public uint MaxTransfersPerDelivery { get; set; } = ProtonConstants.DefaultMaxTransfersPerDelivery;
+
#region Internal Engine API
internal void RecomputeEffectiveFrameSizeLimits()
diff --git a/src/Proton/Engine/Implementation/ProtonFrameDecodingHandler.cs b/src/Proton/Engine/Implementation/ProtonFrameDecodingHandler.cs
index 1f49ba5..2929059 100644
--- a/src/Proton/Engine/Implementation/ProtonFrameDecodingHandler.cs
+++ b/src/Proton/Engine/Implementation/ProtonFrameDecodingHandler.cs
@@ -381,7 +381,15 @@ namespace Apache.Qpid.Proton.Engine.Implementation
if (frameBodySize > 0)
{
long startReadIndex = input.ReadOffset;
- val = handler.decoder.ReadObject(input, handler.decoderState);
+
+ try
+ {
+ val = handler.decoder.ReadObject(input, handler.decoderState);
+ }
+ finally
+ {
+ handler.decoderState.Reset();
+ }
// Copy the payload portion of the incoming bytes for now as the incoming may be
// from a wrapped pooled buffer and for now we have no way of retaining or otherwise
diff --git a/src/Proton/Engine/Implementation/ProtonIncomingDelivery.cs b/src/Proton/Engine/Implementation/ProtonIncomingDelivery.cs
index fb7c186..3f8f325 100644
--- a/src/Proton/Engine/Implementation/ProtonIncomingDelivery.cs
+++ b/src/Proton/Engine/Implementation/ProtonIncomingDelivery.cs
@@ -259,8 +259,6 @@ namespace Apache.Qpid.Proton.Engine.Implementation
internal bool IsFirstTransfer => transferCount <= 1;
- internal uint IncrementAndGetTransferCount() => ++transferCount;
-
internal uint DeliveryId => deliveryId;
internal ProtonIncomingDelivery Aborted()
@@ -307,19 +305,24 @@ namespace Apache.Qpid.Proton.Engine.Implementation
internal ProtonIncomingDelivery AppendTransferPayload(IProtonBuffer buffer)
{
- if (payload == null)
- {
- payload = buffer;
- }
- else if (aggregate != null)
- {
- aggregate.Append(buffer);
- }
- else
+ ++transferCount;
+
+ if (buffer != null)
{
- IProtonBuffer previous = payload;
+ if (payload == null)
+ {
+ payload = buffer;
+ }
+ else if (aggregate != null)
+ {
+ aggregate.Append(buffer);
+ }
+ else
+ {
+ IProtonBuffer previous = payload;
- payload = aggregate = IProtonCompositeBuffer.Compose(ProtonByteBufferAllocator.Instance, previous, buffer);
+ payload = aggregate = IProtonCompositeBuffer.Compose(ProtonByteBufferAllocator.Instance, previous, buffer);
+ }
}
return this;
diff --git a/src/Proton/Engine/Implementation/ProtonReceiver.cs b/src/Proton/Engine/Implementation/ProtonReceiver.cs
index e641172..c60ffbf 100644
--- a/src/Proton/Engine/Implementation/ProtonReceiver.cs
+++ b/src/Proton/Engine/Implementation/ProtonReceiver.cs
@@ -39,7 +39,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation
private Action<IIncomingDelivery> deliveryUpdatedEventHandler = null;
private readonly ProtonSessionIncomingWindow sessionWindow;
- private readonly LinkedSplayedDictionary<uint, ProtonIncomingDelivery> unsettled = new();
+ private readonly UnsettledDictionary<ProtonIncomingDelivery> unsettled = new(delivery => delivery.DeliveryId);
private uint? currentDeliveryId;
@@ -154,23 +154,22 @@ namespace Apache.Qpid.Proton.Engine.Implementation
IList<uint> toRemove = new List<uint>();
- foreach (KeyValuePair<uint, ProtonIncomingDelivery> delivery in unsettled)
+ unsettled.ForEach((deliveryId, delivery) =>
{
- if (filter.Invoke(delivery.Value))
+ if (filter.Invoke(delivery))
{
if (state != null)
{
- delivery.Value.LocalState(state);
+ delivery.LocalState(state);
}
if (settle)
{
- delivery.Value.LocallySettled();
- toRemove.Add(delivery.Key);
+ delivery.LocallySettled();
+ toRemove.Add(deliveryId);
}
-
- sessionWindow.ProcessDisposition(this, delivery.Value);
+ sessionWindow.ProcessDisposition(this, delivery);
}
- }
+ });
if (toRemove.Count > 0)
{
@@ -285,8 +284,6 @@ namespace Apache.Qpid.Proton.Engine.Implementation
currentDeliveryId = transfer.DeliveryId;
}
- delivery.IncrementAndGetTransferCount();
-
if (transfer.HasState())
{
delivery.RemoteState = transfer.DeliveryState;
@@ -297,12 +294,10 @@ namespace Apache.Qpid.Proton.Engine.Implementation
delivery.RemotelySettled();
}
- if (payload != null)
- {
- delivery.AppendTransferPayload(payload);
- }
+ delivery.AppendTransferPayload(payload);
bool done = transfer.Aborted || !transfer.More;
+
if (done)
{
CreditState.DecrementCredit();
@@ -318,6 +313,14 @@ namespace Apache.Qpid.Proton.Engine.Implementation
delivery.Completed();
}
}
+ else if (delivery.TransferCount >= engine.Configuration.MaxTransfersPerDelivery)
+ {
+ engine.EngineFailed(new ProtocolViolationException(LinkError.TRANSFER_LIMIT_EXCEEDED,
+ "Delivery not completed within configured max Transfers per delivery value: " +
+ engine.Configuration.MaxTransfersPerDelivery));
+
+ return;
+ }
if (transfer.Aborted)
{
diff --git a/src/Proton/Engine/Implementation/ProtonSessionIncomingWindow.cs b/src/Proton/Engine/Implementation/ProtonSessionIncomingWindow.cs
index d400153..42a7667 100644
--- a/src/Proton/Engine/Implementation/ProtonSessionIncomingWindow.cs
+++ b/src/Proton/Engine/Implementation/ProtonSessionIncomingWindow.cs
@@ -52,7 +52,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation
private uint maxFrameSize;
private uint incomingBytes;
- private readonly SplayedDictionary<uint, ProtonIncomingDelivery> unsettled = new();
+ private readonly UnsettledDictionary<ProtonIncomingDelivery> unsettled = new(delivery => delivery.DeliveryId);
public ProtonSessionIncomingWindow(ProtonSession session)
{
@@ -133,15 +133,22 @@ namespace Apache.Qpid.Proton.Engine.Implementation
/// <returns></returns>
internal Transfer HandleTransfer(IProtonLink link, Transfer transfer, IProtonBuffer payload)
{
- incomingBytes += payload != null ? (uint)payload.ReadableBytes : 0;
- incomingWindow--;
- nextIncomingId++;
+ if (incomingWindow-- == 0)
+ {
+ engine.EngineFailed(new ProtocolViolationException(SessionError.WINDOW_VIOLATION,
+ "Sender violated session incoming window limit: " + link.Handle));
+ }
+ else
+ {
+ incomingBytes += payload != null ? (uint)payload.ReadableBytes : 0;
+ nextIncomingId++;
- link.RemoteTransfer(transfer, payload, out ProtonIncomingDelivery delivery);
+ link.RemoteTransfer(transfer, payload, out ProtonIncomingDelivery delivery);
- if (!delivery.IsSettled && !delivery.IsRemotelySettled && delivery.IsFirstTransfer)
- {
- unsettled.Add(delivery.DeliveryId, delivery);
+ if (!delivery.IsSettled && !delivery.IsRemotelySettled && delivery.IsFirstTransfer)
+ {
+ unsettled.Add(delivery.DeliveryId, delivery);
+ }
}
return transfer;
@@ -159,7 +166,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation
if (disposition.HasLast() && disposition.Last != first)
{
- HandleRangedDisposition(disposition);
+ HandleRangedDisposition(disposition, unsettled);
}
else
{
@@ -177,27 +184,22 @@ namespace Apache.Qpid.Proton.Engine.Implementation
return disposition;
}
- private void HandleRangedDisposition(Disposition disposition)
+ private static void HandleRangedDisposition(Disposition disposition, UnsettledDictionary<ProtonIncomingDelivery> unsettled)
{
- uint first = disposition.First;
- uint last = disposition.Last;
- bool settled = disposition.Settled;
-
- uint index = first;
-
- do
+ if (disposition.Settled)
{
- if (unsettled.TryGetValue(index, out ProtonIncomingDelivery delivery))
+ unsettled.RemoveEach(disposition.First, disposition.Last, (delivery) =>
{
- if (settled)
- {
- unsettled.Remove(index);
- }
-
((IProtonLink)delivery.Link).RemoteDisposition(disposition, delivery);
- }
+ });
+ }
+ else
+ {
+ unsettled.ForEach(disposition.First, disposition.Last, (delivery) =>
+ {
+ ((IProtonLink)delivery.Link).RemoteDisposition(disposition, delivery);
+ });
}
- while (index++ != last);
}
internal uint UpdateIncomingWindow()
diff --git a/src/Proton/Engine/Implementation/ProtonSessionOutgoingWindow.cs b/src/Proton/Engine/Implementation/ProtonSessionOutgoingWindow.cs
index 2ad654b..23967c5 100644
--- a/src/Proton/Engine/Implementation/ProtonSessionOutgoingWindow.cs
+++ b/src/Proton/Engine/Implementation/ProtonSessionOutgoingWindow.cs
@@ -52,7 +52,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation
private uint remoteIncomingWindow;
private uint remoteNextIncomingId = 0;
- private readonly SplayedDictionary<uint, ProtonOutgoingDelivery> unsettled = new();
+ private readonly UnsettledDictionary<ProtonOutgoingDelivery> unsettled = new(delivery => delivery.DeliveryId);
public ProtonSessionOutgoingWindow(ProtonSession session)
{
@@ -233,7 +233,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation
if (disposition.HasLast() && disposition.Last != first)
{
- HandleRangedDisposition(disposition);
+ HandleRangedDisposition(disposition, unsettled);
}
else
{
@@ -250,25 +250,22 @@ namespace Apache.Qpid.Proton.Engine.Implementation
return disposition;
}
- private void HandleRangedDisposition(Disposition disposition)
+ private static void HandleRangedDisposition(Disposition disposition, UnsettledDictionary<ProtonOutgoingDelivery> unsettled)
{
- uint first = disposition.First;
- uint last = disposition.Last;
-
- uint index = first;
-
- do
+ if (disposition.Settled)
{
- if (unsettled.TryGetValue(index, out ProtonOutgoingDelivery delivery))
+ unsettled.RemoveEach(disposition.First, disposition.Last, (delivery) =>
{
- if (disposition.Settled)
- {
- unsettled.Remove(first);
- }
((IProtonLink)delivery.Link).RemoteDisposition(disposition, delivery);
- }
+ });
+ }
+ else
+ {
+ unsettled.ForEach(disposition.First, disposition.Last, (delivery) =>
+ {
+ ((IProtonLink)delivery.Link).RemoteDisposition(disposition, delivery);
+ });
}
- while (index++ != last);
}
#endregion
diff --git a/src/Proton/Engine/Implementation/ProtonTransactionManager.cs b/src/Proton/Engine/Implementation/ProtonTransactionManager.cs
index 317c771..8a6823e 100644
--- a/src/Proton/Engine/Implementation/ProtonTransactionManager.cs
+++ b/src/Proton/Engine/Implementation/ProtonTransactionManager.cs
@@ -335,7 +335,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation
{
IProtonBuffer payload = delivery.ReadAll();
- AmqpValue container = (AmqpValue)payloadDecoder.ReadObject(payload, payloadDecoder.CachedDecoderState);
+ AmqpValue container = payloadDecoder.ReadObject<AmqpValue>(payload, payloadDecoder.CachedDecoderState);
if (container.Value is Declare)
{
diff --git a/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslClientAuthenticator.cs b/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslClientAuthenticator.cs
index a314e1f..0e395f2 100644
--- a/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslClientAuthenticator.cs
+++ b/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslClientAuthenticator.cs
@@ -31,7 +31,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation.Sasl
{
public static readonly ProtonDefaultSaslClientAuthenticator Instance = new();
- private readonly Symbol ANONYMOUS = Symbol.Lookup("ANONYMOUS");
+ private readonly Symbol ANONYMOUS = Symbol.SaslLookup("ANONYMOUS");
public void HandleSaslChallenge(ISaslClientContext context, IProtonBuffer challenge)
{
@@ -40,7 +40,6 @@ namespace Apache.Qpid.Proton.Engine.Implementation.Sasl
public void HandleSaslMechanisms(ISaslClientContext context, Symbol[] mechanisms)
{
-
if (mechanisms != null && Array.Find(mechanisms, element => ANONYMOUS.Equals(element)) != null)
{
context.SendChosenMechanism(ANONYMOUS, null, ProtonByteBufferAllocator.Instance.Allocate(0, 0));
diff --git a/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslServerAuthenticator .cs b/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslServerAuthenticator .cs
index 9411516..c01d298 100644
--- a/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslServerAuthenticator .cs
+++ b/src/Proton/Engine/Implementation/Sasl/ProtonDefaultSaslServerAuthenticator .cs
@@ -33,7 +33,7 @@ namespace Apache.Qpid.Proton.Engine.Implementation.Sasl
{
public static readonly ProtonDefaultSaslServerAuthenticator Instance = new();
- private static readonly Symbol[] PLAIN = { Symbol.Lookup("PLAIN") };
+ private static readonly Symbol[] PLAIN = { Symbol.SaslLookup("PLAIN") };
public void HandleSaslHeader(ISaslServerContext context, AmqpHeader header)
{
diff --git a/src/Proton/Engine/Sasl/Client/AnonymousMechanism.cs b/src/Proton/Engine/Sasl/Client/AnonymousMechanism.cs
index 118d6d1..8fbc05b 100644
--- a/src/Proton/Engine/Sasl/Client/AnonymousMechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/AnonymousMechanism.cs
@@ -24,7 +24,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class AnonymousMechanism : AbstractMechanism
{
- public static readonly Symbol ANONYMOUS = Symbol.Lookup("ANONYMOUS");
+ public static readonly Symbol ANONYMOUS = Symbol.SaslLookup("ANONYMOUS");
public override Symbol Name => ANONYMOUS;
diff --git a/src/Proton/Engine/Sasl/Client/CramMD5Mechanism.cs b/src/Proton/Engine/Sasl/Client/CramMD5Mechanism.cs
index b8189f9..90d97a2 100644
--- a/src/Proton/Engine/Sasl/Client/CramMD5Mechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/CramMD5Mechanism.cs
@@ -27,7 +27,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class CramMD5Mechanism : AbstractMechanism
{
- public static readonly Symbol CRAM_MD5 = Symbol.Lookup("CRAM-MD5");
+ public static readonly Symbol CRAM_MD5 = Symbol.SaslLookup("CRAM-MD5");
private bool sentResponse;
diff --git a/src/Proton/Engine/Sasl/Client/ExternalMechanism.cs b/src/Proton/Engine/Sasl/Client/ExternalMechanism.cs
index 0cafa91..3884311 100644
--- a/src/Proton/Engine/Sasl/Client/ExternalMechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/ExternalMechanism.cs
@@ -24,7 +24,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class ExternalMechanism : AbstractMechanism
{
- public static readonly Symbol EXTERNAL = Symbol.Lookup("EXTERNAL");
+ public static readonly Symbol EXTERNAL = Symbol.SaslLookup("EXTERNAL");
public override Symbol Name => EXTERNAL;
diff --git a/src/Proton/Engine/Sasl/Client/IMechanism.cs b/src/Proton/Engine/Sasl/Client/IMechanism.cs
index 57f6561..9d1fd48 100644
--- a/src/Proton/Engine/Sasl/Client/IMechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/IMechanism.cs
@@ -81,7 +81,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// authentication error if that mechanism matches the highest priority value offered by the remote
/// peer.
/// </remarks>
- /// <returns>true if the mechanim should used without it having been requested</returns>
+ /// <returns>true if the mechanism should used without it having been requested</returns>
bool IsEnabledByDefault();
}
diff --git a/src/Proton/Engine/Sasl/Client/PlainMechanism.cs b/src/Proton/Engine/Sasl/Client/PlainMechanism.cs
index 2ee6d3c..a7f9eb8 100644
--- a/src/Proton/Engine/Sasl/Client/PlainMechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/PlainMechanism.cs
@@ -27,7 +27,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class PlainMechanism : AbstractMechanism
{
- public static readonly Symbol PLAIN = Symbol.Lookup("PLAIN");
+ public static readonly Symbol PLAIN = Symbol.SaslLookup("PLAIN");
public override Symbol Name => PLAIN;
diff --git a/src/Proton/Engine/Sasl/Client/SaslMechanismSelector.cs b/src/Proton/Engine/Sasl/Client/SaslMechanismSelector.cs
index b7622ad..96ed2ea 100644
--- a/src/Proton/Engine/Sasl/Client/SaslMechanismSelector.cs
+++ b/src/Proton/Engine/Sasl/Client/SaslMechanismSelector.cs
@@ -46,7 +46,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// <param name="allowed">An enumeration of SASL mechanism names</param>
public SaslMechanismSelector(IEnumerable<string> allowed)
{
- this.allowedMechanisms = allowed != null ? StringUtils.ToSymbolSet(allowed) : new HashSet<Symbol>();
+ this.allowedMechanisms = allowed != null ? StringUtils.ToSaslSymbolSet(allowed) : new HashSet<Symbol>();
}
/// <summary>
diff --git a/src/Proton/Engine/Sasl/Client/ScramSHA1Mechanism.cs b/src/Proton/Engine/Sasl/Client/ScramSHA1Mechanism.cs
index 7e50ff5..963095f 100644
--- a/src/Proton/Engine/Sasl/Client/ScramSHA1Mechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/ScramSHA1Mechanism.cs
@@ -26,7 +26,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class ScramSHA1Mechanism : AbstractScramSHAMechanism
{
- public static readonly Symbol SCRAM_SHA_1 = Symbol.Lookup("SCRAM-SHA-1");
+ public static readonly Symbol SCRAM_SHA_1 = Symbol.SaslLookup("SCRAM-SHA-1");
public ScramSHA1Mechanism() : this(Guid.NewGuid().ToString())
{
diff --git a/src/Proton/Engine/Sasl/Client/ScramSHA256Mechanism.cs b/src/Proton/Engine/Sasl/Client/ScramSHA256Mechanism.cs
index 129a622..53b35f4 100644
--- a/src/Proton/Engine/Sasl/Client/ScramSHA256Mechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/ScramSHA256Mechanism.cs
@@ -26,7 +26,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class ScramSHA256Mechanism : AbstractScramSHAMechanism
{
- public static readonly Symbol SCRAM_SHA_256 = Symbol.Lookup("SCRAM-SHA-256");
+ public static readonly Symbol SCRAM_SHA_256 = Symbol.SaslLookup("SCRAM-SHA-256");
public ScramSHA256Mechanism() : this(Guid.NewGuid().ToString())
{
diff --git a/src/Proton/Engine/Sasl/Client/ScramSHA512Mechanism.cs b/src/Proton/Engine/Sasl/Client/ScramSHA512Mechanism.cs
index f84c706..19f1fe5 100644
--- a/src/Proton/Engine/Sasl/Client/ScramSHA512Mechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/ScramSHA512Mechanism.cs
@@ -26,7 +26,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </summary>
public sealed class ScramSHA512Mechanism : AbstractScramSHAMechanism
{
- public static readonly Symbol SCRAM_SHA_512 = Symbol.Lookup("SCRAM-SHA-512");
+ public static readonly Symbol SCRAM_SHA_512 = Symbol.SaslLookup("SCRAM-SHA-512");
public ScramSHA512Mechanism() : this(Guid.NewGuid().ToString())
{
diff --git a/src/Proton/Engine/Sasl/Client/XOauth2Mechanism.cs b/src/Proton/Engine/Sasl/Client/XOauth2Mechanism.cs
index c94a691..8a1d432 100644
--- a/src/Proton/Engine/Sasl/Client/XOauth2Mechanism.cs
+++ b/src/Proton/Engine/Sasl/Client/XOauth2Mechanism.cs
@@ -31,7 +31,7 @@ namespace Apache.Qpid.Proton.Engine.Sasl.Client
/// </remarks>
public sealed class XOauth2Mechanism : AbstractMechanism
{
- public static readonly Symbol XOAUTH2 = Symbol.Lookup("XOAUTH2");
+ public static readonly Symbol XOAUTH2 = Symbol.SaslLookup("XOAUTH2");
private readonly Regex ACCESS_TOKEN_PATTERN = new("^[\\x20-\\x7F]+$", RegexOptions.Compiled);
diff --git a/src/Proton/Types/Security/SaslChallenge.cs b/src/Proton/Types/Security/SaslChallenge.cs
index 02df9f0..e8366e7 100644
--- a/src/Proton/Types/Security/SaslChallenge.cs
+++ b/src/Proton/Types/Security/SaslChallenge.cs
@@ -24,7 +24,7 @@ namespace Apache.Qpid.Proton.Types.Security
public sealed class SaslChallenge : ISaslPerformative
{
public static readonly ulong DescriptorCode = 0x0000000000000042UL;
- public static readonly Symbol DescriptorSymbol = Symbol.Lookup("amqp:sasl-challenge:list");
+ public static readonly Symbol DescriptorSymbol = Symbol.SaslLookup("amqp:sasl-challenge:list");
private IProtonBuffer challenge;
diff --git a/src/Proton/Types/Security/SaslInit.cs b/src/Proton/Types/Security/SaslInit.cs
index d8ac09b..0107deb 100644
--- a/src/Proton/Types/Security/SaslInit.cs
+++ b/src/Proton/Types/Security/SaslInit.cs
@@ -24,7 +24,7 @@ namespace Apache.Qpid.Proton.Types.Security
public class SaslInit : ISaslPerformative
{
public static readonly ulong DescriptorCode = 0x0000000000000041UL;
- public static readonly Symbol DescriptorSymbol = Symbol.Lookup("amqp:sasl-init:list");
+ public static readonly Symbol DescriptorSymbol = Symbol.SaslLookup("amqp:sasl-init:list");
private Symbol mechanism;
private IProtonBuffer initialResponse;
diff --git a/src/Proton/Types/Security/SaslMechanisms.cs b/src/Proton/Types/Security/SaslMechanisms.cs
index 5fa051d..dd51851 100644
--- a/src/Proton/Types/Security/SaslMechanisms.cs
+++ b/src/Proton/Types/Security/SaslMechanisms.cs
@@ -22,7 +22,7 @@ namespace Apache.Qpid.Proton.Types.Security
public class SaslMechanisms : ISaslPerformative
{
public static readonly ulong DescriptorCode = 0x0000000000000040UL;
- public static readonly Symbol DescriptorSymbol = Symbol.Lookup("amqp:sasl-mechanisms:list");
+ public static readonly Symbol DescriptorSymbol = Symbol.SaslLookup("amqp:sasl-mechanisms:list");
private Symbol[] mechanisms;
diff --git a/src/Proton/Types/Security/SaslOutcome.cs b/src/Proton/Types/Security/SaslOutcome.cs
index 97c29a7..029ea1f 100644
--- a/src/Proton/Types/Security/SaslOutcome.cs
+++ b/src/Proton/Types/Security/SaslOutcome.cs
@@ -23,7 +23,7 @@ namespace Apache.Qpid.Proton.Types.Security
public class SaslOutcome : ISaslPerformative
{
public static readonly ulong DescriptorCode = 0x0000000000000044UL;
- public static readonly Symbol DescriptorSymbol = Symbol.Lookup("amqp:sasl-outcome:list");
+ public static readonly Symbol DescriptorSymbol = Symbol.SaslLookup("amqp:sasl-outcome:list");
public SaslOutcome() { }
diff --git a/src/Proton/Types/Security/SaslResponse.cs b/src/Proton/Types/Security/SaslResponse.cs
index eaaf5ef..1b8894e 100644
--- a/src/Proton/Types/Security/SaslResponse.cs
+++ b/src/Proton/Types/Security/SaslResponse.cs
@@ -24,7 +24,7 @@ namespace Apache.Qpid.Proton.Types.Security
public class SaslResponse : ISaslPerformative
{
public static readonly ulong DescriptorCode = 0x0000000000000043UL;
- public static readonly Symbol DescriptorSymbol = Symbol.Lookup("amqp:sasl-response:list");
+ public static readonly Symbol DescriptorSymbol = Symbol.SaslLookup("amqp:sasl-response:list");
private IProtonBuffer response;
diff --git a/src/Proton/Types/Symbol.cs b/src/Proton/Types/Symbol.cs
index 9d3acc7..96e1cf9 100644
--- a/src/Proton/Types/Symbol.cs
+++ b/src/Proton/Types/Symbol.cs
@@ -24,32 +24,42 @@ namespace Apache.Qpid.Proton.Types
{
public sealed class Symbol : IEquatable<Symbol>, IComparable, IComparable<Symbol>
{
- private static readonly ConcurrentDictionary<IProtonBuffer, Symbol> buffersToSymbols = new();
- private static readonly ConcurrentDictionary<string, Symbol> stringsToSymbols = new();
+ // Prevents the Symbol cache from growing overly large if abused by creating overly
+ // large Symbols which would all be stored in the symbol cache. The SASL symbol cache
+ // is kept considerably smaller since there shouldn't be many entries used for the
+ // mechanisms and descriptor symbols as compared to the main application level cache.
- private static readonly Symbol EMPTY_SYMBOL = new();
+ private static readonly uint MaxSymbolCacheEntries = 8192;
+ private static readonly uint MaxCachedSymbolSize = 64;
- // Prevents the Symbol cache from growing overly large if abused by creating overly
- // large Symbols which would all be stored in the symbol cache.
- private static readonly uint MAX_CACHED_SYMBOL_SIZE = 64;
+ private static readonly uint MaxSaslSymbolCacheEntries = 128;
+ private static readonly uint MaxCachedSaslSymbolSize = 32;
+
+ private static readonly SymbolCache CachedSymbols = new SymbolCache(MaxSymbolCacheEntries, MaxCachedSymbolSize);
+ private static readonly SymbolCache CachedSaslSymbols = new SymbolCache(MaxSaslSymbolCacheEntries, MaxCachedSaslSymbolSize);
+
+ private static readonly Symbol EMPTY_SYMBOL = new();
// Lazy allocated based on calls to stringify the given Symbol
private string symbolString;
private readonly IProtonBuffer underlying;
private readonly int hashCode;
+ private readonly SymbolCache symbolCache;
private Symbol()
{
underlying = ProtonByteBufferAllocator.Instance.Allocate(0, 0);
symbolString = "";
hashCode = 32;
+ symbolCache = null;
}
- private Symbol(IProtonBuffer buffer)
+ private Symbol(IProtonBuffer buffer, SymbolCache cache)
{
underlying = buffer;
hashCode = buffer.GetHashCode();
+ symbolCache = cache;
}
/// <summary>
@@ -82,19 +92,7 @@ namespace Apache.Qpid.Proton.Types
}
else
{
- if (!stringsToSymbols.TryGetValue(value, out Symbol symbol))
- {
- symbol = Lookup(ProtonByteBufferAllocator.Instance.Wrap(Encoding.ASCII.GetBytes(value)));
-
- if (symbol.Length <= MAX_CACHED_SYMBOL_SIZE)
- {
- // Try and keep the Symbol instance consistent with the one that is stored
- // in the buffer to symbol dictionary.
- stringsToSymbols[value] = symbol;
- }
- }
-
- return symbol;
+ return CachedSymbols.Lookup(value);
}
}
@@ -131,29 +129,69 @@ namespace Apache.Qpid.Proton.Types
}
else
{
- if (!buffersToSymbols.TryGetValue(value, out Symbol symbol))
- {
- if (copyOnCreate)
- {
- long symbolSize = value.ReadableBytes;
- IProtonBuffer copy = ProtonByteBufferAllocator.Instance.Allocate(symbolSize, symbolSize);
- value.CopyInto(value.ReadOffset, copy, 0, symbolSize);
- copy.WriteOffset = symbolSize;
- value = copy;
- }
+ return CachedSymbols.Lookup(value, copyOnCreate);
+ }
+ }
- symbol = new Symbol(value);
+ /// <summary>
+ /// Lookup or create a singleton instance of the given Symbol that has the
+ /// matching name to the string value provided. This method looks in the
+ /// smaller SASL symbol cache for the matching Symbol value.
+ /// </summary>
+ /// <param name="value">the stringified symbol name</param>
+ /// <returns>A singleton instance of the named Symbol</returns>
+ public static Symbol SaslLookup(string value)
+ {
+ if (value == null)
+ {
+ return null;
+ }
+ else if (value.Length == 0)
+ {
+ return EMPTY_SYMBOL;
+ }
+ else
+ {
+ return CachedSaslSymbols.Lookup(value);
+ }
+ }
- if (symbol.Length <= MAX_CACHED_SYMBOL_SIZE)
- {
- if (!buffersToSymbols.TryAdd(value, symbol))
- {
- symbol = buffersToSymbols[value];
- }
- }
- }
+ /// <summary>
+ /// Lookup or create a singleton instance of the given Symbol that has the
+ /// matching byte contents as the given buffer, if none exists a new Symbol
+ /// is created using the given buffer which is not copied but used directly.
+ /// This method looks in the smaller SASL Symbol cache for the matching value.
+ /// </summary>
+ /// <param name="value">the stringified symbol name</param>
+ /// <returns>A singleton instance of the named Symbol</returns>
+ public static Symbol SaslLookup(IProtonBuffer value)
+ {
+ return SaslLookup(value, false);
+ }
- return symbol;
+ /// <summary>
+ /// Lookup or create a singleton instance of the given Symbol that has the
+ /// matching byte contents as the given buffer, if none exists a new Symbol
+ /// is created using the given buffer which is not copied if the provided
+ /// boolean option requests it. This method looks in the smaller SASL Symbol
+ /// cache for the matching value.
+ /// </summary>
+ /// <param name="value">the stringified symbol name</param>
+ /// <param name="copyOnCreate">should the given buffer be copied if a Symbol is created</param>
+ /// <returns>A singleton instance of the named Symbol</returns>
+ public static Symbol SaslLookup(IProtonBuffer value, bool copyOnCreate)
+ {
+ if (value == null)
+ {
+ return null;
+ }
+ else if (!value.IsReadable)
+ {
+ return EMPTY_SYMBOL;
+ }
+ else
+ {
+ return CachedSaslSymbols.Lookup(value, copyOnCreate);
}
}
@@ -180,14 +218,7 @@ namespace Apache.Qpid.Proton.Types
{
if (symbolString == null && underlying.IsReadable)
{
- symbolString = underlying.ToString(Encoding.ASCII);
- if (symbolString.Length <= MAX_CACHED_SYMBOL_SIZE)
- {
- if (!stringsToSymbols.TryAdd(symbolString, this))
- {
- symbolString = stringsToSymbols[symbolString].symbolString;
- }
- }
+ symbolCache.ToString(this);
}
return symbolString ?? "";
@@ -227,5 +258,117 @@ namespace Apache.Qpid.Proton.Types
{
return CompareTo(other as Symbol);
}
+
+ private static Symbol CreateSymbol(SymbolCache cache, IProtonBuffer buffer, bool copyOnCreate)
+ {
+ if (copyOnCreate)
+ {
+ long symbolSize = buffer.ReadableBytes;
+ IProtonBuffer copy = ProtonByteBufferAllocator.Instance.Allocate(symbolSize, symbolSize);
+ buffer.CopyInto(buffer.ReadOffset, copy, 0, symbolSize);
+ copy.WriteOffset = symbolSize;
+ buffer = copy;
+ }
+
+ return new Symbol(buffer, cache);
+ }
+
+ private sealed class SymbolCache
+ {
+ private readonly ConcurrentDictionary<IProtonBuffer, Symbol> buffersToSymbols = new();
+ private readonly ConcurrentDictionary<string, Symbol> stringsToSymbols = new();
+
+ private readonly uint maxCachedSymbols;
+ private readonly uint maxCachedSymbolSize;
+
+ public SymbolCache(uint maxCachedSymbols, uint maxCachedSymbolSize)
+ {
+ this.maxCachedSymbols = maxCachedSymbols;
+ this.maxCachedSymbolSize = maxCachedSymbolSize;
+ }
+
+ public Symbol Lookup(string value)
+ {
+ if (!stringsToSymbols.TryGetValue(value, out Symbol symbol))
+ {
+ symbol = Lookup(ProtonByteBufferAllocator.Instance.Wrap(Encoding.ASCII.GetBytes(value)));
+
+ if (symbol.symbolString == null)
+ {
+ // In case of a new Symbol object being created we want to ensure the String value
+ // is loaded now since we know what it is and future calls won't need to access the
+ // cache for no reason.
+ symbol.symbolString = value;
+ }
+
+ if (symbol.Length <= maxCachedSymbolSize && stringsToSymbols.Count < maxCachedSymbols)
+ {
+ // Try and keep the Symbol instance consistent with the one that is stored
+ // in the buffer to symbol dictionary.
+ stringsToSymbols[value] = symbol;
+ }
+ }
+
+ return symbol;
+ }
+
+ public Symbol Lookup(IProtonBuffer value)
+ {
+ return Lookup(value, false);
+ }
+
+ public Symbol Lookup(IProtonBuffer value, bool copyOnCreate)
+ {
+ bool canCache = value.ReadableBytes <= maxCachedSymbolSize;
+
+ if (canCache)
+ {
+ if (!buffersToSymbols.TryGetValue(value, out Symbol symbol))
+ {
+ // Lock to prevent the cache from possibly growing beyond the max cache size
+ // due to races on early fills from multiple connection threads.
+ lock (EMPTY_SYMBOL)
+ {
+ if (!buffersToSymbols.TryGetValue(value, out symbol))
+ {
+ symbol = CreateSymbol(this, value, copyOnCreate);
+
+ if (buffersToSymbols.Count < maxCachedSymbols)
+ {
+ if (!buffersToSymbols.TryAdd(value, symbol))
+ {
+ symbol = buffersToSymbols[value];
+ }
+ }
+ }
+ }
+ }
+
+ return symbol;
+ }
+ else
+ {
+ return CreateSymbol(this, value, copyOnCreate);
+ }
+ }
+
+ public string ToString(Symbol symbol)
+ {
+ if (symbol.symbolString == null && symbol.underlying.IsReadable)
+ {
+ symbol.symbolString = symbol.underlying.ToString(Encoding.ASCII);
+
+ if (symbol.symbolString.Length <= maxCachedSymbolSize && stringsToSymbols.Count < maxCachedSymbols)
+ {
+ if (!stringsToSymbols.TryAdd(symbol.symbolString, symbol))
+ {
+ symbol.symbolString = stringsToSymbols[symbol.symbolString].symbolString;
+ }
+ }
+ }
+
+ return symbol.symbolString ?? "";
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Proton/Types/UnknownDescribedType.cs b/src/Proton/Types/UnknownDescribedType.cs
index 5e58186..967847b 100644
--- a/src/Proton/Types/UnknownDescribedType.cs
+++ b/src/Proton/Types/UnknownDescribedType.cs
@@ -24,7 +24,7 @@ namespace Apache.Qpid.Proton.Types
/// </summary>
public sealed class UnknownDescribedType : IDescribedType
{
- internal UnknownDescribedType(object descriptor, object described)
+ public UnknownDescribedType(object descriptor, object described)
{
Descriptor = descriptor;
Described = described;
diff --git a/src/Proton/Utilities/StringUtils.cs b/src/Proton/Utilities/StringUtils.cs
index 842848a..5a6631f 100644
--- a/src/Proton/Utilities/StringUtils.cs
+++ b/src/Proton/Utilities/StringUtils.cs
@@ -53,6 +53,28 @@ namespace Apache.Qpid.Proton.Utilities
return result;
}
+ /// <summary>
+ /// Given an array of string objects, convert them to a matching array of
+ /// their Symbol equivalent values using the SASL Symbol cache as the source.
+ /// </summary>
+ /// <param name="stringArray"></param>
+ /// <returns>A new Symbol array with values that correspond to the input stings</returns>
+ public static Symbol[] ToSaslSymbolArray(string[] stringArray)
+ {
+ Symbol[] result = null;
+
+ if (stringArray != null)
+ {
+ result = new Symbol[stringArray.Length];
+ for (int i = 0; i < stringArray.Length; ++i)
+ {
+ result[i] = Symbol.SaslLookup(stringArray[i]);
+ }
+ }
+
+ return result;
+ }
+
/// <summary>
/// Given an array of Symbol objects, convert them to a matching array of
/// their string equivalent values.
@@ -100,6 +122,32 @@ namespace Apache.Qpid.Proton.Utilities
return result;
}
+ /// <summary>
+ /// Converts an enumeration of string values into a set of Symbol values.
+ /// Uses the SASL Symbol cache as the source of cached value.
+ /// </summary>
+ /// <param name="strings">an enumeration of string values</param>
+ /// <returns>a set of Symbol value that match the input strings</returns>
+ public static ISet<Symbol> ToSaslSymbolSet(in IEnumerable<string> strings)
+ {
+ ISet<Symbol> result;
+
+ if (strings != null)
+ {
+ result = new HashSet<Symbol>();
+ foreach (string value in strings)
+ {
+ result.Add(Symbol.SaslLookup(value));
+ }
+ }
+ else
+ {
+ result = null;
+ }
+
+ return result;
+ }
+
/// <summary>
/// Converts an enumeration of Symbol values into a set of string values.
/// </summary>
diff --git a/src/Proton/Utilities/UnsettledDictionary.cs b/src/Proton/Utilities/UnsettledDictionary.cs
... 14406 lines suppressed ...
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org
(qpid-proton-dotnet) 02/03: Update version for next release cycle
Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
tabish121 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton-dotnet.git
commit 57cecabed730eb60b706e204fac7aacd7f101fad
Author: Timothy Bish <ta...@gmail.com>
AuthorDate: Fri Jul 31 10:44:57 2026 -0400
Update version for next release cycle
---
VERSION.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/VERSION.txt b/VERSION.txt
index 51f7e73..9084fa2 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1 +1 @@
-1.0.1-SNAPSHOT
+1.1.0
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org