Files
mirall/fastcgi_request.cc

108 lines
2.4 KiB
C++
Raw Normal View History

2019-04-28 06:47:30 +00:00
#include <sys/uio.h>
#include "fastcgi_request.h"
2019-04-28 18:19:32 +00:00
#include "fastcgi_conn.h"
2019-04-28 18:51:56 +00:00
namespace {
template<class T> void AppendVec(const T& obj, std::vector<iovec>* vec) {
vec->push_back(iovec{
.iov_base = (void*)(&obj),
.iov_len = sizeof(obj),
});
}
} // namespace
2019-04-28 18:19:32 +00:00
2019-04-28 06:47:30 +00:00
FastCGIRequest::FastCGIRequest(uint16_t request_id, FastCGIConn* conn)
: request_id_(request_id),
2019-04-28 18:19:32 +00:00
conn_(conn),
out_buf_(fastcgi_max_record_len) {}
2019-04-28 06:47:30 +00:00
uint16_t FastCGIRequest::RequestId() {
return request_id_;
}
2019-04-28 06:47:30 +00:00
void FastCGIRequest::AddParam(const std::string_view& key, const std::string_view& value) {
2019-04-28 06:57:00 +00:00
params_.try_emplace(std::string(key), std::string(value));
2019-04-28 06:47:30 +00:00
}
void FastCGIRequest::AddIn(const std::string_view& in) {
in_.append(in);
}
const std::string& FastCGIRequest::GetParam(const std::string& key) {
auto iter = params_.find(key);
if (iter == params_.end()) {
static const std::string none;
return none;
}
return iter->second;
2019-04-28 06:47:30 +00:00
}
2019-04-28 18:19:32 +00:00
void FastCGIRequest::WriteHeader(const std::string_view& name, const std::string_view& value) {
2019-04-28 18:51:56 +00:00
CHECK(!body_written_);
2019-04-28 18:19:32 +00:00
CHECK(out_buf_.Write(name));
CHECK(out_buf_.Write(": "));
CHECK(out_buf_.Write(value));
CHECK(out_buf_.Write("\n"));
}
2019-04-28 06:47:30 +00:00
2019-04-28 18:19:32 +00:00
void FastCGIRequest::WriteBody(const std::string_view& body) {
2019-04-28 18:51:56 +00:00
if (!body_written_) {
2019-04-28 18:19:32 +00:00
CHECK(out_buf_.Write("\n"));
2019-04-28 18:51:56 +00:00
body_written_ = true;
2019-04-28 06:47:30 +00:00
}
2019-04-28 18:19:32 +00:00
// TODO: make this able to span multiple packets
CHECK(out_buf_.Write(body));
}
2019-04-28 06:47:30 +00:00
bool FastCGIRequest::Flush() {
2019-04-28 18:51:56 +00:00
std::vector<iovec> vecs;
auto header = OutputHeader();
AppendVec(header, &vecs);
vecs.push_back(OutputVec());
if (!conn_->Write(vecs)) {
return false;
}
2019-04-28 18:51:56 +00:00
out_buf_.Commit();
return true;
2019-04-28 18:51:56 +00:00
}
bool FastCGIRequest::End() {
2019-04-28 18:51:56 +00:00
// Fully empty response not allowed
WriteBody("");
std::vector<iovec> vecs;
// 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-04-28 18:19:32 +00:00
FastCGIEndRequest end;
FastCGIHeader end_header(3, request_id_, sizeof(end));
2019-04-28 18:51:56 +00:00
AppendVec(end_header, &vecs);
AppendVec(end, &vecs);
2019-04-28 06:47:30 +00:00
return conn_->Write(vecs);
2019-04-28 06:47:30 +00:00
}
2019-04-28 18:51:56 +00:00
iovec FastCGIRequest::OutputVec() {
const auto output_len = out_buf_.ReadMaxLen();
return iovec{
.iov_base = (void *)(CHECK_NOTNULL(out_buf_.Read(output_len))),
.iov_len = output_len,
};
}
FastCGIHeader FastCGIRequest::OutputHeader() {
return FastCGIHeader(6, request_id_, out_buf_.ReadMaxLen());
}