(if found): MUST have extras. MAY have key. MAY have value. Extra data for the get commands: Byte/ 0 | 1 | 2 | 3 | / | | | | |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| +---------------+---------------+---------------+---------------+ 0| Flags
| 345 | // +---------------+---------------+---------------+---------------+ |
| 346 | // Total 4 bytes |
| 347 | bool MemcacheResponse::PopGet( |
| 348 | butil::IOBuf* value, uint32_t* flags, uint64_t* cas_value) { |
| 349 | const size_t n = _buf.size(); |
| 350 | policy::MemcacheResponseHeader header; |
| 351 | if (n < sizeof(header)) { |
| 352 | butil::string_printf(&_err, "buffer is too small to contain a header"); |
| 353 | return false; |
| 354 | } |
| 355 | _buf.copy_to(&header, sizeof(header)); |
| 356 | if (header.command != (uint8_t)policy::MC_BINARY_GET) { |
| 357 | butil::string_printf(&_err, "not a GET response"); |
| 358 | return false; |
| 359 | } |
| 360 | if (n < sizeof(header) + header.total_body_length) { |
| 361 | butil::string_printf(&_err, "response=%u < header=%u + body=%u", |
| 362 | (unsigned)n, (unsigned)sizeof(header), header.total_body_length); |
| 363 | return false; |
| 364 | } |
| 365 | if (header.status != (uint16_t)STATUS_SUCCESS) { |
| 366 | LOG_IF(ERROR, header.extras_length != 0) << "GET response must not have flags"; |
| 367 | LOG_IF(ERROR, header.key_length != 0) << "GET response must not have key"; |
| 368 | const int value_size = (int)header.total_body_length - (int)header.extras_length |
| 369 | - (int)header.key_length; |
| 370 | if (value_size < 0) { |
| 371 | butil::string_printf(&_err, "value_size=%d is non-negative", value_size); |
| 372 | return false; |
| 373 | } |
| 374 | _buf.pop_front(sizeof(header) + header.extras_length + |
| 375 | header.key_length); |
| 376 | _err.clear(); |
| 377 | _buf.cutn(&_err, value_size); |
| 378 | return false; |
| 379 | } |
| 380 | if (header.extras_length != 4u) { |
| 381 | butil::string_printf(&_err, "GET response must have flags as extras, actual length=%u", |
| 382 | header.extras_length); |
| 383 | return false; |
| 384 | } |
| 385 | if (header.key_length != 0) { |
| 386 | butil::string_printf(&_err, "GET response must not have key"); |
| 387 | return false; |
| 388 | } |
| 389 | const int value_size = (int)header.total_body_length - (int)header.extras_length |
| 390 | - (int)header.key_length; |
| 391 | if (value_size < 0) { |
| 392 | butil::string_printf(&_err, "value_size=%d is non-negative", value_size); |
| 393 | return false; |
| 394 | } |
| 395 | _buf.pop_front(sizeof(header)); |
| 396 | uint32_t raw_flags = 0; |
| 397 | _buf.cutn(&raw_flags, sizeof(raw_flags)); |
| 398 | if (flags) { |
| 399 | *flags = butil::NetToHost32(raw_flags); |
| 400 | } |
| 401 | if (value) { |
| 402 | value->clear(); |
| 403 | _buf.cutn(value, value_size); |
| 404 | } |