@@ -56,12 +56,10 @@ struct MemcachedResponseDecoder: NIOSingleStepByteToMessageDecoder {
5656 /// This error is thrown when EOF is encountered but there are still
5757 /// readable bytes in the buffer, which can indicate a bad message.
5858 case unexpectedEOF
59-
6059 /// This error is thrown when EOF is encountered but there is still an expected next step
6160 /// in the decoder's state machine. This error suggests that the message ended prematurely,
6261 /// possibly indicating a bad message.
6362 case unexpectedNextStep( NextStep )
64-
6563 /// This error is thrown when an unexpected character is encountered in the buffer
6664 /// during the decoding process.
6765 case unexpectedCharacter( UInt8 )
@@ -72,11 +70,12 @@ struct MemcachedResponseDecoder: NIOSingleStepByteToMessageDecoder {
7270 enum NextStep : Hashable {
7371 /// The initial step.
7472 case returnCode
75- /// Decode the data length, flags or check if we are the end
76- case dataLengthOrFlag( MemcachedResponse . ReturnCode )
77- /// Decode the next flag
78- case decodeNextFlag( MemcachedResponse . ReturnCode , UInt64 ? )
79- // TODO: Add a next step for decoding the response data if the return code is VA
73+ /// Decode the data length
74+ case dataLength( MemcachedResponse . ReturnCode )
75+ /// Decode the flags
76+ case decodeFlag( MemcachedResponse . ReturnCode , UInt64 ? )
77+ /// Decode the Value
78+ case decodeValue( MemcachedResponse . ReturnCode , UInt64 , MemcachedFlags )
8079 }
8180
8281 /// The action that the decoder will take in response to the current state of the ByteBuffer and the `NextStep`.
@@ -108,47 +107,84 @@ struct MemcachedResponseDecoder: NIOSingleStepByteToMessageDecoder {
108107 }
109108
110109 mutating func next( buffer: inout ByteBuffer ) throws -> NextDecodeAction {
110+ // Check if the buffer contains "\r\n"
111+ let bytesView = buffer. readableBytesView
112+ guard let crIndex = bytesView. firstIndex ( of: UInt8 . carriageReturn) , bytesView. index ( after: crIndex) < bytesView. endIndex,
113+ bytesView [ bytesView. index ( after: crIndex) ] == UInt8 . newline else {
114+ return . waitForMoreBytes
115+ }
111116 switch self . nextStep {
112117 case . returnCode:
113118 guard let bytes = buffer. readInteger ( as: UInt16 . self) else {
114119 return . waitForMoreBytes
115120 }
116121
117122 let returnCode = MemcachedResponse . ReturnCode ( bytes)
118- self . nextStep = . dataLengthOrFlag ( returnCode)
123+ self . nextStep = . dataLength ( returnCode)
119124 return . continueDecodeLoop
120125
121- case . dataLengthOrFlag ( let returnCode) :
126+ case . dataLength ( let returnCode) :
122127 if returnCode == . VA {
123- // TODO: Implement decoding of data length
124- fatalError ( " Decoding for VA return code is not yet implemented " )
128+ // Check if we have at least one whitespace in the buffer.
129+ guard buffer. readableBytesView. contains ( UInt8 . whitespace) else {
130+ return . waitForMoreBytes
131+ }
132+
133+ if let currentByte = buffer. getInteger ( at: buffer. readerIndex, as: UInt8 . self) , currentByte == UInt8 . whitespace {
134+ buffer. moveReaderIndex ( forwardBy: 1 )
135+ }
136+
137+ guard let dataLength = buffer. readIntegerFromASCII ( ) else {
138+ throw MemcachedDecoderError . unexpectedCharacter ( buffer. readableBytesView [ buffer. readerIndex] )
139+ }
140+
141+ self . nextStep = . decodeFlag( returnCode, dataLength)
142+ return . continueDecodeLoop
143+ } else {
144+ self . nextStep = . decodeFlag( returnCode, nil )
145+ return . continueDecodeLoop
125146 }
126147
127- guard let nextByte = buffer. readInteger ( as: UInt8 . self) else {
128- return . waitForMoreBytes
148+ case . decodeFlag( let returnCode, let dataLength) :
149+ if let nextByte = buffer. getInteger ( at: buffer. readerIndex, as: UInt8 . self) , nextByte == UInt8 . newline {
150+ self . nextStep = . decodeValue( returnCode, dataLength!, MemcachedFlags ( ) )
151+ buffer. moveReaderIndex ( forwardBy: 1 )
152+ return . continueDecodeLoop
153+ }
154+
155+ if let currentByte = buffer. getInteger ( at: buffer. readerIndex, as: UInt8 . self) , currentByte == UInt8 . whitespace {
156+ buffer. moveReaderIndex ( forwardBy: 1 )
129157 }
130158
131- if nextByte == UInt8 . whitespace {
132- self . nextStep = . decodeNextFlag( returnCode, nil )
159+ let flags = buffer. readMemcachedFlags ( )
160+
161+ if returnCode == . VA {
162+ self . nextStep = . decodeValue( returnCode, dataLength!, flags)
133163 return . continueDecodeLoop
134- } else if nextByte == UInt8 . carriageReturn {
135- guard let nextNextByte = buffer. readInteger ( as: UInt8 . self) , nextNextByte == UInt8 . newline else {
136- return . waitForMoreBytes
137- }
138- let response = MemcachedResponse ( returnCode: returnCode, dataLength: nil )
164+ } else {
165+ let response = MemcachedResponse ( returnCode: returnCode, dataLength: dataLength, flags: flags, value: nil )
139166 self . nextStep = . returnCode
140167 return . returnDecodedResponse( response)
141- } else {
142- throw MemcachedDecoderError . unexpectedCharacter ( nextByte)
143168 }
144169
145- case . decodeNextFlag( let returnCode, let dataLength) :
146- while let nextByte = buffer. readInteger ( as: UInt8 . self) , nextByte != UInt8 . whitespace {
147- // for now consume the byte and do nothing with it.
148- // TODO: Implement decoding of flags
170+ case . decodeValue( let returnCode, let dataLength, let flags) :
171+ guard buffer. readableBytes >= dataLength + 2 else {
172+ return . waitForMoreBytes
173+ }
174+
175+ guard let data = buffer. readSlice ( length: Int ( dataLength) ) else {
176+ throw MemcachedDecoderError . unexpectedEOF
177+ }
178+
179+ guard buffer. readableBytes >= 2 ,
180+ let nextByte = buffer. readInteger ( as: UInt8 . self) ,
181+ nextByte == UInt8 . carriageReturn,
182+ let nextNextByte = buffer. readInteger ( as: UInt8 . self) ,
183+ nextNextByte == UInt8 . newline else {
184+ preconditionFailure ( " Expected to find CRLF at end of response " )
149185 }
150186
151- let response = MemcachedResponse ( returnCode: returnCode, dataLength: dataLength)
187+ let response = MemcachedResponse ( returnCode: returnCode, dataLength: dataLength, flags : flags , value : data )
152188 self . nextStep = . returnCode
153189 return . returnDecodedResponse( response)
154190 }
0 commit comments