ParseResult InputMessenger::CutInputMessage()

in src/brpc/input_messenger.cpp [84:180]


ParseResult InputMessenger::CutInputMessage(
        Socket* m, size_t* index, bool read_eof) {
    const int preferred = m->preferred_index();
    const int max_index = (int)_max_index.load(butil::memory_order_acquire);
    // Try preferred handler first. The preferred_index is set on last
    // selection or by client.
    if (preferred >= 0 && preferred <= max_index
            && _handlers[preferred].parse != NULL) {
        int cur_index = preferred;
        do {
            ParseResult result =
                _handlers[cur_index].parse(&m->_read_buf, m, read_eof, _handlers[cur_index].arg);
            if (result.is_ok() ||
                result.error() == PARSE_ERROR_NOT_ENOUGH_DATA) {
                m->set_preferred_index(cur_index);
                *index = cur_index;
                return result;
            } else if (result.error() != PARSE_ERROR_TRY_OTHERS) {
                // Critical error, return directly.
                LOG_IF(ERROR, result.error() == PARSE_ERROR_TOO_BIG_DATA)
                    << "A message from " << m->remote_side()
                    << "(protocol=" << _handlers[cur_index].name
                    << ") is bigger than " << FLAGS_max_body_size
                    << " bytes, the connection will be closed."
                    " Set max_body_size to allow bigger messages";
                return result;
            } else {
                if (m->_read_buf.size() >= 4) {
                    // The length of `data' must be PROTO_DUMMY_LEN + 1 to store extra ending char '\0'
                    char data[PROTO_DUMMY_LEN + 1];
                    m->_read_buf.copy_to_cstr(data, PROTO_DUMMY_LEN);
                    if (strncmp(data, "RDMA", PROTO_DUMMY_LEN) == 0 &&
                        m->_rdma_state == Socket::RDMA_OFF) {
                        // To avoid timeout when client uses RDMA but server uses TCP
                        return MakeParseError(PARSE_ERROR_TRY_OTHERS);
                    }
                }
            }

            if (m->CreatedByConnect()) {
                if((ProtocolType)cur_index == PROTOCOL_BAIDU_STD && cur_index == preferred) {
                    // baidu_std may fall to streaming_rpc.
                    cur_index = (int)PROTOCOL_STREAMING_RPC;
                    continue;
                } else if((ProtocolType)cur_index == PROTOCOL_STREAMING_RPC && cur_index == preferred) {
                    // streaming_rpc may fall to baidu_std.
                    cur_index = (int)PROTOCOL_BAIDU_STD;
                    continue;
                } else {
                    // The protocol is fixed at client-side, no need to try others.
                    LOG(ERROR) << "Fail to parse response from " << m->remote_side()
                        << " by " << _handlers[preferred].name 
                        << " at client-side";
                    return MakeParseError(PARSE_ERROR_ABSOLUTELY_WRONG);
                }
            } else {
                // Try other protocols.
                break;
            }
        } while (true);
        // Clear context before trying next protocol which probably has
        // an incompatible context with the current one.
        if (m->parsing_context()) {
            m->reset_parsing_context(NULL);
        }
        m->set_preferred_index(-1);
    }
    for (int i = 0; i <= max_index; ++i) {
        if (i == preferred || _handlers[i].parse == NULL) {
            // Don't try preferred handler(already tried) or invalid handler
            continue;
        }
        ParseResult result = _handlers[i].parse(&m->_read_buf, m, read_eof, _handlers[i].arg);
        if (result.is_ok() ||
            result.error() == PARSE_ERROR_NOT_ENOUGH_DATA) {
            m->set_preferred_index(i);
            *index = i;
            return result;
        } else if (result.error() != PARSE_ERROR_TRY_OTHERS) {
            // Critical error, return directly.
            LOG_IF(ERROR, result.error() == PARSE_ERROR_TOO_BIG_DATA)
                << "A message from " << m->remote_side()
                << "(protocol=" << _handlers[i].name
                << ") is bigger than " << FLAGS_max_body_size
                << " bytes, the connection will be closed."
                " Set max_body_size to allow bigger messages";
            return result;
        }
        // Clear context before trying next protocol which definitely has
        // an incompatible context with the current one.
        if (m->parsing_context()) {
            m->reset_parsing_context(NULL);
        }
        // Try other protocols.
    }
    return MakeParseError(PARSE_ERROR_TRY_OTHERS);
}