@@ -524,12 +524,20 @@ R"x*x*x(<html>
524
524
http_ranges parser_http_ranges (std::string range) const noexcept
525
525
{
526
526
range = strutil::remove_spaces (range);
527
+
528
+ // range 必须以 bytes= 开头, 否则返回空数组.
529
+ if (!range.starts_with (" bytes=" ))
530
+ return {};
531
+
532
+ // 去掉开头的 bytes= 字符串.
527
533
boost::ireplace_first (range, " bytes=" , " " );
528
534
535
+ // 使用正则表达式解析 range.
529
536
boost::sregex_iterator it (
530
537
range.begin (), range.end (),
531
538
boost::regex{ " ((\\ d+)-(\\ d+))+" });
532
539
540
+ // 解析结果保存在 results 中.
533
541
http_ranges results;
534
542
std::for_each (it, {}, [&results](const auto & what) mutable
535
543
{
@@ -539,14 +547,18 @@ R"x*x*x(<html>
539
547
std::atoll (what[3 ].str ().c_str ())));
540
548
});
541
549
550
+ // 如果开始为-或者结尾为-, 则表示只有一个数字, 则将其作为开始
551
+ // 或者结束, 开始按 http range request 规则解析
552
+ // 例如: bytes=-100, bytes=100-
553
+ // 解析后的结果为: { {-1, 100}, {100, -1} }
542
554
if (results.empty () && !range.empty ())
543
555
{
544
556
if (range.front () == ' -' )
545
557
{
546
558
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 ));
548
560
}
549
- else if (range. back () == ' - ' )
561
+ else
550
562
{
551
563
auto r = std::atoll (range.c_str ());
552
564
results.emplace_back (std::make_pair (r, -1 ));
@@ -3860,21 +3872,51 @@ R"x*x*x(<html>
3860
3872
" , range: " + std::string (request[" Range" ])
3861
3873
: std::string ());
3862
3874
3863
- auto range = parser_http_ranges (request[" Range" ]);
3864
3875
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 )
3866
3880
{
3867
3881
st = http::status::partial_content;
3868
3882
auto & r = range.front ();
3869
3883
3870
- if (r.second == -1 )
3884
+ // 起始位置为 -1, 表示从文件末尾开始读取, 例如 Range: -500
3885
+ // 则表示读取文件末尾的 500 字节.
3886
+ if (r.first == -1 )
3871
3887
{
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 )
3873
3897
{
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 ;
3875
3905
r.second = content_length - 1 ;
3876
3906
}
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
3878
3920
{
3879
3921
r.second = content_length - 1 ;
3880
3922
}
@@ -3915,6 +3957,7 @@ R"x*x*x(<html>
3915
3957
r.first ,
3916
3958
r.second ,
3917
3959
content_length);
3960
+
3918
3961
content_length = r.second - r.first + 1 ;
3919
3962
res.set (http::field::content_range, content_range);
3920
3963
}
0 commit comments