@@ -4720,29 +4720,47 @@ serialize_multipart_formdata(const MultipartFormDataItems &items,
47204720 return body;
47214721}
47224722
4723- inline std::pair<size_t , size_t >
4724- get_range_offset_and_length (Range range, size_t content_length) {
4725- if (range.first == -1 && range.second == -1 ) {
4726- return std::make_pair (0 , content_length);
4727- }
4723+ inline bool normalize_ranges (Request &req, Response &res) {
4724+ ssize_t len = static_cast <ssize_t >(res.content_length_ ? res.content_length_
4725+ : res.body .size ());
4726+
4727+ if (!req.ranges .empty ()) {
4728+ for (auto &r : req.ranges ) {
4729+ auto &st = r.first ;
4730+ auto &ed = r.second ;
4731+
4732+ if (st == -1 && ed == -1 ) {
4733+ st = 0 ;
4734+ ed = len;
4735+ }
4736+
4737+ if (st == -1 ) {
4738+ st = len - ed;
4739+ ed = len - 1 ;
4740+ }
47284741
4729- auto slen = static_cast < ssize_t >(content_length);
4742+ if (ed == - 1 ) { ed = len - 1 ; }
47304743
4731- if (range.first == -1 ) {
4732- range.first = (std::max)(static_cast <ssize_t >(0 ), slen - range.second );
4733- range.second = slen - 1 ;
4744+ if (!(0 <= st && st <= ed && ed <= len - 1 )) { return false ; }
4745+ }
47344746 }
4747+ return true ;
4748+ }
47354749
4736- if (range.second == -1 ) { range.second = slen - 1 ; }
4737- return std::make_pair (range.first ,
4738- static_cast <size_t >(range.second - range.first ) + 1 );
4750+ inline std::pair<size_t , size_t >
4751+ get_range_offset_and_length (Range r, size_t content_length) {
4752+ assert (r.first != -1 && r.second != -1 );
4753+ assert (0 <= r.first && r.first < static_cast <ssize_t >(content_length));
4754+ assert (r.first <= r.second &&
4755+ r.second < static_cast <ssize_t >(content_length));
4756+
4757+ return std::make_pair (r.first , static_cast <size_t >(r.second - r.first ) + 1 );
47394758}
47404759
47414760inline std::string make_content_range_header_field (
47424761 const std::pair<size_t , size_t > &offset_and_length, size_t content_length) {
4743-
47444762 auto st = offset_and_length.first ;
4745- auto ed = (std::min)( st + offset_and_length.second - 1 , content_length - 1 ) ;
4763+ auto ed = st + offset_and_length.second - 1 ;
47464764
47474765 std::string field = " bytes " ;
47484766 field += std::to_string (st);
@@ -4754,11 +4772,11 @@ inline std::string make_content_range_header_field(
47544772}
47554773
47564774template <typename SToken, typename CToken, typename Content>
4757- bool process_multipart_ranges_data (const Request &req, Response &res,
4775+ bool process_multipart_ranges_data (const Request &req,
47584776 const std::string &boundary,
47594777 const std::string &content_type,
4760- SToken stoken, CToken ctoken ,
4761- Content content) {
4778+ size_t content_length, SToken stoken ,
4779+ CToken ctoken, Content content) {
47624780 for (size_t i = 0 ; i < req.ranges .size (); i++) {
47634781 ctoken (" --" );
47644782 stoken (boundary);
@@ -4770,11 +4788,10 @@ bool process_multipart_ranges_data(const Request &req, Response &res,
47704788 }
47714789
47724790 auto offset_and_length =
4773- get_range_offset_and_length (req.ranges [i], res. content_length_ );
4791+ get_range_offset_and_length (req.ranges [i], content_length );
47744792
47754793 ctoken (" Content-Range: " );
4776- stoken (make_content_range_header_field (offset_and_length,
4777- res.content_length_ ));
4794+ stoken (make_content_range_header_field (offset_and_length, content_length));
47784795 ctoken (" \r\n " );
47794796 ctoken (" \r\n " );
47804797
@@ -4791,31 +4808,30 @@ bool process_multipart_ranges_data(const Request &req, Response &res,
47914808 return true ;
47924809}
47934810
4794- inline bool make_multipart_ranges_data (const Request &req, Response &res,
4811+ inline void make_multipart_ranges_data (const Request &req, Response &res,
47954812 const std::string &boundary,
47964813 const std::string &content_type,
4814+ size_t content_length,
47974815 std::string &data) {
4798- return process_multipart_ranges_data (
4799- req, res, boundary, content_type,
4816+ process_multipart_ranges_data (
4817+ req, boundary, content_type, content_length ,
48004818 [&](const std::string &token) { data += token; },
48014819 [&](const std::string &token) { data += token; },
48024820 [&](size_t offset, size_t length) {
4803- if (offset < res.body .size ()) {
4804- data += res.body .substr (offset, length);
4805- return true ;
4806- }
4807- return false ;
4821+ assert (offset + length <= content_length);
4822+ data += res.body .substr (offset, length);
4823+ return true ;
48084824 });
48094825}
48104826
4811- inline size_t
4812- get_multipart_ranges_data_length ( const Request &req, Response &res ,
4813- const std::string &boundary ,
4814- const std::string &content_type ) {
4827+ inline size_t get_multipart_ranges_data_length ( const Request &req,
4828+ const std::string &boundary ,
4829+ const std::string &content_type ,
4830+ size_t content_length ) {
48154831 size_t data_length = 0 ;
48164832
48174833 process_multipart_ranges_data (
4818- req, res, boundary, content_type,
4834+ req, boundary, content_type, content_length ,
48194835 [&](const std::string &token) { data_length += token.size (); },
48204836 [&](const std::string &token) { data_length += token.size (); },
48214837 [&](size_t /* offset*/ , size_t length) {
@@ -4827,13 +4843,13 @@ get_multipart_ranges_data_length(const Request &req, Response &res,
48274843}
48284844
48294845template <typename T>
4830- inline bool write_multipart_ranges_data (Stream &strm, const Request &req,
4831- Response &res,
4832- const std::string &boundary,
4833- const std::string &content_type,
4834- const T &is_shutting_down) {
4846+ inline bool
4847+ write_multipart_ranges_data (Stream &strm, const Request &req, Response &res,
4848+ const std::string &boundary,
4849+ const std::string &content_type,
4850+ size_t content_length, const T &is_shutting_down) {
48354851 return process_multipart_ranges_data (
4836- req, res, boundary, content_type,
4852+ req, boundary, content_type, content_length ,
48374853 [&](const std::string &token) { strm.write (token); },
48384854 [&](const std::string &token) { strm.write (token); },
48394855 [&](size_t offset, size_t length) {
@@ -6012,7 +6028,6 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection,
60126028 if (write_content_with_provider (strm, req, res, boundary, content_type)) {
60136029 res.content_provider_success_ = true ;
60146030 } else {
6015- res.content_provider_success_ = false ;
60166031 ret = false ;
60176032 }
60186033 }
@@ -6045,7 +6060,8 @@ Server::write_content_with_provider(Stream &strm, const Request &req,
60456060 offset_and_length.second , is_shutting_down);
60466061 } else {
60476062 return detail::write_multipart_ranges_data (
6048- strm, req, res, boundary, content_type, is_shutting_down);
6063+ strm, req, res, boundary, content_type, res.content_length_ ,
6064+ is_shutting_down);
60496065 }
60506066 } else {
60516067 if (res.is_chunked_content_provider_ ) {
@@ -6437,14 +6453,14 @@ inline void Server::apply_ranges(const Request &req, Response &res,
64376453 std::string &content_type,
64386454 std::string &boundary) const {
64396455 if (req.ranges .size () > 1 ) {
6440- boundary = detail::make_multipart_data_boundary ();
6441-
64426456 auto it = res.headers .find (" Content-Type" );
64436457 if (it != res.headers .end ()) {
64446458 content_type = it->second ;
64456459 res.headers .erase (it);
64466460 }
64476461
6462+ boundary = detail::make_multipart_data_boundary ();
6463+
64486464 res.set_header (" Content-Type" ,
64496465 " multipart/byteranges; boundary=" + boundary);
64506466 }
@@ -6466,8 +6482,8 @@ inline void Server::apply_ranges(const Request &req, Response &res,
64666482 offset_and_length, res.content_length_ );
64676483 res.set_header (" Content-Range" , content_range);
64686484 } else {
6469- length = detail::get_multipart_ranges_data_length (req, res, boundary,
6470- content_type);
6485+ length = detail::get_multipart_ranges_data_length (
6486+ req, boundary, content_type, res. content_length_ );
64716487 }
64726488 res.set_header (" Content-Length" , std::to_string (length));
64736489 } else {
@@ -6495,21 +6511,13 @@ inline void Server::apply_ranges(const Request &req, Response &res,
64956511 offset_and_length, res.body .size ());
64966512 res.set_header (" Content-Range" , content_range);
64976513
6498- if (offset < res.body .size ()) {
6499- res.body = res.body .substr (offset, length);
6500- } else {
6501- res.body .clear ();
6502- res.status = StatusCode::RangeNotSatisfiable_416;
6503- }
6514+ assert (offset + length <= res.body .size ());
6515+ res.body = res.body .substr (offset, length);
65046516 } else {
65056517 std::string data;
6506- if (detail::make_multipart_ranges_data (req, res, boundary, content_type,
6507- data)) {
6508- res.body .swap (data);
6509- } else {
6510- res.body .clear ();
6511- res.status = StatusCode::RangeNotSatisfiable_416;
6512- }
6518+ detail::make_multipart_ranges_data (req, res, boundary, content_type,
6519+ res.body .size (), data);
6520+ res.body .swap (data);
65136521 }
65146522
65156523 if (type != detail::EncodingType::None) {
@@ -6685,13 +6693,20 @@ Server::process_request(Stream &strm, bool close_connection,
66856693 }
66866694 }
66876695#endif
6688-
66896696 if (routed) {
6690- if (res.status == -1 ) {
6691- res.status = req.ranges .empty () ? StatusCode::OK_200
6692- : StatusCode::PartialContent_206;
6697+ if (detail::normalize_ranges (req, res)) {
6698+ if (res.status == -1 ) {
6699+ res.status = req.ranges .empty () ? StatusCode::OK_200
6700+ : StatusCode::PartialContent_206;
6701+ }
6702+ return write_response_with_content (strm, close_connection, req, res);
6703+ } else {
6704+ res.body .clear ();
6705+ res.content_length_ = 0 ;
6706+ res.content_provider_ = nullptr ;
6707+ res.status = StatusCode::RangeNotSatisfiable_416;
6708+ return write_response (strm, close_connection, req, res);
66936709 }
6694- return write_response_with_content (strm, close_connection, req, res);
66956710 } else {
66966711 if (res.status == -1 ) { res.status = StatusCode::NotFound_404; }
66976712 return write_response (strm, close_connection, req, res);
0 commit comments