Skip to content

Commit 3b9999d

Browse files
committed
Improve http range request
1 parent 0ce2ddf commit 3b9999d

File tree

1 file changed

+51
-8
lines changed

1 file changed

+51
-8
lines changed

proxy/include/proxy/proxy_server.hpp

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -524,12 +524,20 @@ R"x*x*x(<html>
524524
http_ranges parser_http_ranges(std::string range) const noexcept
525525
{
526526
range = strutil::remove_spaces(range);
527+
528+
// range 必须以 bytes= 开头, 否则返回空数组.
529+
if (!range.starts_with("bytes="))
530+
return {};
531+
532+
// 去掉开头的 bytes= 字符串.
527533
boost::ireplace_first(range, "bytes=", "");
528534

535+
// 使用正则表达式解析 range.
529536
boost::sregex_iterator it(
530537
range.begin(), range.end(),
531538
boost::regex{ "((\\d+)-(\\d+))+" });
532539

540+
// 解析结果保存在 results 中.
533541
http_ranges results;
534542
std::for_each(it, {}, [&results](const auto& what) mutable
535543
{
@@ -539,14 +547,18 @@ R"x*x*x(<html>
539547
std::atoll(what[3].str().c_str())));
540548
});
541549

550+
// 如果开始为-或者结尾为-, 则表示只有一个数字, 则将其作为开始
551+
// 或者结束, 开始按 http range request 规则解析
552+
// 例如: bytes=-100, bytes=100-
553+
// 解析后的结果为: { {-1, 100}, {100, -1} }
542554
if (results.empty() && !range.empty())
543555
{
544556
if (range.front() == '-')
545557
{
546558
auto r = std::atoll(range.c_str());
547-
results.emplace_back(std::make_pair(r, -1));
559+
results.emplace_back(std::make_pair(-1, r));
548560
}
549-
else if (range.back() == '-')
561+
else
550562
{
551563
auto r = std::atoll(range.c_str());
552564
results.emplace_back(std::make_pair(r, -1));
@@ -3860,21 +3872,51 @@ R"x*x*x(<html>
38603872
", range: " + std::string(request["Range"])
38613873
: std::string());
38623874

3863-
auto range = parser_http_ranges(request["Range"]);
38643875
http::status st = http::status::ok;
3865-
if (!range.empty())
3876+
auto range = parser_http_ranges(request["Range"]);
3877+
3878+
// 只支持一个 range 的请求, 不支持多个 range 的请求.
3879+
if (range.size() == 1)
38663880
{
38673881
st = http::status::partial_content;
38683882
auto& r = range.front();
38693883

3870-
if (r.second == -1)
3884+
// 起始位置为 -1, 表示从文件末尾开始读取, 例如 Range: -500
3885+
// 则表示读取文件末尾的 500 字节.
3886+
if (r.first == -1)
38713887
{
3872-
if (r.first < 0)
3888+
// 如果第二个参数也为 -1, 则表示请求有问题, 返回 416.
3889+
if (r.second < 0)
3890+
{
3891+
co_await default_http_route(request,
3892+
fake_416_content,
3893+
http::status::range_not_satisfiable);
3894+
co_return;
3895+
}
3896+
else if (r.second >= 0)
38733897
{
3874-
r.first = content_length + r.first;
3898+
// 计算起始位置和结束位置, 例如 Range: -500
3899+
// 则表示读取文件末尾的 500 字节.
3900+
// content_length - r.second 表示起始位置.
3901+
// content_length - 1 表示结束位置.
3902+
// 例如文件长度为 1000 字节, 则起始位置为 500,
3903+
// 结束位置为 999, 一共 500 字节.
3904+
r.first = content_length - r.second;
38753905
r.second = content_length - 1;
38763906
}
3877-
else if (r.first >= 0)
3907+
}
3908+
else if (r.second == -1)
3909+
{
3910+
// 起始位置为正数, 表示从文件头开始读取, 例如 Range: 500
3911+
// 则表示读取文件头的 500 字节.
3912+
if (r.first < 0)
3913+
{
3914+
co_await default_http_route(request,
3915+
fake_416_content,
3916+
http::status::range_not_satisfiable);
3917+
co_return;
3918+
}
3919+
else
38783920
{
38793921
r.second = content_length - 1;
38803922
}
@@ -3915,6 +3957,7 @@ R"x*x*x(<html>
39153957
r.first,
39163958
r.second,
39173959
content_length);
3960+
39183961
content_length = r.second - r.first + 1;
39193962
res.set(http::field::content_range, content_range);
39203963
}

0 commit comments

Comments
 (0)