【Servicemesh系列】【Envoy源码解析(三)】一个Http请求到响应的全链路(二)

目录

上一章节讲到了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(
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值