Blink DB Documentation v1.0.0
Blink DB Documentation
Loading...
Searching...
No Matches
resp_decoder.hpp
Go to the documentation of this file.
1
12#ifndef RESP_DECODER
13#define RESP_DECODER
14
15#include <string>
16
17#define CRLF "\r\n"
18
25 SET,
26 GET,
27 DEL,
28 UNKNOWN
29};
30
37class Resp {
38public:
39 Operation operation;
40 std::string key;
41 std::string value;
42 bool success;
43 std::string error;
44 Resp() : operation(UNKNOWN), success(false) {}
45};
46
55public:
62 static Resp decode(const char *buffer, size_t length) {
63 Resp resp;
64
65 std::string_view input(buffer, length);
66
67 if (input.empty() || input[0] != '*') {
68 resp.error = "Invalid request: missing array marker";
69 return resp;
70 }
71
72 size_t pos = input.find(CRLF);
73 if (pos == std::string_view::npos) {
74 resp.error = "Invalid request: malformed array header";
75 return resp;
76 }
77
78 int num_args;
79 try {
80 num_args = std::stoi(std::string(input.substr(1, pos - 1)));
81 } catch (std::exception &) {
82 resp.error = "Invalid request: invalid argument count";
83 return resp;
84 }
85
86 if (num_args < 2 || num_args > 3) {
87 resp.error = "Invalid request: unexpected argument count";
88 return resp;
89 }
90
91 input.remove_prefix(pos + 2);
92 if (!parseOperation(input, resp)) {
93 return resp;
94 }
95
96 if (!parseKey(input, resp)) {
97 return resp;
98 }
99
100 if (resp.operation == SET) {
101 if (num_args != 3) {
102 resp.error = "Invalid request: SET requires a value";
103 return resp;
104 }
105
106 if (!parseValue(input, resp)) {
107 return resp;
108 }
109 } else if (num_args > 2) {
110 resp.error = "Invalid request: too many arguments";
111 return resp;
112 }
113
114 if (!input.empty() && input != CRLF) {
115 resp.error = "Invalid request: extra data after command";
116 return resp;
117 }
118
119 resp.success = true;
120 return resp;
121 }
122
128 static Resp decode(const char *buffer) {
129 return decode(buffer, std::strlen(buffer));
130 }
131
132private:
139 static bool parseOperation(std::string_view &input, Resp &resp) {
140 if (input.empty() || input[0] != '$') {
141 resp.error = "Invalid request: missing operation string marker";
142 return false;
143 }
144
145 size_t pos = input.find(CRLF);
146 if (pos == std::string_view::npos) {
147 resp.error = "Invalid request: malformed operation length";
148 return false;
149 }
150
151 int op_len;
152 try {
153 op_len = std::stoi(std::string(input.substr(1, pos - 1)));
154 } catch (std::exception &) {
155 resp.error = "Invalid request: invalid operation length";
156 return false;
157 }
158
159 input.remove_prefix(pos + 2);
160 if (input.size() < static_cast<size_t>(op_len) + 2) {
161 resp.error = "Invalid request: truncated operation";
162 return false;
163 }
164
165 std::string_view op = input.substr(0, op_len);
166
167 if (op == "DEL") {
168 resp.operation = DEL;
169 } else if (op == "GET") {
170 resp.operation = GET;
171 } else if (op == "SET") {
172 resp.operation = SET;
173 } else {
174 resp.error = "Invalid request: unknown operation";
175 return false;
176 }
177
178 input.remove_prefix(op_len + 2);
179 return true;
180 }
181
188 static bool parseKey(std::string_view &input, Resp &resp) {
189 if (input.empty() || input[0] != '$') {
190 resp.error = "Invalid request: missing key string marker";
191 return false;
192 }
193
194 size_t pos = input.find(CRLF);
195 if (pos == std::string_view::npos) {
196 resp.error = "Invalid request: malformed key length";
197 return false;
198 }
199
200 int key_len;
201 try {
202 key_len = std::stoi(std::string(input.substr(1, pos - 1)));
203 } catch (std::exception &) {
204 resp.error = "Invalid request: invalid key length";
205 return false;
206 }
207
208 input.remove_prefix(pos + 2);
209
210 if (input.size() < static_cast<size_t>(key_len) + 2) {
211 resp.error = "Invalid request: truncated key";
212 return false;
213 }
214
215 resp.key = std::string(input.substr(0, key_len));
216 input.remove_prefix(key_len + 2);
217 return true;
218 }
219
226 static bool parseValue(std::string_view &input, Resp &resp) {
227 if (input.empty() || input[0] != '$') {
228 resp.error = "Invalid request: missing value string marker";
229 return false;
230 }
231
232 size_t pos = input.find(CRLF);
233 if (pos == std::string_view::npos) {
234 resp.error = "Invalid request: malformed value length";
235 return false;
236 }
237
238 int value_len;
239 try {
240 value_len = std::stoi(std::string(input.substr(1, pos - 1)));
241 } catch (std::exception &) {
242 resp.error = "Invalid request: invalid value length";
243 return false;
244 }
245
246 input.remove_prefix(pos + 2);
247
248 if (input.size() < static_cast<size_t>(value_len) + 2) {
249 resp.error = "Invalid request: truncated value";
250 return false;
251 }
252
253 resp.value = std::string(input.substr(0, value_len));
254 input.remove_prefix(value_len + 2);
255 return true;
256 }
257};
258#endif
RESP Decoder class.
Definition resp_decoder.hpp:54
static Resp decode(const char *buffer)
Decode a RESP command from a null-terminated string.
Definition resp_decoder.hpp:128
static Resp decode(const char *buffer, size_t length)
Decode a RESP command from a buffer.
Definition resp_decoder.hpp:62
Response object for RESP commands.
Definition resp_decoder.hpp:37
Operation
Enum for RESP operations.
Definition resp_decoder.hpp:24