Commit de4dc017 authored by Georgios Bitzes's avatar Georgios Bitzes
Browse files

Escape non-printable characters in MONITOR

parent 463dba80
Pipeline #273328 failed with stages
in 29 minutes and 13 seconds
......@@ -22,6 +22,7 @@
************************************************************************/
#include "RedisRequest.hh"
#include "utils/StringUtils.hh"
using namespace quarkdb;
void RedisRequest::parseCommand() {
......@@ -40,3 +41,18 @@ void RedisRequest::parseCommand() {
command = it->second.first;
commandType = it->second.second;
}
std::string RedisRequest::toPrintableString() const {
std::stringstream ss;
for(auto it = begin(); it != end(); it++) {
if(it != begin()) ss << " ";
if(StringUtils::isPrintable(*it)) {
ss << "\"" << *it << "\"";
}
else {
ss << "\"" << StringUtils::escapeNonPrintable(*it) << "\"";
}
}
return ss.str();
}
......@@ -116,16 +116,7 @@ public:
}
void parseCommand();
std::string toString() const {
std::stringstream ss;
for(auto it = begin(); it != end(); it++) {
if(it != begin()) ss << " ";
ss << "\"" << *it << "\"";
}
return ss.str();
}
std::string toPrintableString() const;
private:
std::vector<std::string> contents;
RedisCommand command = RedisCommand::INVALID;
......
......@@ -36,7 +36,7 @@ void CommandMonitor::broadcast(const RedisRequest &received) {
auto it = monitors.begin();
while(it != monitors.end()) {
bool stillAlive = (*it)->appendIfAttached(Formatter::status(received.toString()));
bool stillAlive = (*it)->appendIfAttached(Formatter::status(received.toPrintableString()));
if(!stillAlive) {
it = monitors.erase(it);
......
......@@ -63,6 +63,34 @@ inline bool isPrefix(const std::string &prefix, const std::string &target) {
return isPrefix(prefix, target.c_str(), target.size());
}
inline bool isPrintable(const std::string &str) {
for(size_t i = 0; i < str.size(); i++) {
if(!isprint(str[i])) {
return false;
}
}
return true;
}
inline std::string escapeNonPrintable(const std::string &str) {
std::stringstream ss;
for(size_t i = 0; i < str.size(); i++) {
if(isprint(str[i])) {
ss << str[i];
}
else if(str[i] == '\0') {
ss << "\\x00";
}
else {
char buff[16];
snprintf(buff, 16, "\\x%02X", (unsigned char) str[i]);
ss << buff;
}
}
return ss.str();
}
} }
#endif
......@@ -698,10 +698,10 @@ TEST_F(Raft_e2e, monitor) {
RETRY_ASSERT_TRUE(reader.consume(5, response));
ASSERT_EQ(response, "+OK\r\n");
tunnel(leaderID)->exec("set", "abc", "aaaa");
tunnel(leaderID)->exec("set", "abc", "aaaa" "\xab" "bbb");
response.clear();
RETRY_ASSERT_TRUE(reader.consume(21, response));
ASSERT_EQ(response, "+\"set\" \"abc\" \"aaaa\"\r\n");
RETRY_ASSERT_TRUE(reader.consume(28, response));
ASSERT_EQ(response, "+\"set\" \"abc\" \"aaaa\\xABbbb\"\r\n");
tunnel(leaderID)->exec("get", "abc");
response.clear();
......
......@@ -86,7 +86,7 @@ TEST_F(Redis_Parser, T1) {
TEST_F(Redis_Parser, T2) {
std::string str("*2\r\n$3\r\nget\r\n$3\r\nabc\r\n");
RedisRequest valid = {"get", "abc"};
ASSERT_EQ(valid.toString(), "\"get\" \"abc\"");
ASSERT_EQ(valid.toPrintableString(), "\"get\" \"abc\"");
simulateMany(str, valid, 10);
str = "*3\r\n$3\r\nset\r\n$4\r\nabcd\r\n$5\r\n12345\r\n";
......
......@@ -227,6 +227,21 @@ TEST(StringUtils, isPrefix) {
ASSERT_TRUE(StringUtils::isPrefix("1234adfas", target));
}
TEST(StringUtils, EscapeNonPrintable) {
ASSERT_TRUE(StringUtils::isPrintable("abc"));
ASSERT_FALSE(StringUtils::isPrintable("abc\r\n"));
ASSERT_EQ(StringUtils::escapeNonPrintable("abc" "\xab" "abc"), "abc" "\\xAB" "abc");
ASSERT_EQ(StringUtils::escapeNonPrintable("abc"), "abc");
std::string binstr = "abc123";
binstr.push_back('\0');
binstr.push_back(0xff);
binstr += "aaa";
ASSERT_EQ(StringUtils::escapeNonPrintable(binstr), "abc123\\x00\\xFFaaa");
}
TEST(ScanParsing, BasicSanity) {
RedisRequest req { "0" };
ScanCommandArguments args = parseScanCommand(req.begin(), req.end());
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment