nghttp: Assign different priority according to the resource type

This commit is contained in:
Tatsuhiro Tsujikawa 2013-09-29 18:58:46 +09:00
parent 31ae1fe660
commit 8e9f08f81d
3 changed files with 65 additions and 32 deletions

View File

@ -60,6 +60,20 @@ const char* get_attr(const xmlChar **attrs, const char *name)
} }
} // namespace } // namespace
namespace {
void add_link(ParserData *parser_data, const char *uri, RequestPriority pri)
{
auto u = xmlBuildURI(reinterpret_cast<const xmlChar*>(uri),
reinterpret_cast<const xmlChar*>
(parser_data->base_uri.c_str()));
if(u) {
parser_data->links.push_back(std::make_pair(reinterpret_cast<char*>(u),
pri));
free(u);
}
}
} // namespace
namespace { namespace {
void start_element_func void start_element_func
(void* user_data, (void* user_data,
@ -70,29 +84,26 @@ void start_element_func
if(util::strieq(reinterpret_cast<const char*>(name), "link")) { if(util::strieq(reinterpret_cast<const char*>(name), "link")) {
const char *rel_attr = get_attr(attrs, "rel"); const char *rel_attr = get_attr(attrs, "rel");
const char *href_attr = get_attr(attrs, "href"); const char *href_attr = get_attr(attrs, "href");
if((util::strieq(rel_attr, "shortcut icon") || if(!href_attr) {
util::strieq(rel_attr, "stylesheet")) && return;
href_attr) {
xmlChar *u = xmlBuildURI(reinterpret_cast<const xmlChar*>(href_attr),
reinterpret_cast<const xmlChar*>
(parser_data->base_uri.c_str()));
if(u) {
parser_data->links.push_back(reinterpret_cast<char*>(u));
free(u);
} }
if(util::strieq(rel_attr, "shortcut icon")) {
add_link(parser_data, href_attr, REQ_PRI_LOWEST);
} else if(util::strieq(rel_attr, "stylesheet")) {
add_link(parser_data, href_attr, REQ_PRI_MEDIUM);
} }
} else if(util::strieq(reinterpret_cast<const char*>(name), "img") || } else if(util::strieq(reinterpret_cast<const char*>(name), "img")) {
util::strieq(reinterpret_cast<const char*>(name), "script")) {
const char *src_attr = get_attr(attrs, "src"); const char *src_attr = get_attr(attrs, "src");
if(src_attr) { if(!src_attr) {
xmlChar *u = xmlBuildURI(reinterpret_cast<const xmlChar*>(src_attr), return;
reinterpret_cast<const xmlChar*>
(parser_data->base_uri.c_str()));
if(u) {
parser_data->links.push_back(reinterpret_cast<char*>(u));
free(u);
} }
add_link(parser_data, src_attr, REQ_PRI_LOWEST);
} else if(util::strieq(reinterpret_cast<const char*>(name), "script")) {
const char *src_attr = get_attr(attrs, "src");
if(!src_attr) {
return;
} }
add_link(parser_data, src_attr, REQ_PRI_MEDIUM);
} }
} }
} // namespace } // namespace
@ -168,7 +179,8 @@ int HtmlParser::parse_chunk_internal(const char *chunk, size_t size,
} }
} }
const std::vector<std::string>& HtmlParser::get_links() const const std::vector<std::pair<std::string, RequestPriority>>&
HtmlParser::get_links() const
{ {
return parser_data_.links; return parser_data_.links;
} }

View File

@ -36,9 +36,16 @@
namespace nghttp2 { namespace nghttp2 {
enum RequestPriority {
REQ_PRI_HIGH = 0,
REQ_PRI_MEDIUM = 1,
REQ_PRI_LOW = 2,
REQ_PRI_LOWEST = 3
};
struct ParserData { struct ParserData {
std::string base_uri; std::string base_uri;
std::vector<std::string> links; std::vector<std::pair<std::string, RequestPriority>> links;
ParserData(const std::string& base_uri); ParserData(const std::string& base_uri);
}; };
@ -47,7 +54,8 @@ public:
HtmlParser(const std::string& base_uri); HtmlParser(const std::string& base_uri);
~HtmlParser(); ~HtmlParser();
int parse_chunk(const char *chunk, size_t size, int fin); int parse_chunk(const char *chunk, size_t size, int fin);
const std::vector<std::string>& get_links() const; const std::vector<std::pair<std::string, RequestPriority>>&
get_links() const;
void clear_links(); void clear_links();
private: private:
int parse_chunk_internal(const char *chunk, size_t size, int fin); int parse_chunk_internal(const char *chunk, size_t size, int fin);

View File

@ -248,16 +248,17 @@ struct Request {
const nghttp2_data_provider *data_prd; const nghttp2_data_provider *data_prd;
int64_t data_length; int64_t data_length;
int64_t data_offset; int64_t data_offset;
int32_t pri;
// Recursion level: 0: first entity, 1: entity linked from first entity // Recursion level: 0: first entity, 1: entity linked from first entity
int level; int level;
RequestStat stat; RequestStat stat;
std::string status; std::string status;
Request(const std::string& uri, const http_parser_url &u, Request(const std::string& uri, const http_parser_url &u,
const nghttp2_data_provider *data_prd, int64_t data_length, const nghttp2_data_provider *data_prd, int64_t data_length,
int level = 0) int32_t pri, int level = 0)
: uri(uri), u(u), : uri(uri), u(u),
inflater(nullptr), html_parser(nullptr), data_prd(data_prd), inflater(nullptr), html_parser(nullptr), data_prd(data_prd),
data_length(data_length), data_offset(0), data_length(data_length), data_offset(0), pri(pri),
level(level) level(level)
{} {}
@ -794,6 +795,7 @@ struct HttpClient {
bool add_request(const std::string& uri, bool add_request(const std::string& uri,
const nghttp2_data_provider *data_prd, const nghttp2_data_provider *data_prd,
int64_t data_length, int64_t data_length,
int32_t pri,
int level = 0) int level = 0)
{ {
http_parser_url u; http_parser_url u;
@ -807,7 +809,7 @@ struct HttpClient {
path_cache.insert(uri); path_cache.insert(uri);
} }
reqvec.push_back(util::make_unique<Request>(uri, u, data_prd, reqvec.push_back(util::make_unique<Request>(uri, u, data_prd,
data_length, level)); data_length, pri, level));
return true; return true;
} }
} }
@ -930,12 +932,23 @@ void submit_request(HttpClient *client,
} }
nv[pos] = nullptr; nv[pos] = nullptr;
int r = nghttp2_submit_request(client->session, config.pri, int r = nghttp2_submit_request(client->session, req->pri,
nv.get(), req->data_prd, req); nv.get(), req->data_prd, req);
assert(r == 0); assert(r == 0);
} }
} // namespace } // namespace
namespace {
int32_t adjust_pri(int32_t base_pri, int32_t rel_pri)
{
if((int32_t)NGHTTP2_PRI_LOWEST - rel_pri < base_pri) {
return NGHTTP2_PRI_LOWEST;
} else {
return base_pri + rel_pri;
}
}
} // namespace
namespace { namespace {
void update_html_parser(HttpClient *client, Request *req, void update_html_parser(HttpClient *client, Request *req,
const uint8_t *data, size_t len, int fin) const uint8_t *data, size_t len, int fin)
@ -945,16 +958,16 @@ void update_html_parser(HttpClient *client, Request *req,
} }
req->update_html_parser(data, len, fin); req->update_html_parser(data, len, fin);
for(size_t i = 0; i < req->html_parser->get_links().size(); ++i) { for(auto& p : req->html_parser->get_links()) {
const auto& raw_uri = req->html_parser->get_links()[i]; auto uri = strip_fragment(p.first.c_str());
auto uri = strip_fragment(raw_uri.c_str());
http_parser_url u; http_parser_url u;
if(http_parser_parse_url(uri.c_str(), uri.size(), 0, &u) == 0 && if(http_parser_parse_url(uri.c_str(), uri.size(), 0, &u) == 0 &&
fieldeq(uri.c_str(), u, req->uri.c_str(), req->u, UF_SCHEMA) && fieldeq(uri.c_str(), u, req->uri.c_str(), req->u, UF_SCHEMA) &&
fieldeq(uri.c_str(), u, req->uri.c_str(), req->u, UF_HOST) && fieldeq(uri.c_str(), u, req->uri.c_str(), req->u, UF_HOST) &&
porteq(uri.c_str(), u, req->uri.c_str(), req->u)) { porteq(uri.c_str(), u, req->uri.c_str(), req->u)) {
int32_t pri = adjust_pri(req->pri, p.second);
// No POST data for assets // No POST data for assets
if ( client->add_request(uri, nullptr, 0, req->level+1) ) { if ( client->add_request(uri, nullptr, 0, pri, req->level+1) ) {
submit_request(client, config.headers, submit_request(client, config.headers,
client->reqvec.back().get()); client->reqvec.back().get());
} }
@ -1344,7 +1357,7 @@ int communicate(const std::string& scheme, const std::string& host,
for(auto req : requests) { for(auto req : requests) {
for(int i = 0; i < config.multiply; ++i) { for(int i = 0; i < config.multiply; ++i) {
client.add_request(std::get<0>(req), std::get<1>(req), client.add_request(std::get<0>(req), std::get<1>(req),
std::get<2>(req)); std::get<2>(req), config.pri);
} }
} }
client.update_hostport(); client.update_hostport();