Files
firecgi/request.cc

139 lines
3.0 KiB
C++
Raw Normal View History

2019-05-04 23:42:03 -07:00
#include <sys/uio.h>
#include "request.h"
#include "connection.h"
namespace firecgi {
namespace {
2019-05-18 12:15:11 -07:00
template <class T>
void AppendVec(const T& obj, std::vector<iovec>* vec) {
vec->push_back(iovec{
.iov_base = (void*)(&obj),
.iov_len = sizeof(obj),
});
2019-05-04 23:42:03 -07:00
}
2019-05-18 12:15:11 -07:00
} // namespace
2019-05-04 23:42:03 -07:00
2019-05-18 12:15:11 -07:00
Request::Request(Connection* conn) : conn_(conn), out_buf_(64 * 1024) {}
2019-05-04 23:42:03 -07:00
2019-05-11 21:52:49 -07:00
Request::~Request() {
2019-05-18 12:15:11 -07:00
if (on_close_) {
on_close_();
}
2019-05-11 21:52:49 -07:00
}
void Request::NewRequest(uint16_t request_id) {
2019-05-18 12:15:11 -07:00
if (on_close_) {
on_close_();
}
request_id_ = request_id;
params_.clear();
body_ = {};
on_close_ = nullptr;
out_buf_.Reset();
body_written_ = false;
}
2019-05-18 12:15:11 -07:00
uint16_t Request::RequestId() const { return request_id_; }
2019-05-04 23:42:03 -07:00
2019-05-18 12:15:11 -07:00
void Request::AddParam(const std::string_view& key,
const std::string_view& value) {
params_.try_emplace(key, value);
2019-05-04 23:42:03 -07:00
}
2019-05-18 12:15:11 -07:00
void Request::SetBody(const std::string_view& body) { body_ = body; }
2019-05-04 23:42:03 -07:00
const std::string_view& Request::GetParam(const std::string_view& key) const {
2019-05-18 12:15:11 -07:00
auto iter = params_.find(key);
if (iter == params_.end()) {
static const std::string_view none;
return none;
}
return iter->second;
2019-05-04 23:42:03 -07:00
}
2019-05-18 12:15:11 -07:00
const std::string_view& Request::GetBody() const { return body_; }
2019-05-11 21:52:49 -07:00
void Request::OnClose(const std::function<void()>& on_close) {
2019-05-18 12:15:11 -07:00
on_close_ = on_close;
2019-05-11 21:52:49 -07:00
}
2019-05-18 12:15:11 -07:00
void Request::WriteHeader(const std::string_view& name,
const std::string_view& value) {
std::lock_guard<std::recursive_mutex> l(output_mu_);
2019-05-09 20:24:59 -07:00
2019-05-18 12:15:11 -07:00
CHECK(!body_written_);
CHECK(out_buf_.Write(name));
CHECK(out_buf_.Write(": "));
CHECK(out_buf_.Write(value));
CHECK(out_buf_.Write("\n"));
2019-05-04 23:42:03 -07:00
}
void Request::WriteBody(const std::string_view& body) {
2019-05-18 12:15:11 -07:00
std::lock_guard<std::recursive_mutex> l(output_mu_);
if (!body_written_) {
CHECK(out_buf_.Write("\n"));
body_written_ = true;
}
// TODO: make this able to span multiple packets
CHECK(out_buf_.Write(body));
2019-05-04 23:42:03 -07:00
}
bool Request::Flush() {
2019-05-18 12:15:11 -07:00
std::lock_guard<std::recursive_mutex> l(output_mu_);
2019-05-09 20:24:59 -07:00
2019-05-18 12:15:11 -07:00
std::vector<iovec> vecs;
2019-05-04 23:42:03 -07:00
2019-05-18 12:15:11 -07:00
auto header = OutputHeader();
AppendVec(header, &vecs);
2019-05-04 23:42:03 -07:00
2019-05-18 12:15:11 -07:00
vecs.push_back(OutputVec());
2019-05-04 23:42:03 -07:00
2019-05-18 12:15:11 -07:00
if (!conn_->Write(vecs)) {
return false;
}
out_buf_.Commit();
out_buf_.Consume();
return true;
2019-05-04 23:42:03 -07:00
}
bool Request::End() {
2019-05-18 12:15:11 -07:00
std::lock_guard<std::recursive_mutex> l(output_mu_);
2019-05-09 20:24:59 -07:00
2019-05-18 12:15:11 -07:00
WriteBody("");
2019-05-04 23:42:03 -07:00
2019-05-18 12:15:11 -07:00
std::vector<iovec> vecs;
2019-05-04 23:42:03 -07:00
2019-05-18 12:15:11 -07:00
// Must be outside if block, so it lives through Write() below
auto output_header = OutputHeader();
if (output_header.ContentLength()) {
AppendVec(output_header, &vecs);
vecs.push_back(OutputVec());
}
2019-05-04 23:42:03 -07:00
2019-05-18 12:15:11 -07:00
EndRequest end;
Header end_header(3, request_id_, sizeof(end));
AppendVec(end_header, &vecs);
AppendVec(end, &vecs);
2019-05-04 23:42:03 -07:00
2019-05-18 12:15:11 -07:00
return conn_->Write(vecs);
2019-05-04 23:42:03 -07:00
}
iovec Request::OutputVec() {
2019-05-18 12:15:11 -07:00
const auto output_len = out_buf_.ReadMaxLen();
return iovec{
.iov_base = (void*)(CHECK_NOTNULL(out_buf_.Read(output_len))),
.iov_len = output_len,
};
2019-05-04 23:42:03 -07:00
}
Header Request::OutputHeader() {
2019-05-18 12:15:11 -07:00
return Header(6, request_id_, out_buf_.ReadMaxLen());
2019-05-04 23:42:03 -07:00
}
2019-05-18 12:15:11 -07:00
} // namespace firecgi