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"
18 #include <sys/types.h>
25 bool memcached_binary_protocol_pedantic_check_request(
26 const protocol_binary_request_header
*request
) {
27 ensure(request
->request
.magic
== PROTOCOL_BINARY_REQ
);
28 ensure(request
->request
.datatype
== PROTOCOL_BINARY_RAW_BYTES
);
30 ensure(request
->bytes
[6] == 0);
31 ensure(request
->bytes
[7] == 0);
33 uint8_t opcode
= request
->request
.opcode
;
34 uint16_t keylen
= ntohs(request
->request
.keylen
);
35 uint8_t extlen
= request
->request
.extlen
;
36 uint32_t bodylen
= ntohl(request
->request
.bodylen
);
38 ensure(bodylen
>= (keylen
+ extlen
));
41 case PROTOCOL_BINARY_CMD_GET
:
42 case PROTOCOL_BINARY_CMD_GETK
:
43 case PROTOCOL_BINARY_CMD_GETKQ
:
44 case PROTOCOL_BINARY_CMD_GETQ
:
47 ensure(keylen
== bodylen
);
48 ensure(request
->request
.cas
== 0);
51 case PROTOCOL_BINARY_CMD_ADD
:
52 case PROTOCOL_BINARY_CMD_ADDQ
:
53 /* it makes no sense to run add with a cas value */
54 ensure(request
->request
.cas
== 0);
56 case PROTOCOL_BINARY_CMD_SET
:
57 case PROTOCOL_BINARY_CMD_SETQ
:
58 case PROTOCOL_BINARY_CMD_REPLACE
:
59 case PROTOCOL_BINARY_CMD_REPLACEQ
:
64 case PROTOCOL_BINARY_CMD_DELETE
:
65 case PROTOCOL_BINARY_CMD_DELETEQ
:
68 ensure(keylen
== bodylen
);
71 case PROTOCOL_BINARY_CMD_INCREMENT
:
72 case PROTOCOL_BINARY_CMD_INCREMENTQ
:
73 case PROTOCOL_BINARY_CMD_DECREMENT
:
74 case PROTOCOL_BINARY_CMD_DECREMENTQ
:
77 ensure(keylen
+ extlen
== bodylen
);
80 case PROTOCOL_BINARY_CMD_QUIT
:
81 case PROTOCOL_BINARY_CMD_QUITQ
:
82 case PROTOCOL_BINARY_CMD_NOOP
:
83 case PROTOCOL_BINARY_CMD_VERSION
:
89 case PROTOCOL_BINARY_CMD_FLUSH
:
90 case PROTOCOL_BINARY_CMD_FLUSHQ
:
91 ensure(extlen
== 0 || extlen
== 4);
93 ensure(bodylen
== extlen
);
96 case PROTOCOL_BINARY_CMD_STAT
:
98 /* May have key, but not value */
99 ensure(keylen
== bodylen
);
102 case PROTOCOL_BINARY_CMD_APPEND
:
103 case PROTOCOL_BINARY_CMD_APPENDQ
:
104 case PROTOCOL_BINARY_CMD_PREPEND
:
105 case PROTOCOL_BINARY_CMD_PREPENDQ
:
111 /* Unknown command */
118 bool memcached_binary_protocol_pedantic_check_response(
119 const protocol_binary_request_header
*request
,
120 const protocol_binary_response_header
*response
) {
121 ensure(response
->response
.magic
== PROTOCOL_BINARY_RES
);
122 ensure(response
->response
.datatype
== PROTOCOL_BINARY_RAW_BYTES
);
123 ensure(response
->response
.opaque
== request
->request
.opaque
);
125 uint16_t status
= ntohs(response
->response
.status
);
126 uint8_t opcode
= response
->response
.opcode
;
128 if (status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
) {
130 case PROTOCOL_BINARY_CMD_ADDQ
:
131 case PROTOCOL_BINARY_CMD_APPENDQ
:
132 case PROTOCOL_BINARY_CMD_DECREMENTQ
:
133 case PROTOCOL_BINARY_CMD_DELETEQ
:
134 case PROTOCOL_BINARY_CMD_FLUSHQ
:
135 case PROTOCOL_BINARY_CMD_INCREMENTQ
:
136 case PROTOCOL_BINARY_CMD_PREPENDQ
:
137 case PROTOCOL_BINARY_CMD_QUITQ
:
138 case PROTOCOL_BINARY_CMD_REPLACEQ
:
139 case PROTOCOL_BINARY_CMD_SETQ
:
140 /* Quiet command shouldn't return on success */
147 case PROTOCOL_BINARY_CMD_ADD
:
148 case PROTOCOL_BINARY_CMD_REPLACE
:
149 case PROTOCOL_BINARY_CMD_SET
:
150 case PROTOCOL_BINARY_CMD_APPEND
:
151 case PROTOCOL_BINARY_CMD_PREPEND
:
152 ensure(response
->response
.keylen
== 0);
153 ensure(response
->response
.extlen
== 0);
154 ensure(response
->response
.bodylen
== 0);
155 ensure(response
->response
.cas
!= 0);
157 case PROTOCOL_BINARY_CMD_FLUSH
:
158 case PROTOCOL_BINARY_CMD_NOOP
:
159 case PROTOCOL_BINARY_CMD_QUIT
:
160 case PROTOCOL_BINARY_CMD_DELETE
:
161 ensure(response
->response
.keylen
== 0);
162 ensure(response
->response
.extlen
== 0);
163 ensure(response
->response
.bodylen
== 0);
164 ensure(response
->response
.cas
== 0);
167 case PROTOCOL_BINARY_CMD_DECREMENT
:
168 case PROTOCOL_BINARY_CMD_INCREMENT
:
169 ensure(response
->response
.keylen
== 0);
170 ensure(response
->response
.extlen
== 0);
171 ensure(ntohl(response
->response
.bodylen
) == 8);
172 ensure(response
->response
.cas
!= 0);
175 case PROTOCOL_BINARY_CMD_STAT
:
176 ensure(response
->response
.extlen
== 0);
177 /* key and value exists in all packets except in the terminating */
178 ensure(response
->response
.cas
== 0);
181 case PROTOCOL_BINARY_CMD_VERSION
:
182 ensure(response
->response
.keylen
== 0);
183 ensure(response
->response
.extlen
== 0);
184 ensure(response
->response
.bodylen
!= 0);
185 ensure(response
->response
.cas
== 0);
188 case PROTOCOL_BINARY_CMD_GET
:
189 case PROTOCOL_BINARY_CMD_GETQ
:
190 ensure(response
->response
.keylen
== 0);
191 ensure(response
->response
.extlen
== 4);
192 ensure(response
->response
.cas
!= 0);
195 case PROTOCOL_BINARY_CMD_GETK
:
196 case PROTOCOL_BINARY_CMD_GETKQ
:
197 ensure(response
->response
.keylen
!= 0);
198 ensure(response
->response
.extlen
== 4);
199 ensure(response
->response
.cas
!= 0);
203 /* Undefined command code */
207 ensure(response
->response
.cas
== 0);
208 ensure(response
->response
.extlen
== 0);
209 if (opcode
!= PROTOCOL_BINARY_CMD_GETK
) {
210 ensure(response
->response
.keylen
== 0);