2021SC@SDUSC
本周主要任务是改进HttpTaskImpl.cc中的ComplexHttpTask::message_out()部分代码,提高http性能。
在简单的http request client中,任务被调起,发送request(request优先复用,然后message_out发送)
相关代码在workflow/src/factory/HttpTaskImpl.cc中。
用gdb查看
cgdb ./wget (gdb) set args www.baidu.com (gdb) b HttpTaskImpl.cc:ComplexHttpTask::message_out
分析代码可以看到,这里一共用了4次find header,分别是"Transfer-Encoding","Content-Length", "Connection","Keep-Alive",伴随了三次cursor的rewind。
旧版代码如下:
CommMessageOut *ComplexHttpProxyTask::message_out()
{
long long seqid = this->get_seq();
if (seqid == 0) // ConNECT
{
HttpRequest *conn_req = new HttpRequest;
std::string request_uri(user_uri_.host);
request_uri += ":";
if (user_uri_.port)
request_uri += user_uri_.port;
else
request_uri += is_ssl_ ? "443" : "80";
conn_req->set_method("CONNECT");
conn_req->set_request_uri(request_uri);
conn_req->set_http_version("HTTP/1.1");
conn_req->add_header_pair("Host", request_uri.c_str());
if (!proxy_auth_.empty())
conn_req->add_header_pair("Proxy-Authorization", proxy_auth_);
is_user_request_ = false;
return conn_req;
}
else if (seqid == 1 && is_ssl_) // HANDSHAKE
{
is_user_request_ = false;
return get_ssl_handshaker();
}
auto *msg = (ProtocolMessage *)this->ComplexHttpTask::message_out();
return is_ssl_ ? get_ssl_wrapper(msg) : msg;
}
修改后新代码如下:
CommMessageOut *ComplexHttpTask::message_out()
{
HttpRequest *req = this->get_req();
struct HttpMessageHeader header;
bool is_alive;
// 如果不为chunked 且req没有content_length 的 header
if (!req->is_chunked() && !req->has_content_length_header())
{
size_t body_size = req->get_output_body_size();
const char *method = req->get_method();
if (body_size != 0 || strcmp(method, "POST") == 0 ||
strcmp(method, "PUT") == 0)
{
// 同理,不为chunked的话,那我们给他添加上 "Content-Length" 这个header
char buf[32];
header.name = "Content-Length";
header.name_len = strlen("Content-Length");
header.value = buf;
header.value_len = sprintf(buf, "%zu", body_size);
req->add_header(&header);
}
}
// 如果req有connection_header
if (req->has_connection_header())
// 查看是否is_keep_alive
is_alive = req->is_keep_alive();
else
{
// 如果没有,我们帮用户添加
header.name = "Connection";
header.name_len = strlen("Connection");
is_alive = (this->keep_alive_timeo != 0); // 如果是time_out不为0,则是Keep-Alive
if (is_alive)
{
header.value = "Keep-Alive";
header.value_len = strlen("Keep-Alive");
}
else
{
header.value = "close";
header.value_len = strlen("close");
}
req->add_header(&header);
}
if (!is_alive)
this->keep_alive_timeo = 0;
else if (req->has_keep_alive_header())
{
// 这里因为不是简单的有没有的信息,而是要把这个字段取出切割,还是得用一次find
HttpHeaderCursor req_cursor(req);
//req---Connection: Keep-Alive
//req---Keep-Alive: timeout=0,max=100
header.name = "Keep-Alive";
header.name_len = strlen("Keep-Alive");
if (req_cursor.find(&header))
{
std::string keep_alive((const char *)header.value, header.value_len);
std::vector params = StringUtil::split(keep_alive, ',');
for (const auto& kv : params)
{
std::vector arr = StringUtil::split(kv, '=');
if (arr.size() < 2)
arr.emplace_back("0");
std::string key = StringUtil::strip(arr[0]);
std::string val = StringUtil::strip(arr[1]);
if (strcasecmp(key.c_str(), "timeout") == 0)
{
this->keep_alive_timeo = 1000 * atoi(val.c_str());
break;
}
}
}
if ((unsigned int)this->keep_alive_timeo > HTTP_KEEPALIVE_MAX)
this->keep_alive_timeo = HTTP_KEEPALIVE_MAX;
//if (this->keep_alive_timeo < 0 || this->keep_alive_timeo > HTTP_KEEPALIVE_MAX)
}
//req->set_header_pair("Accept", "*/*");
return this->WFComplexClientTask::message_out();
}
原代码没有利用好http_parser中的一些记录信息, 比如说是否是chunked,是否有content_length _header等等,而是反复的rewind去find这些字段。新代码改进了这点不足。



