summaryrefslogtreecommitdiff
path: root/project2/cgi
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2014-03-20 23:49:45 +0000
committerrandomdan <randomdan@localhost>2014-03-20 23:49:45 +0000
commita9523a398c57733cde6b736c14129288095491fa (patch)
treec634070b88a1832c8bfb6945570778e7719c1b01 /project2/cgi
parentAdd a stream presenter, allows output of any source stream (diff)
downloadproject2-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.cpp24
-rw-r--r--project2/cgi/cgiRequestContext.h2
-rw-r--r--project2/cgi/cgiResultWritable.cpp26
-rw-r--r--project2/cgi/testCgi.cpp1
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")