@@ -56,6 +56,59 @@ void abstract_protocol::set_keep_value(bool flag)
5656 m_keep_value = flag;
5757}
5858
59+ void abstract_protocol::capture_buffer_preview ()
60+ {
61+ if (!m_read_buf) {
62+ m_parse_error.raw_buffer_len = 0 ;
63+ m_parse_error.raw_buffer_preview [0 ] = ' \0 ' ;
64+ return ;
65+ }
66+
67+ m_parse_error.raw_buffer_len = evbuffer_get_length (m_read_buf);
68+
69+ if (m_parse_error.raw_buffer_len == 0 ) {
70+ m_parse_error.raw_buffer_preview [0 ] = ' \0 ' ;
71+ return ;
72+ }
73+
74+ // Get a preview of the buffer (up to 100 bytes to leave room for escaping)
75+ size_t preview_len = m_parse_error.raw_buffer_len ;
76+ if (preview_len > 100 ) preview_len = 100 ;
77+
78+ unsigned char *buf_data = evbuffer_pullup (m_read_buf, preview_len);
79+ if (!buf_data) {
80+ m_parse_error.raw_buffer_preview [0 ] = ' \0 ' ;
81+ return ;
82+ }
83+
84+ // Escape non-printable characters
85+ char *out = m_parse_error.raw_buffer_preview ;
86+ char *out_end = m_parse_error.raw_buffer_preview + sizeof (m_parse_error.raw_buffer_preview ) - 5 ;
87+
88+ for (size_t i = 0 ; i < preview_len && out < out_end; i++) {
89+ unsigned char c = buf_data[i];
90+ if (c >= 32 && c <= 126 && c != ' \\ ' ) {
91+ *out++ = c;
92+ } else if (c == ' \r ' ) {
93+ *out++ = ' \\ ' ; *out++ = ' r' ;
94+ } else if (c == ' \n ' ) {
95+ *out++ = ' \\ ' ; *out++ = ' n' ;
96+ } else if (c == ' \t ' ) {
97+ *out++ = ' \\ ' ; *out++ = ' t' ;
98+ } else if (c == ' \\ ' ) {
99+ *out++ = ' \\ ' ; *out++ = ' \\ ' ;
100+ } else {
101+ out += snprintf (out, 5 , " \\ x%02x" , c);
102+ }
103+ }
104+
105+ if (m_parse_error.raw_buffer_len > preview_len) {
106+ snprintf (out, 5 , " ..." );
107+ out += 3 ;
108+ }
109+ *out = ' \0 ' ;
110+ }
111+
59112// ///////////////////////////////////////////////////////////////////////
60113
61114protocol_response::protocol_response ()
@@ -174,6 +227,23 @@ class redis_protocol : public abstract_protocol {
174227 bool single_type (char c);
175228 bool response_ended ();
176229
230+ const char * response_state_name () const {
231+ switch (m_response_state) {
232+ case rs_initial: return " initial" ;
233+ case rs_read_bulk: return " read_bulk" ;
234+ case rs_read_line: return " read_line" ;
235+ case rs_end_bulk: return " end_bulk" ;
236+ default : return " unknown" ;
237+ }
238+ }
239+
240+ void set_parse_error (const char * msg) {
241+ m_parse_error.error_message = msg;
242+ m_parse_error.response_state_name = response_state_name ();
243+ m_parse_error.bytes_parsed = m_response_len;
244+ capture_buffer_preview ();
245+ }
246+
177247public:
178248 redis_protocol () : m_response_state(rs_initial), m_bulk_len(0 ), m_response_len(0 ), m_total_bulks_count(0 ), m_current_mbulk(NULL ), m_resp3(false ), m_attribute(false ) { }
179249 virtual redis_protocol* clone (void ) { return new redis_protocol (); }
@@ -625,6 +695,7 @@ int redis_protocol::parse_response(void)
625695 }
626696 } else {
627697 benchmark_debug_log (" unsupported response: '%s'.\n " , line);
698+ set_parse_error (" unsupported response type" );
628699 free (line);
629700 return -1 ;
630701 }
@@ -707,10 +778,12 @@ int redis_protocol::parse_response(void)
707778 }
708779 break ;
709780 default :
781+ set_parse_error (" invalid response state" );
710782 return -1 ;
711783 }
712784 }
713785
786+ set_parse_error (" unexpected end of parse loop" );
714787 return -1 ;
715788}
716789
@@ -785,6 +858,24 @@ class memcache_text_protocol : public abstract_protocol {
785858 response_state m_response_state;
786859 unsigned int m_value_len;
787860 size_t m_response_len;
861+
862+ const char * response_state_name () const {
863+ switch (m_response_state) {
864+ case rs_initial: return " initial" ;
865+ case rs_read_section: return " read_section" ;
866+ case rs_read_value: return " read_value" ;
867+ case rs_read_end: return " read_end" ;
868+ default : return " unknown" ;
869+ }
870+ }
871+
872+ void set_parse_error (const char * msg) {
873+ m_parse_error.error_message = msg;
874+ m_parse_error.response_state_name = response_state_name ();
875+ m_parse_error.bytes_parsed = m_response_len;
876+ capture_buffer_preview ();
877+ }
878+
788879public:
789880 memcache_text_protocol () : m_response_state(rs_initial), m_value_len(0 ), m_response_len(0 ) { }
790881 virtual memcache_text_protocol* clone (void ) { return new memcache_text_protocol (); }
@@ -927,6 +1018,7 @@ int memcache_text_protocol::parse_response(void)
9271018 int res = sscanf (line, " %s %s %u %u %u" , prefix, key, &flags, &m_value_len, &cas);
9281019 if (res < 4 || res > 5 ) {
9291020 benchmark_debug_log (" unexpected VALUE response: %s\n " , line);
1021+ set_parse_error (" unexpected VALUE response format" );
9301022 if (m_last_response.get_status () != line)
9311023 free (line);
9321024 return -1 ;
@@ -943,6 +1035,7 @@ int memcache_text_protocol::parse_response(void)
9431035 } else {
9441036 m_last_response.set_error ();
9451037 benchmark_debug_log (" unknown response: %s\n " , line);
1038+ set_parse_error (" unknown response type" );
9461039 return -1 ;
9471040 }
9481041 break ;
@@ -978,10 +1071,12 @@ int memcache_text_protocol::parse_response(void)
9781071
9791072 default :
9801073 benchmark_debug_log (" unknown response state %d.\n " , m_response_state);
1074+ set_parse_error (" invalid response state" );
9811075 return -1 ;
9821076 }
9831077 }
9841078
1079+ set_parse_error (" unexpected end of parse loop" );
9851080 return -1 ;
9861081}
9871082
@@ -1007,6 +1102,22 @@ class memcache_binary_protocol : public abstract_protocol {
10071102 size_t m_response_len;
10081103
10091104 const char * status_text (void );
1105+
1106+ const char * response_state_name () const {
1107+ switch (m_response_state) {
1108+ case rs_initial: return " initial" ;
1109+ case rs_read_body: return " read_body" ;
1110+ default : return " unknown" ;
1111+ }
1112+ }
1113+
1114+ void set_parse_error (const char * msg) {
1115+ m_parse_error.error_message = msg;
1116+ m_parse_error.response_state_name = response_state_name ();
1117+ m_parse_error.bytes_parsed = m_response_len;
1118+ capture_buffer_preview ();
1119+ }
1120+
10101121public:
10111122 memcache_binary_protocol () : m_response_state(rs_initial), m_response_len(0 ) { }
10121123 virtual memcache_binary_protocol* clone (void ) { return new memcache_binary_protocol (); }
@@ -1190,6 +1301,7 @@ int memcache_binary_protocol::parse_response(void)
11901301
11911302 if (m_response_hdr.message .header .response .magic != PROTOCOL_BINARY_RES) {
11921303 benchmark_error_log (" error: invalid memcache response header magic.\n " );
1304+ set_parse_error (" invalid memcache response header magic" );
11931305 return -1 ;
11941306 }
11951307
@@ -1253,10 +1365,12 @@ int memcache_binary_protocol::parse_response(void)
12531365 break ;
12541366 default :
12551367 benchmark_debug_log (" unknown response state.\n " );
1368+ set_parse_error (" invalid response state" );
12561369 return -1 ;
12571370 }
12581371 }
12591372
1373+ set_parse_error (" unexpected end of parse loop" );
12601374 return -1 ;
12611375}
12621376
0 commit comments