2 +--------------------------------------------------------------------+
3 | libmemcached - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
16 #include "libmemcachedprotocol/common.h"
17 #include "p9y/socket.hpp"
24 bool memcached_binary_protocol_pedantic_check_request(
25 const protocol_binary_request_header
*request
) {
26 ensure(request
->request
.magic
== PROTOCOL_BINARY_REQ
);
27 ensure(request
->request
.datatype
== PROTOCOL_BINARY_RAW_BYTES
);
29 ensure(request
->bytes
[6] == 0);
30 ensure(request
->bytes
[7] == 0);
32 uint8_t opcode
= request
->request
.opcode
;
33 uint16_t keylen
= ntohs(request
->request
.keylen
);
34 uint8_t extlen
= request
->request
.extlen
;
35 uint32_t bodylen
= ntohl(request
->request
.bodylen
);
37 ensure(bodylen
>= (keylen
+ extlen
));
40 case PROTOCOL_BINARY_CMD_GET
:
41 case PROTOCOL_BINARY_CMD_GETK
:
42 case PROTOCOL_BINARY_CMD_GETKQ
:
43 case PROTOCOL_BINARY_CMD_GETQ
:
46 ensure(keylen
== bodylen
);
47 ensure(request
->request
.cas
== 0);
50 case PROTOCOL_BINARY_CMD_ADD
:
51 case PROTOCOL_BINARY_CMD_ADDQ
:
52 /* it makes no sense to run add with a cas value */
53 ensure(request
->request
.cas
== 0);
55 case PROTOCOL_BINARY_CMD_SET
:
56 case PROTOCOL_BINARY_CMD_SETQ
:
57 case PROTOCOL_BINARY_CMD_REPLACE
:
58 case PROTOCOL_BINARY_CMD_REPLACEQ
:
63 case PROTOCOL_BINARY_CMD_DELETE
:
64 case PROTOCOL_BINARY_CMD_DELETEQ
:
67 ensure(keylen
== bodylen
);
70 case PROTOCOL_BINARY_CMD_INCREMENT
:
71 case PROTOCOL_BINARY_CMD_INCREMENTQ
:
72 case PROTOCOL_BINARY_CMD_DECREMENT
:
73 case PROTOCOL_BINARY_CMD_DECREMENTQ
:
76 ensure(keylen
+ extlen
== bodylen
);
79 case PROTOCOL_BINARY_CMD_QUIT
:
80 case PROTOCOL_BINARY_CMD_QUITQ
:
81 case PROTOCOL_BINARY_CMD_NOOP
:
82 case PROTOCOL_BINARY_CMD_VERSION
:
88 case PROTOCOL_BINARY_CMD_FLUSH
:
89 case PROTOCOL_BINARY_CMD_FLUSHQ
:
90 ensure(extlen
== 0 || extlen
== 4);
92 ensure(bodylen
== extlen
);
95 case PROTOCOL_BINARY_CMD_STAT
:
97 /* May have key, but not value */
98 ensure(keylen
== bodylen
);
101 case PROTOCOL_BINARY_CMD_APPEND
:
102 case PROTOCOL_BINARY_CMD_APPENDQ
:
103 case PROTOCOL_BINARY_CMD_PREPEND
:
104 case PROTOCOL_BINARY_CMD_PREPENDQ
:
110 /* Unknown command */
117 bool memcached_binary_protocol_pedantic_check_response(
118 const protocol_binary_request_header
*request
,
119 const protocol_binary_response_header
*response
) {
120 ensure(response
->response
.magic
== PROTOCOL_BINARY_RES
);
121 ensure(response
->response
.datatype
== PROTOCOL_BINARY_RAW_BYTES
);
122 ensure(response
->response
.opaque
== request
->request
.opaque
);
124 uint16_t status
= ntohs(response
->response
.status
);
125 uint8_t opcode
= response
->response
.opcode
;
127 if (status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
) {
129 case PROTOCOL_BINARY_CMD_ADDQ
:
130 case PROTOCOL_BINARY_CMD_APPENDQ
:
131 case PROTOCOL_BINARY_CMD_DECREMENTQ
:
132 case PROTOCOL_BINARY_CMD_DELETEQ
:
133 case PROTOCOL_BINARY_CMD_FLUSHQ
:
134 case PROTOCOL_BINARY_CMD_INCREMENTQ
:
135 case PROTOCOL_BINARY_CMD_PREPENDQ
:
136 case PROTOCOL_BINARY_CMD_QUITQ
:
137 case PROTOCOL_BINARY_CMD_REPLACEQ
:
138 case PROTOCOL_BINARY_CMD_SETQ
:
139 /* Quiet command shouldn't return on success */
146 case PROTOCOL_BINARY_CMD_ADD
:
147 case PROTOCOL_BINARY_CMD_REPLACE
:
148 case PROTOCOL_BINARY_CMD_SET
:
149 case PROTOCOL_BINARY_CMD_APPEND
:
150 case PROTOCOL_BINARY_CMD_PREPEND
:
151 ensure(response
->response
.keylen
== 0);
152 ensure(response
->response
.extlen
== 0);
153 ensure(response
->response
.bodylen
== 0);
154 ensure(response
->response
.cas
);
156 case PROTOCOL_BINARY_CMD_FLUSH
:
157 case PROTOCOL_BINARY_CMD_NOOP
:
158 case PROTOCOL_BINARY_CMD_QUIT
:
159 case PROTOCOL_BINARY_CMD_DELETE
:
160 ensure(response
->response
.keylen
== 0);
161 ensure(response
->response
.extlen
== 0);
162 ensure(response
->response
.bodylen
== 0);
163 ensure(response
->response
.cas
== 0);
166 case PROTOCOL_BINARY_CMD_DECREMENT
:
167 case PROTOCOL_BINARY_CMD_INCREMENT
:
168 ensure(response
->response
.keylen
== 0);
169 ensure(response
->response
.extlen
== 0);
170 ensure(ntohl(response
->response
.bodylen
) == 8);
171 ensure(response
->response
.cas
);
174 case PROTOCOL_BINARY_CMD_STAT
:
175 ensure(response
->response
.extlen
== 0);
176 /* key and value exists in all packets except in the terminating */
177 ensure(response
->response
.cas
== 0);
180 case PROTOCOL_BINARY_CMD_VERSION
:
181 ensure(response
->response
.keylen
== 0);
182 ensure(response
->response
.extlen
== 0);
183 ensure(response
->response
.bodylen
);
184 ensure(response
->response
.cas
== 0);
187 case PROTOCOL_BINARY_CMD_GET
:
188 case PROTOCOL_BINARY_CMD_GETQ
:
189 ensure(response
->response
.keylen
== 0);
190 ensure(response
->response
.extlen
== 4);
191 ensure(response
->response
.cas
);
194 case PROTOCOL_BINARY_CMD_GETK
:
195 case PROTOCOL_BINARY_CMD_GETKQ
:
196 ensure(response
->response
.keylen
);
197 ensure(response
->response
.extlen
== 4);
198 ensure(response
->response
.cas
);
202 /* Undefined command code */
206 ensure(response
->response
.cas
== 0);
207 ensure(response
->response
.extlen
== 0);
208 if (opcode
!= PROTOCOL_BINARY_CMD_GETK
) {
209 ensure(response
->response
.keylen
== 0);