#include
#include
#include "response.h"
#include "config.h"
#include "readable_string_stream.h"
#include "chunked_response_stream.h"
#include "gzip_response_stream.h"
const std::string rs::httpserver::Response::emptyValue_;
const std::string rs::httpserver::Response::keepAliveHeaderValue_ = std::string("timeout=") + boost::lexical_cast<:string>(Config::KeepAliveTimeout);
void rs::httpserver::Response::Send() {
getResponseStream().Flush();
}
void rs::httpserver::Response::Send(const std::string& data) {
ReadableStringStream stream(data);
setContentLength(data.length()).Send(stream);
}
void rs::httpserver::Response::Send(Stream& inStream) {
auto& responseStream = getResponseStream();
Stream::Copy(inStream, responseStream);
responseStream.Flush();
}
void rs::httpserver::Response::Send(std::iostream& inStream) {
auto& responseStream = getResponseStream();
Stream::Copy(inStream, responseStream);
responseStream.Flush();
}
void rs::httpserver::Response::SendContinue(bool kontinue) {
if (socketBytesSentContinue_ > 0) {
throw MultipleContinueResponseException{};
}
const char* header = "HTTP/1.1 100 Continue\r\n\r\n";
if (!kontinue) {
header = "HTTP/1.1 417 Expectation Failed\r\nContent-Length: 0\r\n\r\n";
}
socketBytesSentContinue_ = std::strlen(header);
socket_->Send(reinterpret_cast(header), socketBytesSentContinue_);
}
rs::httpserver::Stream& rs::httpserver::Response::getResponseStream() {
if (HasResponded()) {
throw MultipleResponseException{};
}
if (!request_->IsHttp10() && !HasContentLength() && statusCode_ != 304) {
headers_[Headers::TransferEncoding] = "chunked";
if (compress_) {
headers_[Headers::ContentEncoding] = "gzip";
}
}
std::stringstream headers;
SerializeHeaders(headers);
socket_->Send(headers.str());
if (!request_->IsHead()) {
if (IsChunkEncoded()) {
if (compress_) {
return zStream_;
} else {
return chunkedStream_;
}
} else {
return responseStream_;
}
} else {
return nullStream_;
}
}
rs::httpserver::MultipartResponseStream& rs::httpserver::Response::getMultiResponseStream() {
if (multiStream_.getPartCount() == 0) {
if (HasResponded()) {
throw MultipleResponseException{};
}
headers_.erase(Headers::ContentLength);
forceClose_ = true;
headers_[Headers::ContentType] = (boost::format("multipart/related; boundary=\"%1%\"") % MultipartResponseStream::boundary).str();
std::stringstream headers;
SerializeHeaders(headers);
socket_->Send(headers.str());
}
return multiStream_;
}
rs::httpserver::Response& rs::httpserver::Response::setETag(const std::string& etag) {
if (etag.length() > 1 && etag[0] != '"' && etag[etag.length() - 1] != '"') {
std::string value = '"' + etag + '"';
return setHeader(Headers::ETag, value);
} else {
return setHeader(Headers::ETag, etag);
}
}
rs::httpserver::Response& rs::httpserver::Response::setLastModified(const std::string& lastModifiedTime) {
return setHeader(Headers::LastModified, lastModifiedTime);
}
rs::httpserver::Response& rs::httpserver::Response::setLastModified(std::time_t lastModifiedTime) {
auto formattedTime = Response::FormatLastModifiedTime(lastModifiedTime);
return setHeader(Headers::LastModified, formattedTime);
}
rs::httpserver::Response& rs::httpserver::Response::setNoCache() {
return setHeader(Headers::Pragma, "no-cache").
setHeader(Headers::CacheControl, "max-age=0, no-cache, no-store").
setHeader(Headers::LastModified, "Mon, 1 Jan 1990 00:00:00 GMT").
setHeader(Headers::ETag, emptyValue_);
}
rs::httpserver::Response& rs::httpserver::Response::setContentRange(const std::string& range) {
return setHeader(rs::httpserver::Headers::ContentRange, range);
}
std::string rs::httpserver::Response::FormatLastModifiedTime(std::time_t lastModifiedTime) {
auto ptime = boost::posix_time::from_time_t(lastModifiedTime);
auto date = ptime.date();
auto time = ptime.time_of_day();
auto formattedTime = boost::format("%1%, %2% %3% %4% %|5$02d|:%|6$02d|:%|7$02d| GMT") %
date.day_of_week().as_short_string() %
date.day() % date.month().as_short_string() % date.year() %
time.hours() % time.minutes() % time.seconds();
return formattedTime.str();
}
void rs::httpserver::Response::Redirect(const std::string& location) {
ResetHeaders();
if (request_->getHeaders()->getVersion() == Headers::Http10) {
setStatusCode(302);
setStatusDescription("Found");
} else {
setStatusCode(307);
setStatusDescription("Temporary Redirect");
}
setHeader(Headers::Location, location);
Send();
}
void rs::httpserver::Response::SerializeHeaders(std::stringstream& sout) {
if (request_->IsHttp10()) {
version_ = Headers::Http10;
headers_[Headers::Connection] = "close";
headers_.erase(Headers::KeepAlive);
headers_.erase(Headers::TransferEncoding);
} else if (!forceClose_ && request_->IsKeepAlive()) {
headers_[Headers::Connection] = "keep-alive";
headers_[Headers::KeepAlive] = keepAliveHeaderValue_;
} else {
headers_[Headers::Connection] = "close";
headers_.erase(Headers::KeepAlive);
}
if (statusCode_ == 200) {
statusDescription_ = "OK";
}
sout << version_ << " " << statusCode_;
if (statusDescription_.length() > 0) {
sout << " " << statusDescription_;
}
sout << "\r\n";
for (auto i : headers_) {
sout << i.first << ": " << i.second << "\r\n";
}
sout << "\r\n";
}