diff --git a/src/server/byte_range.cpp b/src/server/byte_range.cpp index be1ddcb97..e43faef1d 100644 --- a/src/server/byte_range.cpp +++ b/src/server/byte_range.cpp @@ -22,6 +22,8 @@ #include "tools/stringTools.h" +#include + namespace kiwix { namespace { @@ -34,7 +36,7 @@ ByteRange parseByteRange(const std::string& rangeStr) if (iss >> start) { if ( start < 0 ) { if ( iss.eof() ) - return ByteRange(ByteRange::PARSED, start, end); + return ByteRange(-start); } else { char c; if (iss >> c && c=='-') { @@ -60,7 +62,37 @@ ByteRange::ByteRange(Kind kind, int64_t first, int64_t last) : kind_(kind) , first_(first) , last_(last) -{} +{ + assert(kind != NONE); + assert(first >= 0); + assert(last >= first); +} + +ByteRange::ByteRange(int64_t suffix_length) + : kind_(PARSED) + , first_(-suffix_length) + , last_(INT64_MAX) +{ + assert(suffix_length > 0); +} + +int64_t ByteRange::first() const +{ + assert(kind_ > PARSED); + return first_; +} + +int64_t ByteRange::last() const +{ + assert(kind_ > PARSED); + return last_; +} + +int64_t ByteRange::length() const +{ + assert(kind_ > PARSED); + return last_ + 1 - first_; +} ByteRange ByteRange::parse(const std::string& rangeStr) { @@ -77,16 +109,16 @@ ByteRange ByteRange::resolve(int64_t contentSize) const return ByteRange(RESOLVED_FULL_CONTENT, 0, contentSize-1); if ( kind() == INVALID ) - return ByteRange(INVALID, 0, contentSize-1); + return ByteRange(RESOLVED_UNSATISFIABLE, 0, contentSize-1); - const int64_t resolved_first = first() < 0 - ? std::max(int64_t(0), contentSize + first()) - : first(); + const int64_t resolved_first = first_ < 0 + ? std::max(int64_t(0), contentSize + first_) + : first_; - const int64_t resolved_last = std::min(contentSize-1, last()); + const int64_t resolved_last = std::min(contentSize-1, last_); if ( resolved_first > resolved_last ) - return ByteRange(INVALID, 0, contentSize-1); + return ByteRange(RESOLVED_UNSATISFIABLE, 0, contentSize-1); return ByteRange(RESOLVED_PARTIAL_CONTENT, resolved_first, resolved_last); } diff --git a/src/server/byte_range.h b/src/server/byte_range.h index 848fd8082..2d1643f5b 100644 --- a/src/server/byte_range.h +++ b/src/server/byte_range.h @@ -29,33 +29,49 @@ namespace kiwix { class ByteRange { public: // types + + // ByteRange is parsed in a request, then it must be resolved (taking + // into account the actual size of the requested resource) before + // being applied in the response. + // The Kind enum represents possible states in such a lifecycle. enum Kind { - // No byte-range was present in the request + // The request is not a range request (no Range header) NONE, - // The value of the Range header is not a valid continuous range. - // Note that a valid (according to RFC7233) sequence of byte ranges is - // considered invalid in this context. + // The value of the Range header is not a valid continuous + // range. Note that a valid (according to RFC7233) sequence of multiple + // byte ranges is considered invalid in the current implementation + // (i.e. only single-range partial requests are supported). INVALID, - // This byte-range has been parsed from request + // This byte-range has been successfully parsed from the request PARSED, - // This is a response to a regular request + // This is a response to a regular (non-range) request RESOLVED_FULL_CONTENT, - // This is a response to a range request - RESOLVED_PARTIAL_CONTENT + // The range request is valid but unsatisfiable + RESOLVED_UNSATISFIABLE, + + // This is a response to a (satisfiable) range request + RESOLVED_PARTIAL_CONTENT, }; public: // functions + // Constructs a ByteRange object of NONE kind ByteRange(); + + // Constructs a ByteRange object of the given kind (except NONE) ByteRange(Kind kind, int64_t first, int64_t last); + // Constructs a ByteRange object of PARSED kind corresponding to a + // range request of the form "Range: bytes=-suffix_length" + explicit ByteRange(int64_t suffix_length); + Kind kind() const { return kind_; } - int64_t first() const { return first_; } - int64_t last() const { return last_; } - int64_t length() const { return last_ + 1 - first_; } + int64_t first() const; + int64_t last() const; + int64_t length() const; static ByteRange parse(const std::string& rangeStr); ByteRange resolve(int64_t contentSize) const; diff --git a/src/server/response.cpp b/src/server/response.cpp index dddc64da9..47050b4cd 100644 --- a/src/server/response.cpp +++ b/src/server/response.cpp @@ -342,7 +342,7 @@ void Response::set_entry(const Entry& entry, const RequestContext& request) { set_content(content); set_compress(true); - } else if ( m_byteRange.kind() == ByteRange::INVALID ) { + } else if ( m_byteRange.kind() == ByteRange::RESOLVED_UNSATISFIABLE ) { set_code(416); set_content(""); m_mode = ResponseMode::ERROR_RESPONSE;