mirror of
https://github.com/yhirose/cpp-httplib
synced 2024-11-21 14:29:10 -07:00
Use memory mapped file for static file server (#1632)
* Use memory mapped file for static file server * Fix build error
This commit is contained in:
parent
6bb580cda8
commit
44c62d838e
1 changed files with 118 additions and 18 deletions
136
httplib.h
136
httplib.h
|
@ -90,10 +90,6 @@
|
|||
#define CPPHTTPLIB_RECV_BUFSIZ size_t(4096u)
|
||||
#endif
|
||||
|
||||
#ifndef CPPHTTPLIB_SEND_BUFSIZ
|
||||
#define CPPHTTPLIB_SEND_BUFSIZ size_t(4096u)
|
||||
#endif
|
||||
|
||||
#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ
|
||||
#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(16384u)
|
||||
#endif
|
||||
|
@ -197,6 +193,7 @@ using socket_t = SOCKET;
|
|||
#endif
|
||||
#include <csignal>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
@ -2148,6 +2145,29 @@ private:
|
|||
std::string glowable_buffer_;
|
||||
};
|
||||
|
||||
class mmap {
|
||||
public:
|
||||
mmap(const char *path);
|
||||
~mmap();
|
||||
|
||||
bool open(const char *path);
|
||||
void close();
|
||||
|
||||
bool is_open() const;
|
||||
size_t size() const;
|
||||
const char *data() const;
|
||||
|
||||
private:
|
||||
#if defined(_WIN32)
|
||||
HANDLE hFile_;
|
||||
HANDLE hMapping_;
|
||||
#else
|
||||
int fd_;
|
||||
#endif
|
||||
size_t size_;
|
||||
void *addr_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -2528,6 +2548,95 @@ inline void stream_line_reader::append(char c) {
|
|||
}
|
||||
}
|
||||
|
||||
inline mmap::mmap(const char *path)
|
||||
#if defined(_WIN32)
|
||||
: hFile_(NULL), hMapping_(NULL)
|
||||
#else
|
||||
: fd_(-1)
|
||||
#endif
|
||||
,
|
||||
size_(0), addr_(nullptr) {
|
||||
if (!open(path)) { std::runtime_error(""); }
|
||||
}
|
||||
|
||||
inline mmap::~mmap() { close(); }
|
||||
|
||||
inline bool mmap::open(const char *path) {
|
||||
close();
|
||||
|
||||
#if defined(_WIN32)
|
||||
hFile_ = ::CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hFile_ == INVALID_HANDLE_VALUE) { return false; }
|
||||
|
||||
size_ = ::GetFileSize(hFile_, NULL);
|
||||
|
||||
hMapping_ = ::CreateFileMapping(hFile_, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
|
||||
if (hMapping_ == NULL) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
addr_ = ::MapViewOfFile(hMapping_, FILE_MAP_READ, 0, 0, 0);
|
||||
#else
|
||||
fd_ = ::open(path, O_RDONLY);
|
||||
if (fd_ == -1) { return false; }
|
||||
|
||||
struct stat sb;
|
||||
if (fstat(fd_, &sb) == -1) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
size_ = static_cast<size_t>(sb.st_size);
|
||||
|
||||
addr_ = ::mmap(NULL, size_, PROT_READ, MAP_PRIVATE, fd_, 0);
|
||||
#endif
|
||||
|
||||
if (addr_ == nullptr) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool mmap::is_open() const { return addr_ != nullptr; }
|
||||
|
||||
inline size_t mmap::size() const { return size_; }
|
||||
|
||||
inline const char *mmap::data() const { return (const char *)addr_; }
|
||||
|
||||
inline void mmap::close() {
|
||||
#if defined(_WIN32)
|
||||
if (addr_) {
|
||||
::UnmapViewOfFile(addr_);
|
||||
addr_ = nullptr;
|
||||
}
|
||||
|
||||
if (hMapping_) {
|
||||
::CloseHandle(hMapping_);
|
||||
hMapping_ = NULL;
|
||||
}
|
||||
|
||||
if (hFile_ != INVALID_HANDLE_VALUE) {
|
||||
::CloseHandle(hFile_);
|
||||
hFile_ = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
#else
|
||||
if (addr_ != nullptr) {
|
||||
munmap(addr_, size_);
|
||||
addr_ = nullptr;
|
||||
}
|
||||
|
||||
if (fd_ != -1) {
|
||||
::close(fd_);
|
||||
fd_ = -1;
|
||||
}
|
||||
#endif
|
||||
size_ = 0;
|
||||
}
|
||||
inline int close_socket(socket_t sock) {
|
||||
#ifdef _WIN32
|
||||
return closesocket(sock);
|
||||
|
@ -5963,24 +6072,15 @@ inline bool Server::handle_file_request(const Request &req, Response &res,
|
|||
res.set_header(kv.first.c_str(), kv.second);
|
||||
}
|
||||
|
||||
auto fs =
|
||||
std::make_shared<std::ifstream>(path, std::ios_base::binary);
|
||||
|
||||
fs->seekg(0, std::ios_base::end);
|
||||
auto size = static_cast<size_t>(fs->tellg());
|
||||
fs->seekg(0);
|
||||
auto mm = std::make_shared<detail::mmap>(path.c_str());
|
||||
if (!mm->is_open()) { return false; }
|
||||
|
||||
res.set_content_provider(
|
||||
size,
|
||||
mm->size(),
|
||||
detail::find_content_type(path, file_extension_and_mimetype_map_,
|
||||
default_file_mimetype_),
|
||||
[fs](size_t offset, size_t length, DataSink &sink) -> bool {
|
||||
std::array<char, CPPHTTPLIB_SEND_BUFSIZ> buf{};
|
||||
length = std::min(length, CPPHTTPLIB_SEND_BUFSIZ);
|
||||
|
||||
fs->seekg(static_cast<std::streamsize>(offset), std::ios_base::beg);
|
||||
fs->read(buf.data(), static_cast<std::streamsize>(length));
|
||||
sink.write(buf.data(), length);
|
||||
[mm](size_t offset, size_t length, DataSink &sink) -> bool {
|
||||
sink.write(mm->data() + offset, length);
|
||||
return true;
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue