-
Notifications
You must be signed in to change notification settings - Fork 527
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add explicit protocol validation when reading RESP messages (#332)
* Add explicit protocol validation when reading RESP messages * Code cleanup * Add unit tests for RespReadUtils * Add length header fast-path for booleans * Improve readability of RespParsingExceptions * Add context to resp parsing integer overflow exceptions * Code cleanup * Misc. code cleanup for RESP read utils * Allow empty string values for INCRBY and SET commands. * Allow empty keys in RESP messages. * Code cleanup * Make RESP null parsing opt-in --------- Co-authored-by: Badrish Chandramouli <badrishc@microsoft.com>
- Loading branch information
Showing
16 changed files
with
1,004 additions
and
314 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT license. | ||
|
||
using System.Diagnostics.CodeAnalysis; | ||
using System.Text; | ||
|
||
namespace Garnet.common.Parsing | ||
{ | ||
/// <summary> | ||
/// Exception wrapper for RESP parsing errors. | ||
/// </summary> | ||
public class RespParsingException : GarnetException | ||
{ | ||
/// <summary> | ||
/// Construct a new RESP parsing exception with the given message. | ||
/// </summary> | ||
/// <param name="message">Message that described the exception that has occurred.</param> | ||
RespParsingException(string message) : base(message) | ||
{ | ||
// Nothing... | ||
} | ||
|
||
/// <summary> | ||
/// Throw an "Unexcepted Token" exception. | ||
/// </summary> | ||
/// <param name="token">The character that was unexpected.</param> | ||
[DoesNotReturn] | ||
public static void ThrowUnexpectedToken(byte token) | ||
{ | ||
var c = (char)token; | ||
var escaped = char.IsControl(c) ? $"\\x{token:x2}" : c.ToString(); | ||
Throw($"Unexpected character '{escaped}'."); | ||
} | ||
|
||
/// <summary> | ||
/// Throw an invalid string length exception. | ||
/// </summary> | ||
/// <param name="len">The invalid string length.</param> | ||
[DoesNotReturn] | ||
public static void ThrowInvalidStringLength(long len) | ||
{ | ||
Throw($"Invalid string length '{len}'."); | ||
} | ||
|
||
/// <summary> | ||
/// Throw an invalid length exception. | ||
/// </summary> | ||
/// <param name="len">The invalid length.</param> | ||
[DoesNotReturn] | ||
public static void ThrowInvalidLength(long len) | ||
{ | ||
Throw($"Invalid length '{len}'."); | ||
} | ||
|
||
/// <summary> | ||
/// Throw NaN (not a number) exception. | ||
/// </summary> | ||
/// <param name="buffer">Pointer to an ASCII-encoded byte buffer containing the string that could not be converted.</param> | ||
/// <param name="length">Length of the buffer.</param> | ||
[DoesNotReturn] | ||
public static unsafe void ThrowNotANumber(byte* buffer, int length) | ||
{ | ||
Throw($"Unable to parse number: {Encoding.ASCII.GetString(buffer, length)}"); | ||
} | ||
|
||
/// <summary> | ||
/// Throw a exception indicating that an integer overflow has occurred. | ||
/// </summary> | ||
/// <param name="buffer">Pointer to an ASCII-encoded byte buffer containing the string that caused the overflow.</param> | ||
/// <param name="length">Length of the buffer.</param> | ||
[DoesNotReturn] | ||
public static unsafe void ThrowIntegerOverflow(byte* buffer, int length) | ||
{ | ||
Throw($"Unable to parse integer. The given number is larger than allowed: {Encoding.ASCII.GetString(buffer, length)}"); | ||
} | ||
|
||
/// <summary> | ||
/// Throw helper that throws a RespParsingException. | ||
/// </summary> | ||
/// <param name="message">Exception message.</param> | ||
[DoesNotReturn] | ||
public static void Throw(string message) => | ||
throw new RespParsingException(message); | ||
} | ||
} |
Oops, something went wrong.