From 29054d42a01f1d897ce2c52c3b8f4cc523863f5b Mon Sep 17 00:00:00 2001 From: Scott Lamb Date: Sat, 9 Jan 2016 23:26:02 -0800 Subject: [PATCH] A few types of FileSlice useful for mp4 building. --- src/http.cc | 63 +++++++++++++++++++++++++++++++++++++---------------- src/http.h | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 19 deletions(-) diff --git a/src/http.cc b/src/http.cc index c6aeb68..6afe1f4 100644 --- a/src/http.cc +++ b/src/http.cc @@ -58,41 +58,31 @@ class RealFile : public VirtualFile { public: RealFile(re2::StringPiece mime_type, re2::StringPiece filename, const struct stat &statbuf) - : mime_type_(mime_type.as_string()), - filename_(filename.as_string()), - stat_(statbuf) {} + : mime_type_(mime_type.as_string()), stat_(statbuf) { + slice_.Init(filename, ByteRange(0, statbuf.st_size)); + } + ~RealFile() final {} int64_t size() const final { return stat_.st_size; } time_t last_modified() const final { return stat_.st_mtime; } + std::string mime_type() const final { return mime_type_; } + std::string filename() const final { return slice_.filename(); } + std::string etag() const final { return StrCat("\"", stat_.st_ino, ":", stat_.st_size, ":", stat_.st_mtim.tv_sec, ":", stat_.st_mtim.tv_nsec, "\""); } - std::string mime_type() const final { return mime_type_; } - std::string filename() const final { return filename_; } // Add the given range of the file to the buffer. bool AddRange(ByteRange range, EvBuffer *buf, std::string *error_message) const final { - int fd = open(filename_.c_str(), O_RDONLY); - if (fd < 0) { - int err = errno; - *error_message = StrCat("open: ", strerror(err)); - return false; - } - if (!buf->AddFile(fd, range.begin, range.end - range.begin, - error_message)) { - close(fd); - return false; - } - // |buf| now owns |fd|. - return true; + return slice_.AddRange(range, buf, error_message); } private: + RealFileSlice slice_; const std::string mime_type_; - const std::string filename_; const struct stat stat_; }; @@ -202,6 +192,28 @@ bool EvBuffer::AddFile(int fd, ev_off_t offset, ev_off_t length, return true; } +void RealFileSlice::Init(re2::StringPiece filename, ByteRange range) { + filename_ = filename.as_string(); + range_ = range; +} + +bool RealFileSlice::AddRange(ByteRange range, EvBuffer *buf, + std::string *error_message) const { + int fd = open(filename_.c_str(), O_RDONLY); + if (fd < 0) { + int err = errno; + *error_message = StrCat("open: ", strerror(err)); + return false; + } + if (!buf->AddFile(fd, range_.begin + range.begin, range.size(), + error_message)) { + close(fd); + return false; + } + // |buf| now owns |fd|. + return true; +} + bool FillerFileSlice::AddRange(ByteRange range, EvBuffer *buf, std::string *error_message) const { std::unique_ptr s(new std::string); @@ -222,6 +234,19 @@ bool FillerFileSlice::AddRange(ByteRange range, EvBuffer *buf, return true; } +bool StaticStringPieceSlice::AddRange(ByteRange range, EvBuffer *buf, + std::string *error_message) const { + buf->AddReference(piece_.data() + range.begin, range.size(), nullptr, + nullptr); + return true; +} + +bool CopyingStringPieceSlice::AddRange(ByteRange range, EvBuffer *buf, + std::string *error_message) const { + buf->Add(re2::StringPiece(piece_.data() + range.begin, range.size())); + return true; +} + bool FileSlices::AddRange(ByteRange range, EvBuffer *buf, std::string *error_message) const { if (range.begin < 0 || range.begin > range.end || range.end > size_) { diff --git a/src/http.h b/src/http.h index 3088f7f..32bf0e6 100644 --- a/src/http.h +++ b/src/http.h @@ -134,6 +134,22 @@ class VirtualFile : public FileSlice { virtual std::string filename() const = 0; // for logging. }; +class RealFileSlice : public FileSlice { + public: + void Init(re2::StringPiece filename, ByteRange range); + + const std::string filename() const { return filename_; } + + int64_t size() const final { return range_.size(); } + + bool AddRange(ByteRange range, EvBuffer *buf, + std::string *error_message) const final; + + private: + std::string filename_; + ByteRange range_; +}; + // A FileSlice of a pre-defined length which calls a function which fills the // slice on demand. The FillerFileSlice is responsible for subsetting. class FillerFileSlice : public FileSlice { @@ -156,6 +172,32 @@ class FillerFileSlice : public FileSlice { size_t size_; }; +// A FileSlice backed by in-memory data which lives forever (static data). +class StaticStringPieceSlice : public FileSlice { + public: + explicit StaticStringPieceSlice(re2::StringPiece piece) : piece_(piece) {} + + int64_t size() const final { return piece_.size(); } + bool AddRange(ByteRange range, EvBuffer *buf, + std::string *error_message) const final; + + private: + re2::StringPiece piece_; +}; + +// A FileSlice backed by in-memory data which should be copied. +class CopyingStringPieceSlice : public FileSlice { + public: + explicit CopyingStringPieceSlice(re2::StringPiece piece) : piece_(piece) {} + + int64_t size() const final { return piece_.size(); } + bool AddRange(ByteRange range, EvBuffer *buf, + std::string *error_message) const final; + + private: + re2::StringPiece piece_; +}; + // A slice composed of other slices. class FileSlices : public FileSlice { public: