diff options
author | randomdan <randomdan@localhost> | 2014-03-20 23:49:45 +0000 |
---|---|---|
committer | randomdan <randomdan@localhost> | 2014-03-20 23:49:45 +0000 |
commit | a9523a398c57733cde6b736c14129288095491fa (patch) | |
tree | c634070b88a1832c8bfb6945570778e7719c1b01 /project2/cgi | |
parent | Add a stream presenter, allows output of any source stream (diff) | |
download | project2-a9523a398c57733cde6b736c14129288095491fa.tar.bz2 project2-a9523a398c57733cde6b736c14129288095491fa.tar.xz project2-a9523a398c57733cde6b736c14129288095491fa.zip |
Support range requests and seekable streams
Untangle streams/streamPresenter/writableContent
Pass the ExecContext into more bits of content interface
Diffstat (limited to 'project2/cgi')
-rw-r--r-- | project2/cgi/cgiRequestContext.cpp | 24 | ||||
-rw-r--r-- | project2/cgi/cgiRequestContext.h | 2 | ||||
-rw-r--r-- | project2/cgi/cgiResultWritable.cpp | 26 | ||||
-rw-r--r-- | project2/cgi/testCgi.cpp | 1 |
4 files changed, 52 insertions, 1 deletions
diff --git a/project2/cgi/cgiRequestContext.cpp b/project2/cgi/cgiRequestContext.cpp index d38a256..2827aa7 100644 --- a/project2/cgi/cgiRequestContext.cpp +++ b/project2/cgi/cgiRequestContext.cpp @@ -8,6 +8,7 @@ #include <map> #include <cgicc/Cgicc.h> #include <curl/curl.h> +#include <boost/lexical_cast.hpp> #include <boost/uuid/uuid_io.hpp> #include <boost/uuid/uuid_generators.hpp> @@ -120,3 +121,26 @@ CgiRequestContext::getParameter(const VariableType & p) const return cgi(p); } +boost::optional<RangeRequest> +CgiRequestContext::getRequestRange() const +{ + const auto r = cgienv.getenv("HTTP_RANGE"); + std::vector<std::string> rangeParts; + boost::split(rangeParts, r, boost::is_any_of("=-"), boost::algorithm::token_compress_off); + + if (rangeParts.size() < 3 || (rangeParts[1].empty() && rangeParts[2].empty())) { + return boost::optional<RangeRequest>(); + } + RangeRequest range; + range.Unit = rangeParts[0]; + + if (!rangeParts[1].empty()) { + range.Start = boost::lexical_cast<RangePos>(rangeParts[1]); + } + if (!rangeParts[2].empty()) { + range.End = boost::lexical_cast<RangePos>(rangeParts[2]); + } + + return range; +} + diff --git a/project2/cgi/cgiRequestContext.h b/project2/cgi/cgiRequestContext.h index 57c233d..9501a20 100644 --- a/project2/cgi/cgiRequestContext.h +++ b/project2/cgi/cgiRequestContext.h @@ -6,6 +6,7 @@ #include "cgiEnvInput.h" #include "cgiRouter.h" #include "execContext.h" +#include <range.h> #include <cgicc/CgiEnvironment.h> #include <cgicc/Cgicc.h> #include <lazyPointer.h> @@ -40,6 +41,7 @@ class CgiRequestContext : public ExecContext { ETags getRequestETags() const; time_t getRequestModifiedSince() const; std::string getCookieValue(const std::string & name) const; + boost::optional<RangeRequest> getRequestRange() const; LazyPointer<Router> router; boost::posix_time::ptime startTime; diff --git a/project2/cgi/cgiResultWritable.cpp b/project2/cgi/cgiResultWritable.cpp index 357a57c..1364456 100644 --- a/project2/cgi/cgiResultWritable.cpp +++ b/project2/cgi/cgiResultWritable.cpp @@ -4,8 +4,32 @@ class WritableToCgiResult : public TransformImpl<WritableContent, CgiResult> { public: void transform(const WritableContent * wc, CgiResult * cr, ExecContext * ec) const { - cr->header->addHeader("Content-Type", Glib::ustring::compose("%1; charset=%2", wc->getContentType(), cr->encoding)); + cr->header->addHeader("Content-Type", Glib::ustring::compose("%1; charset=%2", wc->getContentType(ec), cr->encoding)); cr->header->addHeader("Cache-control", "no-cache"); + auto size = wc->getSizeInBytes(ec); + if (size) { + auto range = wc->getRange(ec); + if (range) { + cr->header->addHeader("Status", "206 Partial Content"); + cr->header->addHeader("Content-Length", Glib::ustring::compose("%1", range->End - range->Start + 1)); + cr->header->addHeader("Content-Range", Glib::ustring::compose("%1 %2-%3/%4", + range->Unit, range->Start, range->End, *size)); + } + else { + cr->header->addHeader("Content-Length", Glib::ustring::compose("%1", *size)); + } + } + if (wc->isSeekable()) { + cr->header->addHeader("Accept-Ranges", "bytes"); + } + auto modifiedTime = wc->getModifiedTime(ec); + if (modifiedTime) { + char buf[100]; + struct tm stm; + gmtime_r(&*modifiedTime, &stm); + strftime(buf, sizeof(buf), "%a, %d %b %Y %T %z", &stm); + cr->header->addHeader("Last-Modified", buf); + } cr->header->render(cr->stream); wc->writeTo(cr->stream, cr->encoding, ec); } diff --git a/project2/cgi/testCgi.cpp b/project2/cgi/testCgi.cpp index 6644102..0c2b472 100644 --- a/project2/cgi/testCgi.cpp +++ b/project2/cgi/testCgi.cpp @@ -125,6 +125,7 @@ TESTOPT("HTTP_REFERER", "", "Referrer") TESTOPT("HTTP_COOKIE", "", "Cookie") TESTOPT("HTTPS", "No", "HTTPS?") TESTOPT("HTTP_IF_MODIFIED_SINCE", "", "Client cached copy timestamp") +TESTOPT("HTTP_RANGE", "", "Range requested by client '{unit}=[start]-[end]'") ("urlListFile", Options::value(&urlListFile, ""), "Load URL list from this file") ("runCount", Options::value(&runCount, 1), "Repeat run this many times") ("help", ShowHelpComponent::Option(), "Print usage and exit")("h") |