目录
上一章节讲到了FilterManager通过对Read Filter进行流程拼装,以下接着以最核心的路由功能为例,来串联整个请求发送的流程。
4. 请求解析
对于一个Sidecar来说,最核心的能力必然就是路由。没有路由,其他的功能都是枉谈。所以这边也就会引出Envoy里面最核心的一个Filter —— 连接管理器ConnectionManagerImpl
。当新连接的请求初次抵达时,不需要做任何处理:
Network::FilterStatus onNewConnection() override { return Network::FilterStatus::Continue; }
当处理包体数据时,代码如下,我们忽略掉一些重发和失败处理、状态更新的逻辑:
Network::FilterStatus ConnectionManagerImpl::onData(Buffer::Instance& data, bool end_stream) {
......
if (!codec_) {
// 初次访问时,codec会被初始化出来。codec是ServerConnection类型。会承担编解码的任务。
codec_ = config_.createCodec(read_callbacks_->connection(), data, *this);
......
}
bool redispatch;
do {
redispatch = false;
try {
// 这边即会进行真实的解码过程。
codec_->dispatch(data);
} catch (const CodecProtocolException& e) {
......
}
} while (redispatch);
return Network::FilterStatus::StopIteration;
}
void ConnectionImpl::dispatch(Buffer::Instance& data) {
//......
if (data.length() > 0) {
uint64_t num_slices = data.getRawSlices(nullptr, 0);
Buffer::RawSlice slices[num_slices];
data.getRawSlices(slices, num_slices);
// 对buffer数据进行分片处理
for (Buffer::RawSlice& slice : slices) {
total_parsed += dispatchSlice(static_cast<const char*>(slice.mem_), slice.len_);
}
} else {
dispatchSlice(nullptr, 0);
}
// 将buffer下标前移,代表已经消费完了指定byte长度的数据。
data.drain(total_parsed);
//......
}
真实解码的过程即在dispatchSlice中,如下:
size_t ConnectionImpl::dispatchSlice(const char* slice, size_t len) {
ssize_t rc = http_parser_execute(&parser_, &settings_, slice, len);
//......
return rc;
}
此处用到了http_parser库来进行处理。我们看下是如何处理的:
http_parser_settings ConnectionImpl::settings_{
[](http_parser* parser) -> int {
static_cast<ConnectionImpl*>(parser->data)->onMessageBeginBase();
return 0;
},
[](http_parser* parser, const char* at, size_t length) -> int {
static_cast<ConnectionImpl*>(parser->data)->onUrl(at, length);
return 0;
},
nullptr, // on_status
[](http_parser* parser, const char* at, size_t length) -> int {
static_cast<ConnectionImpl*>(parser->data)->onHeaderField(at, length);
return 0;
},
[](http_parser* parser, const char* at, size_t length) -> int {
static_cast<ConnectionImpl*>(parser->data)->onHeaderValue(at, length);
return 0;
},
[](http_parser* parser) -> int {
return static_cast<ConnectionImpl*>(parser->data)->onHeadersCompleteBase();
},
[](http_parser* parser, const char* at, size_t length) -> int {
static_cast<ConnectionImpl*>(parser->data)->onBody(at, length);
return 0;
},
[](http_parser* parser) -> int {
static_cast<ConnectionImpl*>(parser->data)->onMessageCompleteBase();
return 0;
},
nullptr, // on_chunk_header
nullptr // on_chunk_complete
};
如上所示,很清晰地把http1的数据切分了如上几个解析的过程。以下流程比较冗长,我们只挑选其中三个环节:
5. 请求的编解码器初始化阶段
onMessageBegin环节,设置一个Codec(ServerConnection)的Decoder和Encoder。这边的Encoder即为ServerConnection自己(注意,ServerConnection持有了网络层的ConnectionImpl实例,可以用以进行响应回写,后面会进一步提及),Decoder即为ActiveStream。ActiveStream会持有ServerConnection(有点绕)。
void ServerConnectionImpl::onMessageBegin() {
if (!resetStreamCalled()) {
ASSERT(!active_request_);
active_request_.reset(