Unverified Commit a6c8da47 authored by Dennis Jenkins's avatar Dennis Jenkins Committed by GitHub

Merge pull request #695 from hyperxor/refactoring_in_http

Refactoring in http.h and http.cc
parents 9a0f8984 4099bf12
......@@ -70,6 +70,7 @@ class Message {
public:
friend class Private::HeadersStep;
friend class Private::BodyStep;
friend class ResponseWriter;
Message() = default;
explicit Message(Version version);
......@@ -279,35 +280,18 @@ private:
std::weak_ptr<Tcp::Peer> peer;
};
class ResponseStream : public Message {
class ResponseStream final {
public:
friend class ResponseWriter;
ResponseStream(ResponseStream &&other)
: Message(std::move(other)), peer_(std::move(other.peer_)),
buf_(std::move(other.buf_)), transport_(other.transport_),
timeout_(std::move(other.timeout_)) {}
ResponseStream(ResponseStream &&other);
ResponseStream &operator=(ResponseStream &&other) {
Message::operator=(std::move(other));
peer_ = std::move(other.peer_);
buf_ = std::move(other.buf_);
transport_ = other.transport_;
timeout_ = std::move(other.timeout_);
return *this;
}
ResponseStream &operator=(ResponseStream &&other);
template <typename T>
friend ResponseStream &operator<<(ResponseStream &stream, const T &val);
std::streamsize write(const char *data, std::streamsize sz) {
std::ostream os(&buf_);
os << std::hex << sz << crlf;
os.write(data, sz);
os << crlf;
return sz;
}
std::streamsize write(const char *data, std::streamsize sz);
void flush();
void ends();
......@@ -316,13 +300,9 @@ private:
ResponseStream(Message &&other, std::weak_ptr<Tcp::Peer> peer,
Tcp::Transport *transport, Timeout timeout, size_t streamSize);
std::shared_ptr<Tcp::Peer> peer() const {
if (peer_.expired())
throw std::runtime_error("Write failed: Broken pipe");
return peer_.lock();
}
std::shared_ptr<Tcp::Peer> peer() const;
Message response_;
std::weak_ptr<Tcp::Peer> peer_;
DynamicStreamBuf buf_;
Tcp::Transport *transport_;
......@@ -371,7 +351,7 @@ public:
Response &operator=(Response &&other) = default;
};
class ResponseWriter : public Response {
class ResponseWriter final {
public:
static constexpr size_t DefaultStreamSize = 512;
......@@ -389,26 +369,11 @@ public:
// C++11: std::weak_ptr move constructor is C++14 only so the default
// version of move constructor / assignement operator does not work and we
// have to define it ourself
ResponseWriter(ResponseWriter &&other)
: Response(std::move(other)), peer_(other.peer_),
buf_(std::move(other.buf_)), transport_(other.transport_),
timeout_(std::move(other.timeout_)) {}
ResponseWriter &operator=(ResponseWriter &&other) {
Response::operator=(std::move(other));
peer_ = std::move(other.peer_);
transport_ = other.transport_;
buf_ = std::move(other.buf_);
timeout_ = std::move(other.timeout_);
return *this;
}
ResponseWriter(ResponseWriter &&other);
void setMime(const Mime::MediaType &mime) {
auto ct = headers_.tryGet<Header::ContentType>();
if (ct)
ct->setMime(mime);
else
headers_.add(std::make_shared<Header::ContentType>(mime));
}
ResponseWriter &operator=(ResponseWriter &&other);
void setMime(const Mime::MediaType &mime);
/* @Feature: add helper functions for common http return code:
* - halt() -> 404
......@@ -416,98 +381,53 @@ public:
* - moved() -> 302
*/
Async::Promise<ssize_t>
sendMethodNotAllowed(const std::vector<Http::Method> &supportedMethods) {
code_ = Http::Code::Method_Not_Allowed;
headers_.add(std::make_shared<Http::Header::Allow>(supportedMethods));
std::string body = codeString(Pistache::Http::Code::Method_Not_Allowed);
return putOnWire(body.c_str(), body.size());
}
Async::Promise<ssize_t> send(Code code) {
code_ = code;
return putOnWire(nullptr, 0);
}
Async::Promise<ssize_t>
send(Code code, const std::string &body,
const Mime::MediaType &mime = Mime::MediaType()) {
code_ = code;
if (mime.isValid()) {
auto contentType = headers_.tryGet<Header::ContentType>();
if (contentType)
contentType->setMime(mime);
else
headers_.add(std::make_shared<Header::ContentType>(mime));
}
sendMethodNotAllowed(const std::vector<Http::Method> &supportedMethods);
return putOnWire(body.c_str(), body.size());
}
Async::Promise<ssize_t> send(Code code, const std::string &body = "",
const Mime::MediaType &mime = Mime::MediaType());
template <size_t N>
Async::Promise<ssize_t>
send(Code code, const char (&arr)[N],
const Mime::MediaType &mime = Mime::MediaType()) {
return send(code, arr, N - 1, std::forward<const Mime::MediaType &>(mime));
return sendImpl(code, arr, N - 1, mime);
}
Async::Promise<ssize_t>
send(Code code, const char *data, const size_t size,
const Mime::MediaType &mime = Mime::MediaType()) {
/* @Refactor: code duplication */
code_ = code;
if (mime.isValid()) {
auto contentType = headers_.tryGet<Header::ContentType>();
if (contentType)
contentType->setMime(mime);
else
headers_.add(std::make_shared<Header::ContentType>(mime));
}
Async::Promise<ssize_t> send(Code code, const char *data, const size_t size,
const Mime::MediaType &mime = Mime::MediaType());
return putOnWire(data, size);
}
ResponseStream stream(Code code, size_t streamSize = DefaultStreamSize) {
code_ = code;
return ResponseStream(std::move(*this), peer_, transport_,
std::move(timeout_), streamSize);
}
ResponseStream stream(Code code, size_t streamSize = DefaultStreamSize);
template <typename Duration> void timeoutAfter(Duration duration) {
timeout_.arm(duration);
}
Timeout &timeout() { return timeout_; }
const CookieJar &cookies() const;
CookieJar &cookies();
std::shared_ptr<Tcp::Peer> peer() const {
if (peer_.expired())
throw std::runtime_error("Write failed: Broken pipe");
const Header::Collection &headers() const;
Header::Collection &headers();
return peer_.lock();
}
Timeout &timeout();
std::shared_ptr<Tcp::Peer> peer() const;
// Unsafe API
DynamicStreamBuf *rdbuf() { return &buf_; }
DynamicStreamBuf *rdbuf();
DynamicStreamBuf *rdbuf(DynamicStreamBuf *other) {
UNUSED(other)
throw std::domain_error("Unimplemented");
}
DynamicStreamBuf *rdbuf(DynamicStreamBuf *other);
ResponseWriter clone() const { return ResponseWriter(*this); }
ResponseWriter clone() const;
private:
ResponseWriter(Tcp::Transport *transport, Request request, Handler *handler)
: Response(request.version()), peer_(), buf_(DefaultStreamSize),
transport_(transport),
timeout_(transport, handler, std::move(request)) {}
ResponseWriter(Tcp::Transport *transport, Request request, Handler *handler);
ResponseWriter(const ResponseWriter &other);
ResponseWriter(const ResponseWriter &other)
: Response(other), peer_(other.peer_), buf_(DefaultStreamSize),
transport_(other.transport_), timeout_(other.timeout_) {}
Async::Promise<ssize_t> sendImpl(Code code, const char *data,
const size_t size,
const Mime::MediaType &mime);
template <typename Ptr> void associatePeer(const Ptr &peer) {
if (peer_.use_count() > 0)
......@@ -519,6 +439,7 @@ private:
Async::Promise<ssize_t> putOnWire(const char *data, size_t len);
Response response_;
std::weak_ptr<Tcp::Peer> peer_;
DynamicStreamBuf buf_;
Tcp::Transport *transport_;
......@@ -526,7 +447,7 @@ private:
};
Async::Promise<ssize_t>
serveFile(ResponseWriter &response, const std::string &fileName,
serveFile(ResponseWriter &writer, const std::string &fileName,
const Mime::MediaType &contentType = Mime::MediaType());
namespace Private {
......
......@@ -567,19 +567,24 @@ std::shared_ptr<Tcp::Peer> Request::peer() const {
}
#endif
ResponseStream::ResponseStream(ResponseStream &&other)
: response_(std::move(other.response_)), peer_(std::move(other.peer_)),
buf_(std::move(other.buf_)), transport_(other.transport_),
timeout_(std::move(other.timeout_)) {}
ResponseStream::ResponseStream(Message &&other, std::weak_ptr<Tcp::Peer> peer,
Tcp::Transport *transport, Timeout timeout,
size_t streamSize)
: Message(std::move(other)), peer_(std::move(peer)), buf_(streamSize),
: response_(std::move(other)), peer_(std::move(peer)), buf_(streamSize),
transport_(transport), timeout_(std::move(timeout)) {
if (!writeStatusLine(version_, code_, buf_))
if (!writeStatusLine(response_.version(), response_.code(), buf_))
throw Error("Response exceeded buffer size");
if (!writeCookies(cookies_, buf_)) {
if (!writeCookies(response_.cookies(), buf_)) {
throw Error("Response exceeded buffer size");
}
if (writeHeaders(headers_, buf_)) {
if (writeHeaders(response_.headers(), buf_)) {
std::ostream os(&buf_);
/* @Todo @Major:
* Correctly handle non-keep alive requests
......@@ -595,6 +600,32 @@ ResponseStream::ResponseStream(Message &&other, std::weak_ptr<Tcp::Peer> peer,
}
}
ResponseStream &ResponseStream::operator=(ResponseStream &&other) {
response_ = std::move(other.response_);
peer_ = std::move(other.peer_);
buf_ = std::move(other.buf_);
transport_ = other.transport_;
timeout_ = std::move(other.timeout_);
return *this;
}
std::streamsize ResponseStream::write(const char *data, std::streamsize sz) {
std::ostream os(&buf_);
os << std::hex << sz << crlf;
os.write(data, sz);
os << crlf;
return sz;
}
std::shared_ptr<Tcp::Peer> ResponseStream::peer() const {
if (peer_.expired()) {
throw std::runtime_error("Write failed: Broken pipe");
}
return peer_.lock();
}
void ResponseStream::flush() {
timeout_.disarm();
auto buf = buf_.buffer();
......@@ -617,6 +648,114 @@ void ResponseStream::ends() {
flush();
}
ResponseWriter::ResponseWriter(ResponseWriter &&other)
: response_(std::move(other.response_)), peer_(other.peer_),
buf_(std::move(other.buf_)), transport_(other.transport_),
timeout_(std::move(other.timeout_)) {}
ResponseWriter::ResponseWriter(Tcp::Transport *transport, Request request,
Handler *handler)
: response_(request.version()), peer_(), buf_(DefaultStreamSize),
transport_(transport), timeout_(transport, handler, std::move(request)) {}
ResponseWriter::ResponseWriter(const ResponseWriter &other)
: response_(other.response_), peer_(other.peer_), buf_(DefaultStreamSize),
transport_(other.transport_), timeout_(other.timeout_) {}
ResponseWriter &ResponseWriter::operator=(ResponseWriter &&other) {
response_ = std::move(other.response_);
peer_ = std::move(other.peer_);
transport_ = other.transport_;
buf_ = std::move(other.buf_);
timeout_ = std::move(other.timeout_);
return *this;
}
void ResponseWriter::setMime(const Mime::MediaType &mime) {
auto ct = response_.headers().tryGet<Header::ContentType>();
if (ct) {
ct->setMime(mime);
}
else {
response_.headers().add(std::make_shared<Header::ContentType>(mime));
}
}
Async::Promise<ssize_t> ResponseWriter::sendMethodNotAllowed(
const std::vector<Http::Method> &supportedMethods) {
response_.code_ = Http::Code::Method_Not_Allowed;
response_.headers().add(
std::make_shared<Http::Header::Allow>(supportedMethods));
const std::string &body =
codeString(Pistache::Http::Code::Method_Not_Allowed);
return putOnWire(body.c_str(), body.size());
}
Async::Promise<ssize_t> ResponseWriter::send(Code code, const std::string &body,
const Mime::MediaType &mime) {
return sendImpl(code, body.c_str(), body.size(), mime);
}
Async::Promise<ssize_t> ResponseWriter::send(Code code, const char *data,
const size_t size,
const Mime::MediaType &mime) {
return sendImpl(code, data, size, mime);
}
Async::Promise<ssize_t> ResponseWriter::sendImpl(Code code, const char *data,
const size_t size,
const Mime::MediaType &mime) {
response_.code_ = code;
if (mime.isValid()) {
auto contentType = headers().tryGet<Header::ContentType>();
if (contentType) {
contentType->setMime(mime);
}
else {
headers().add(std::make_shared<Header::ContentType>(mime));
}
}
return putOnWire(data, size);
}
ResponseStream ResponseWriter::stream(Code code, size_t streamSize) {
response_.code_ = code;
return ResponseStream(std::move(response_), peer_, transport_,
std::move(timeout_), streamSize);
}
const CookieJar &ResponseWriter::cookies() const { return response_.cookies(); }
CookieJar &ResponseWriter::cookies() { return response_.cookies(); }
const Header::Collection &ResponseWriter::headers() const {
return response_.headers();
}
Header::Collection &ResponseWriter::headers() { return response_.headers(); }
Timeout &ResponseWriter::timeout() { return timeout_; }
std::shared_ptr<Tcp::Peer> ResponseWriter::peer() const {
if (peer_.expired()) {
throw std::runtime_error("Write failed: Broken pipe");
}
return peer_.lock();
}
DynamicStreamBuf *ResponseWriter::rdbuf() { return &buf_; }
DynamicStreamBuf *ResponseWriter::rdbuf(DynamicStreamBuf *other) {
UNUSED(other)
throw std::domain_error("Unimplemented");
}
ResponseWriter ResponseWriter::clone() const { return ResponseWriter(*this); }
Async::Promise<ssize_t> ResponseWriter::putOnWire(const char *data,
size_t len) {
try {
......@@ -631,9 +770,9 @@ Async::Promise<ssize_t> ResponseWriter::putOnWire(const char *data,
} \
} while (0);
OUT(writeStatusLine(version_, code_, buf_));
OUT(writeHeaders(headers_, buf_));
OUT(writeCookies(cookies_, buf_));
OUT(writeStatusLine(response_.version(), response_.code(), buf_));
OUT(writeHeaders(response_.headers(), buf_));
OUT(writeCookies(response_.cookies(), buf_));
/* @Todo @Major:
* Correctly handle non-keep alive requests
......@@ -676,7 +815,7 @@ Async::Promise<ssize_t> ResponseWriter::putOnWire(const char *data,
}
}
Async::Promise<ssize_t> serveFile(ResponseWriter &response,
Async::Promise<ssize_t> serveFile(ResponseWriter &writer,
const std::string &fileName,
const Mime::MediaType &contentType) {
struct stat sb;
......@@ -702,7 +841,7 @@ Async::Promise<ssize_t> serveFile(ResponseWriter &response,
throw HttpError(Code::Internal_Server_Error, "");
}
auto *buf = response.rdbuf();
auto *buf = writer.rdbuf();
std::ostream os(buf);
......@@ -716,7 +855,7 @@ Async::Promise<ssize_t> serveFile(ResponseWriter &response,
} while (0);
auto setContentType = [&](const Mime::MediaType &contentType) {
auto &headers = response.headers();
auto &headers = writer.headers();
auto ct = headers.tryGet<Header::ContentType>();
if (ct)
ct->setMime(contentType);
......@@ -724,7 +863,7 @@ Async::Promise<ssize_t> serveFile(ResponseWriter &response,
headers.add<Header::ContentType>(contentType);
};
OUT(writeStatusLine(response.version(), Http::Code::Ok, *buf));
OUT(writeStatusLine(writer.response_.version(), Http::Code::Ok, *buf));
if (contentType.isValid()) {
setContentType(contentType);
} else {
......@@ -733,7 +872,7 @@ Async::Promise<ssize_t> serveFile(ResponseWriter &response,
setContentType(mime);
}
OUT(writeHeaders(response.headers(), *buf));
OUT(writeHeaders(writer.headers(), *buf));
const size_t len = sb.st_size;
......@@ -741,8 +880,8 @@ Async::Promise<ssize_t> serveFile(ResponseWriter &response,
OUT(os << crlf);
auto *transport = response.transport_;
auto peer = response.peer();
auto *transport = writer.transport_;
auto peer = writer.peer();
auto sockFd = peer->fd();
auto buffer = buf->buffer();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment