9090#define CPPHTTPLIB_RECV_BUFSIZ size_t (4096u )
9191#endif
9292
93+ #ifndef CPPHTTPLIB_SEND_BUFSIZ
94+ #define CPPHTTPLIB_SEND_BUFSIZ size_t (4096u )
95+ #endif
96+
9397#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ
9498#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t (16384u )
9599#endif
@@ -784,6 +788,7 @@ class Server {
784788 bool remove_mount_point (const std::string &mount_point);
785789 Server &set_file_extension_and_mimetype_mapping (const std::string &ext,
786790 const std::string &mime);
791+ Server &set_default_file_mimetype (const std::string &mime);
787792 Server &set_file_request_handler (Handler handler);
788793
789794 Server &set_error_handler (HandlerWithResponse handler);
@@ -907,6 +912,7 @@ class Server {
907912 };
908913 std::vector<MountPointEntry> base_dirs_;
909914 std::map<std::string, std::string> file_extension_and_mimetype_map_;
915+ std::string default_file_mimetype_ = " application/octet-stream" ;
910916 Handler file_request_handler_;
911917
912918 Handlers get_handlers_;
@@ -3197,9 +3203,10 @@ inline constexpr unsigned int operator"" _t(const char *s, size_t l) {
31973203
31983204} // namespace udl
31993205
3200- inline const char *
3206+ inline std::string
32013207find_content_type (const std::string &path,
3202- const std::map<std::string, std::string> &user_data) {
3208+ const std::map<std::string, std::string> &user_data,
3209+ const std::string &default_content_type) {
32033210 auto ext = file_extension (path);
32043211
32053212 auto it = user_data.find (ext);
@@ -3208,7 +3215,8 @@ find_content_type(const std::string &path,
32083215 using udl::operator " " _t;
32093216
32103217 switch (str2tag (ext)) {
3211- default : return nullptr ;
3218+ default : return default_content_type;
3219+
32123220 case " css" _t: return " text/css" ;
32133221 case " csv" _t: return " text/csv" ;
32143222 case " htm" _t:
@@ -4489,12 +4497,13 @@ get_range_offset_and_length(const Request &req, size_t content_length,
44894497 return std::make_pair (r.first , static_cast <size_t >(r.second - r.first ) + 1 );
44904498}
44914499
4492- inline std::string make_content_range_header_field (size_t offset, size_t length,
4493- size_t content_length) {
4500+ inline std::string
4501+ make_content_range_header_field (const std::pair<ssize_t , ssize_t > &range,
4502+ size_t content_length) {
44944503 std::string field = " bytes " ;
4495- field += std::to_string (offset);
4504+ if (range. first != - 1 ) { field += std::to_string (range. first ); }
44964505 field += " -" ;
4497- field += std::to_string (offset + length - 1 );
4506+ if (range. second != - 1 ) { field += std::to_string (range. second ); }
44984507 field += " /" ;
44994508 field += std::to_string (content_length);
45004509 return field;
@@ -4516,14 +4525,15 @@ bool process_multipart_ranges_data(const Request &req, Response &res,
45164525 ctoken (" \r\n " );
45174526 }
45184527
4519- auto offsets = get_range_offset_and_length (req, res.body .size (), i);
4520- auto offset = offsets.first ;
4521- auto length = offsets.second ;
4522-
45234528 ctoken (" Content-Range: " );
4524- stoken (make_content_range_header_field (offset, length, res.body .size ()));
4529+ const auto &range = req.ranges [i];
4530+ stoken (make_content_range_header_field (range, res.content_length_ ));
45254531 ctoken (" \r\n " );
45264532 ctoken (" \r\n " );
4533+
4534+ auto offsets = get_range_offset_and_length (req, res.content_length_ , i);
4535+ auto offset = offsets.first ;
4536+ auto length = offsets.second ;
45274537 if (!content (offset, length)) { return false ; }
45284538 ctoken (" \r\n " );
45294539 }
@@ -5493,6 +5503,11 @@ Server::set_file_extension_and_mimetype_mapping(const std::string &ext,
54935503 return *this ;
54945504}
54955505
5506+ inline Server &Server::set_default_file_mimetype (const std::string &mime) {
5507+ default_file_mimetype_ = mime;
5508+ return *this ;
5509+ }
5510+
54965511inline Server &Server::set_file_request_handler (Handler handler) {
54975512 file_request_handler_ = std::move (handler);
54985513 return *this ;
@@ -5944,17 +5959,35 @@ inline bool Server::handle_file_request(const Request &req, Response &res,
59445959 if (path.back () == ' /' ) { path += " index.html" ; }
59455960
59465961 if (detail::is_file (path)) {
5947- detail::read_file (path, res.body );
5948- auto type =
5949- detail::find_content_type (path, file_extension_and_mimetype_map_);
5950- if (type) { res.set_header (" Content-Type" , type); }
59515962 for (const auto &kv : entry.headers ) {
59525963 res.set_header (kv.first .c_str (), kv.second );
59535964 }
5954- res.status = req.has_header (" Range" ) ? 206 : 200 ;
5965+
5966+ auto fs =
5967+ std::make_shared<std::ifstream>(path, std::ios_base::binary);
5968+
5969+ fs->seekg (0 , std::ios_base::end);
5970+ auto size = static_cast <size_t >(fs->tellg ());
5971+ fs->seekg (0 );
5972+
5973+ res.set_content_provider (
5974+ size,
5975+ detail::find_content_type (path, file_extension_and_mimetype_map_,
5976+ default_file_mimetype_),
5977+ [fs](size_t offset, size_t length, DataSink &sink) -> bool {
5978+ std::array<char , CPPHTTPLIB_SEND_BUFSIZ> buf{};
5979+ length = std::min (length, CPPHTTPLIB_SEND_BUFSIZ);
5980+
5981+ fs->seekg (static_cast <std::streamsize>(offset), std::ios_base::beg);
5982+ fs->read (buf.data (), static_cast <std::streamsize>(length));
5983+ sink.write (buf.data (), length);
5984+ return true ;
5985+ });
5986+
59555987 if (!head && file_request_handler_) {
59565988 file_request_handler_ (req, res);
59575989 }
5990+
59585991 return true ;
59595992 }
59605993 }
@@ -6202,10 +6235,10 @@ inline void Server::apply_ranges(const Request &req, Response &res,
62026235 } else if (req.ranges .size () == 1 ) {
62036236 auto offsets =
62046237 detail::get_range_offset_and_length (req, res.content_length_ , 0 );
6205- auto offset = offsets.first ;
62066238 length = offsets.second ;
6239+
62076240 auto content_range = detail::make_content_range_header_field (
6208- offset, length , res.content_length_ );
6241+ req. ranges [ 0 ] , res.content_length_ );
62096242 res.set_header (" Content-Range" , content_range);
62106243 } else {
62116244 length = detail::get_multipart_ranges_data_length (req, res, boundary,
@@ -6228,13 +6261,15 @@ inline void Server::apply_ranges(const Request &req, Response &res,
62286261 if (req.ranges .empty ()) {
62296262 ;
62306263 } else if (req.ranges .size () == 1 ) {
6264+ auto content_range = detail::make_content_range_header_field (
6265+ req.ranges [0 ], res.body .size ());
6266+ res.set_header (" Content-Range" , content_range);
6267+
62316268 auto offsets =
62326269 detail::get_range_offset_and_length (req, res.body .size (), 0 );
62336270 auto offset = offsets.first ;
62346271 auto length = offsets.second ;
6235- auto content_range = detail::make_content_range_header_field (
6236- offset, length, res.body .size ());
6237- res.set_header (" Content-Range" , content_range);
6272+
62386273 if (offset < res.body .size ()) {
62396274 res.body = res.body .substr (offset, length);
62406275 } else {
0 commit comments