| 74 | } |
| 75 | |
| 76 | ParseResult ParseMemcacheMessage(butil::IOBuf* source, |
| 77 | Socket* socket, bool /*read_eof*/, const void */*arg*/) { |
| 78 | while (1) { |
| 79 | const uint8_t* p_mcmagic = (const uint8_t*)source->fetch1(); |
| 80 | if (NULL == p_mcmagic) { |
| 81 | return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); |
| 82 | } |
| 83 | if (*p_mcmagic != (uint8_t)MC_MAGIC_RESPONSE) { |
| 84 | return MakeParseError(PARSE_ERROR_TRY_OTHERS); |
| 85 | } |
| 86 | char buf[24]; |
| 87 | const uint8_t* p = (const uint8_t*)source->fetch(buf, sizeof(buf)); |
| 88 | if (NULL == p) { |
| 89 | return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); |
| 90 | } |
| 91 | const MemcacheResponseHeader* header = (const MemcacheResponseHeader*)p; |
| 92 | uint32_t total_body_length = butil::NetToHost32(header->total_body_length); |
| 93 | if (source->size() < sizeof(*header) + total_body_length) { |
| 94 | return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); |
| 95 | } |
| 96 | |
| 97 | if (!IsSupportedCommand(header->command)) { |
| 98 | LOG(WARNING) << "Not support command=" << header->command; |
| 99 | source->pop_front(sizeof(*header) + total_body_length); |
| 100 | return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); |
| 101 | } |
| 102 | |
| 103 | PipelinedInfo pi; |
| 104 | if (!socket->PopPipelinedInfo(&pi)) { |
| 105 | LOG(WARNING) << "No corresponding PipelinedInfo in socket, drop"; |
| 106 | source->pop_front(sizeof(*header) + total_body_length); |
| 107 | return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); |
| 108 | } |
| 109 | MostCommonMessage* msg = |
| 110 | static_cast<MostCommonMessage*>(socket->parsing_context()); |
| 111 | if (msg == NULL) { |
| 112 | msg = MostCommonMessage::Get(); |
| 113 | socket->reset_parsing_context(msg); |
| 114 | } |
| 115 | |
| 116 | // endianness conversions. |
| 117 | const MemcacheResponseHeader local_header = { |
| 118 | header->magic, |
| 119 | header->command, |
| 120 | butil::NetToHost16(header->key_length), |
| 121 | header->extras_length, |
| 122 | header->data_type, |
| 123 | butil::NetToHost16(header->status), |
| 124 | total_body_length, |
| 125 | butil::NetToHost32(header->opaque), |
| 126 | butil::NetToHost64(header->cas_value), |
| 127 | }; |
| 128 | msg->meta.append(&local_header, sizeof(local_header)); |
| 129 | source->pop_front(sizeof(*header)); |
| 130 | source->cutn(&msg->meta, total_body_length); |
| 131 | if (header->command == MC_BINARY_SASL_AUTH) { |
| 132 | if (header->status != 0) { |
| 133 | LOG(ERROR) << "Failed to authenticate the couchbase bucket."; |
no test coverage detected