Remove redundant files, break build
This commit is contained in:
6
afl.sh
6
afl.sh
@@ -1,6 +0,0 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
cd $(dirname $0)
|
||||
|
||||
make afl
|
||||
afl-fuzz -i afl_state/testcases -o afl_state/findings -- ./fastcgi_conn_afl
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
79
buffer.cc
79
buffer.cc
@@ -1,79 +0,0 @@
|
||||
#include "buffer.h"
|
||||
|
||||
ConstBuffer::ConstBuffer(const char *buf, size_t len)
|
||||
: const_buf_(buf),
|
||||
len_(len) {}
|
||||
|
||||
size_t ConstBuffer::ReadMaxLen() const {
|
||||
return len_ - start_;
|
||||
}
|
||||
|
||||
const char *ConstBuffer::Read(size_t len) {
|
||||
if (ReadMaxLen() < len) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto *ret = &const_buf_[start_];
|
||||
start_ += len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ConstBuffer::Discard(size_t len) {
|
||||
if (len > ReadMaxLen()) {
|
||||
return false;
|
||||
}
|
||||
static_cast<void>(Read(len));
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConstBuffer::ResetRead() {
|
||||
start_ = commit_;
|
||||
}
|
||||
|
||||
void ConstBuffer::Commit() {
|
||||
commit_ = start_;
|
||||
}
|
||||
|
||||
|
||||
Buffer::Buffer(char *buf, size_t size, size_t len)
|
||||
: ConstBuffer(buf, size),
|
||||
buf_(buf),
|
||||
size_(size) {
|
||||
len_ = len;
|
||||
}
|
||||
|
||||
Buffer::Buffer(size_t size)
|
||||
: Buffer(new char[size], size, 0) {
|
||||
own_buf_.reset(buf_);
|
||||
}
|
||||
|
||||
char *Buffer::WritePtr() {
|
||||
return &buf_[len_];
|
||||
}
|
||||
|
||||
size_t Buffer::WriteMaxLen() const {
|
||||
return size_ - len_;
|
||||
}
|
||||
|
||||
bool Buffer::Write(const std::string_view& str) {
|
||||
if (WriteMaxLen() < str.size()) {
|
||||
return false;
|
||||
}
|
||||
memcpy(WritePtr(), str.data(), str.size());
|
||||
Wrote(str.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
void Buffer::Wrote(size_t len) {
|
||||
CHECK_LE(len, WriteMaxLen());
|
||||
len_ += len;
|
||||
}
|
||||
|
||||
void Buffer::Consume() {
|
||||
if (commit_ == 0) {
|
||||
return;
|
||||
}
|
||||
memmove(buf_, &buf_[commit_], len_ - commit_);
|
||||
len_ -= commit_;
|
||||
start_ -= commit_;
|
||||
commit_ = 0;
|
||||
}
|
||||
49
buffer.h
49
buffer.h
@@ -1,49 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
class ConstBuffer {
|
||||
public:
|
||||
ConstBuffer(const char *buf, size_t len);
|
||||
|
||||
[[nodiscard]] size_t ReadMaxLen() const;
|
||||
[[nodiscard]] virtual const char *Read(size_t len);
|
||||
template<class T> [[nodiscard]] const T *ReadObj();
|
||||
|
||||
bool Discard(size_t len); // like Read() but don't use the result
|
||||
void ResetRead(); // next read from last commit
|
||||
void Commit(); // commit read position
|
||||
|
||||
protected:
|
||||
const char *const_buf_;
|
||||
size_t len_;
|
||||
size_t start_ = 0;
|
||||
size_t commit_ = 0;
|
||||
};
|
||||
|
||||
class Buffer : public ConstBuffer {
|
||||
public:
|
||||
Buffer(char *buf, size_t size, size_t len);
|
||||
Buffer(size_t size);
|
||||
|
||||
[[nodiscard]] char *WritePtr();
|
||||
[[nodiscard]] size_t WriteMaxLen() const;
|
||||
bool Write(const std::string_view& str);
|
||||
void Wrote(size_t len);
|
||||
|
||||
void Consume(); // discard up to last commit
|
||||
|
||||
protected:
|
||||
std::unique_ptr<char[]> own_buf_;
|
||||
char *buf_;
|
||||
const size_t size_;
|
||||
};
|
||||
|
||||
template<class T> const T *ConstBuffer::ReadObj() {
|
||||
if (ReadMaxLen() < sizeof(T)) {
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<const T*>(Read(sizeof(T)));
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include "fastcgi.h"
|
||||
|
||||
DEFINE_int32(port, 9000, "TCP port to bind");
|
||||
DEFINE_int32(threads, 1, "Number of server threads");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
FastCGIServer server(FLAGS_port, [](std::unique_ptr<FastCGIRequest> request) {
|
||||
request->WriteHeader("Content-Type", "text/plain");
|
||||
request->WriteBody("Hello world");
|
||||
request->End();
|
||||
}, FLAGS_threads);
|
||||
server.Serve();
|
||||
}
|
||||
113
fastcgi.cc
113
fastcgi.cc
@@ -1,113 +0,0 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <signal.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <thread>
|
||||
|
||||
#include "fastcgi.h"
|
||||
#include "fastcgi_conn.h"
|
||||
|
||||
FastCGIServer::FastCGIServer(int port, const std::function<void(std::unique_ptr<FastCGIRequest>)>& callback, int threads, const std::unordered_set<std::string_view>& headers)
|
||||
: port_(port),
|
||||
callback_(callback),
|
||||
threads_(threads),
|
||||
headers_(headers) {
|
||||
LOG(INFO) << "listening on [::1]:" << port_;
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
|
||||
void FastCGIServer::Serve() {
|
||||
std::vector<std::thread> threads;
|
||||
for (int i = 0; i < threads_ - 1; ++i) {
|
||||
threads.emplace_back([this]() { ServeInt(); });
|
||||
}
|
||||
ServeInt();
|
||||
}
|
||||
|
||||
void FastCGIServer::ServeInt() {
|
||||
auto epoll_fd = epoll_create1(0);
|
||||
PCHECK(epoll_fd >= 0) << "epoll_create()";
|
||||
|
||||
auto listen_sock = NewListenSock();
|
||||
|
||||
{
|
||||
struct epoll_event ev{
|
||||
.events = EPOLLIN,
|
||||
.data = {
|
||||
.ptr = nullptr,
|
||||
},
|
||||
};
|
||||
PCHECK(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_sock, &ev) == 0);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
constexpr auto max_events = 256;
|
||||
struct epoll_event events[max_events];
|
||||
auto num_fd = epoll_wait(epoll_fd, events, max_events, -1);
|
||||
if (num_fd == -1 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
PCHECK(num_fd > 0) << "epoll_wait()";
|
||||
|
||||
for (auto i = 0; i < num_fd; ++i) {
|
||||
if (events[i].data.ptr == nullptr) {
|
||||
NewConn(listen_sock, epoll_fd);
|
||||
} else {
|
||||
auto conn = static_cast<FastCGIConn*>(events[i].data.ptr);
|
||||
auto fd = conn->Read();
|
||||
if (fd != -1) {
|
||||
PCHECK(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr) == 0);
|
||||
delete conn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FastCGIServer::NewConn(int listen_sock, int epoll_fd) {
|
||||
sockaddr_in6 client_addr;
|
||||
socklen_t client_addr_len = sizeof(client_addr);
|
||||
|
||||
auto client_sock = accept(listen_sock, (sockaddr*) &client_addr, &client_addr_len);
|
||||
PCHECK(client_sock >= 0) << "accept()";
|
||||
CHECK_EQ(client_addr.sin6_family, AF_INET6);
|
||||
|
||||
int flags = 1;
|
||||
PCHECK(setsockopt(client_sock, SOL_TCP, TCP_NODELAY, &flags, sizeof(flags)) == 0);
|
||||
|
||||
{
|
||||
auto *conn = new FastCGIConn(client_sock, client_addr, callback_, headers_);
|
||||
struct epoll_event ev{
|
||||
.events = EPOLLIN,
|
||||
.data = {
|
||||
.ptr = conn,
|
||||
},
|
||||
};
|
||||
PCHECK(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_sock, &ev) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
int FastCGIServer::NewListenSock() {
|
||||
auto sock = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
PCHECK(sock >= 0) << "socket()";
|
||||
|
||||
{
|
||||
int optval = 1;
|
||||
PCHECK(setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
sockaddr_in6 bind_addr = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_port = htons(port_),
|
||||
.sin6_addr = IN6ADDR_LOOPBACK_INIT,
|
||||
};
|
||||
PCHECK(bind(sock, (sockaddr*) &bind_addr, sizeof(bind_addr)) == 0);
|
||||
}
|
||||
|
||||
PCHECK(listen(sock, 128) == 0);
|
||||
return sock;
|
||||
}
|
||||
23
fastcgi.h
23
fastcgi.h
@@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "fastcgi_request.h"
|
||||
|
||||
class FastCGIServer {
|
||||
public:
|
||||
FastCGIServer(int port, const std::function<void(std::unique_ptr<FastCGIRequest>)>& callback, int threads=1, const std::unordered_set<std::string_view>& headers={});
|
||||
void Serve();
|
||||
|
||||
private:
|
||||
void NewConn(int listen_sock, int epoll_fd);
|
||||
int NewListenSock();
|
||||
void ServeInt();
|
||||
|
||||
const int port_;
|
||||
const std::function<void(std::unique_ptr<FastCGIRequest>)> callback_;
|
||||
const int threads_;
|
||||
const std::unordered_set<std::string_view> headers_;
|
||||
};
|
||||
143
fastcgi_conn.cc
143
fastcgi_conn.cc
@@ -1,143 +0,0 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "fastcgi_conn.h"
|
||||
|
||||
#include "fastcgi_parse.h"
|
||||
#include "fastcgi_request.h"
|
||||
|
||||
FastCGIConn::FastCGIConn(int sock, const sockaddr_in6& client_addr, const std::function<void(std::unique_ptr<FastCGIRequest>)>& callback, const std::unordered_set<std::string_view>& headers)
|
||||
: sock_(sock),
|
||||
callback_(callback),
|
||||
headers_(headers),
|
||||
buf_(sock, fastcgi_max_record_len) {
|
||||
char client_addr_str[INET6_ADDRSTRLEN];
|
||||
PCHECK(inet_ntop(AF_INET6, &client_addr.sin6_addr, client_addr_str, sizeof(client_addr_str)));
|
||||
|
||||
LOG(INFO) << "new connection: [" << client_addr_str << "]:" << ntohs(client_addr.sin6_port);
|
||||
}
|
||||
|
||||
FastCGIConn::~FastCGIConn() {
|
||||
PCHECK(close(sock_) == 0);
|
||||
LOG(INFO) << "connection closed (handled " << requests_ << " requests)";
|
||||
}
|
||||
|
||||
bool FastCGIConn::Write(const std::vector<iovec>& vecs) {
|
||||
ssize_t total_size = 0;
|
||||
for (const auto& vec : vecs) {
|
||||
total_size += vec.iov_len;
|
||||
}
|
||||
return writev(sock_, vecs.data(), vecs.size()) == total_size;
|
||||
}
|
||||
|
||||
int FastCGIConn::Read() {
|
||||
if (!buf_.Refill()) {
|
||||
return sock_;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
buf_.ResetRead();
|
||||
|
||||
const auto *header = buf_.ReadObj<FastCGIHeader>();
|
||||
if (!header) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (header->version != 1) {
|
||||
LOG(ERROR) << "invalid FastCGI protocol version: " << header->version;
|
||||
return sock_;
|
||||
}
|
||||
|
||||
if (buf_.ReadMaxLen() < header->ContentLength()) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (header->type) {
|
||||
case 1:
|
||||
{
|
||||
if (header->ContentLength() != sizeof(FastCGIBeginRequest)) {
|
||||
LOG(ERROR) << "FCGI_BeginRequestBody is the wrong length: " << header->ContentLength();
|
||||
return sock_;
|
||||
}
|
||||
|
||||
const auto *begin_request = CHECK_NOTNULL(buf_.ReadObj<FastCGIBeginRequest>());
|
||||
|
||||
if (begin_request->Role() != 1) {
|
||||
LOG(ERROR) << "unsupported FastCGI role: " << begin_request->Role();
|
||||
return sock_;
|
||||
}
|
||||
|
||||
request_.reset(new FastCGIRequest(header->RequestId(), this));
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
{
|
||||
if (request_ == nullptr || header->RequestId() != request_->RequestId()) {
|
||||
LOG(ERROR) << "out of order FCGI_PARAMS record, or client is multiplexing requests (which we don't support)";
|
||||
return sock_;
|
||||
}
|
||||
|
||||
ConstBuffer param_buf(buf_.Read(header->ContentLength()), header->ContentLength());
|
||||
while (param_buf.ReadMaxLen() > 0) {
|
||||
const auto *param_header = param_buf.ReadObj<FastCGIParamHeader>();
|
||||
if (!param_header) {
|
||||
LOG(ERROR) << "FCGI_PARAMS missing header";
|
||||
return sock_;
|
||||
}
|
||||
|
||||
const auto *key_buf = param_buf.Read(param_header->key_length);
|
||||
if (!key_buf) {
|
||||
LOG(ERROR) << "FCGI_PARAMS missing key";
|
||||
return sock_;
|
||||
}
|
||||
std::string_view key(key_buf, param_header->key_length);
|
||||
|
||||
const auto *value_buf = param_buf.Read(param_header->value_length);
|
||||
if (!value_buf) {
|
||||
LOG(ERROR) << "FCGI_PARAMS missing value";
|
||||
return sock_;
|
||||
}
|
||||
std::string_view value(value_buf, param_header->value_length);
|
||||
|
||||
if (headers_.find(key) != headers_.end()) {
|
||||
request_->AddParam(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
{
|
||||
if (request_ == nullptr || header->RequestId() != request_->RequestId()) {
|
||||
LOG(ERROR) << "out of order FCGI_STDIN record, or client is multiplexing requests (which we don't support)";
|
||||
return sock_;
|
||||
}
|
||||
|
||||
if (header->ContentLength() == 0) {
|
||||
// Magic signal for completed request (mirrors the HTTP/1.1 protocol)
|
||||
requests_++;
|
||||
callback_(std::move(request_));
|
||||
} else {
|
||||
std::string_view in(buf_.Read(header->ContentLength()), header->ContentLength());
|
||||
request_->AddIn(in);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG(ERROR) << "unknown record type: " << header->type;
|
||||
return sock_;
|
||||
}
|
||||
|
||||
if (!buf_.Discard(header->padding_length)) {
|
||||
break;
|
||||
}
|
||||
|
||||
buf_.Commit(); // we've acted on the bytes read so far
|
||||
}
|
||||
|
||||
buf_.Consume();
|
||||
return -1;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <sys/uio.h>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "fastcgi_request.h"
|
||||
#include "stream_buffer.h"
|
||||
|
||||
class FastCGIConn {
|
||||
public:
|
||||
FastCGIConn(int sock, const sockaddr_in6& client_addr, const std::function<void(std::unique_ptr<FastCGIRequest>)>& callback, const std::unordered_set<std::string_view>& headers);
|
||||
~FastCGIConn();
|
||||
|
||||
[[nodiscard]] int Read();
|
||||
[[nodiscard]] bool Write(const std::vector<iovec>& vecs);
|
||||
|
||||
private:
|
||||
const int sock_;
|
||||
const std::function<void(std::unique_ptr<FastCGIRequest>)>& callback_;
|
||||
const std::unordered_set<std::string_view>& headers_;
|
||||
|
||||
uint64_t requests_ = 0;
|
||||
|
||||
StreamBuffer buf_;
|
||||
|
||||
std::unique_ptr<FastCGIRequest> request_;
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
#include "fastcgi_conn.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
FLAGS_logtostderr = 1;
|
||||
FLAGS_minloglevel = 3;
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
{
|
||||
FastCGIConn conn(STDIN_FILENO, {}, [](std::unique_ptr<FastCGIRequest> req) { req->End(); }, {});
|
||||
static_cast<void>(conn.Read());
|
||||
}
|
||||
|
||||
gflags::ShutDownCommandLineFlags();
|
||||
google::ShutdownGoogleLogging();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
#include "fastcgi_parse.h"
|
||||
|
||||
FastCGIHeader::FastCGIHeader(uint8_t type_in, uint16_t request_id, uint16_t content_length)
|
||||
: type(type_in) {
|
||||
SetRequestId(request_id);
|
||||
SetContentLength(content_length);
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
struct FastCGIHeader {
|
||||
FastCGIHeader(uint8_t type_in, uint16_t request_id, uint16_t content_length);
|
||||
|
||||
uint8_t version = 1;
|
||||
uint8_t type;
|
||||
private:
|
||||
uint16_t request_id_; // network byte order
|
||||
uint16_t content_length_; // network byte order
|
||||
public:
|
||||
uint8_t padding_length = 0;
|
||||
uint8_t reserved = 0;
|
||||
|
||||
uint16_t RequestId() const { return ntohs(request_id_); }
|
||||
uint16_t ContentLength() const { return ntohs(content_length_); }
|
||||
|
||||
void SetRequestId(uint16_t request_id) { request_id_ = htons(request_id); }
|
||||
void SetContentLength(uint16_t content_length) { content_length_ = htons(content_length); }
|
||||
};
|
||||
|
||||
struct FastCGIBeginRequest {
|
||||
private:
|
||||
uint16_t role_; // network byte order
|
||||
public:
|
||||
uint8_t flags;
|
||||
uint8_t reserved[5];
|
||||
|
||||
uint16_t Role() const { return ntohs(role_); }
|
||||
};
|
||||
|
||||
struct FastCGIEndRequest {
|
||||
uint32_t app_status = htonl(0); // network byte order
|
||||
uint8_t protocol_status;
|
||||
uint8_t reserved[3] = {};
|
||||
};
|
||||
|
||||
struct FastCGIParamHeader {
|
||||
uint8_t key_length;
|
||||
uint8_t value_length;
|
||||
};
|
||||
|
||||
constexpr auto fastcgi_max_content_len = 65535;
|
||||
constexpr auto fastcgi_max_padding_len = 255;
|
||||
constexpr auto fastcgi_max_record_len = sizeof(FastCGIHeader) + fastcgi_max_content_len + fastcgi_max_padding_len;
|
||||
@@ -1,107 +0,0 @@
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "fastcgi_request.h"
|
||||
|
||||
#include "fastcgi_conn.h"
|
||||
|
||||
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
|
||||
|
||||
FastCGIRequest::FastCGIRequest(uint16_t request_id, FastCGIConn* conn)
|
||||
: request_id_(request_id),
|
||||
conn_(conn),
|
||||
out_buf_(fastcgi_max_record_len) {}
|
||||
|
||||
uint16_t FastCGIRequest::RequestId() {
|
||||
return request_id_;
|
||||
}
|
||||
|
||||
void FastCGIRequest::AddParam(const std::string_view& key, const std::string_view& value) {
|
||||
params_.try_emplace(std::string(key), std::string(value));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void FastCGIRequest::WriteHeader(const std::string_view& name, const std::string_view& value) {
|
||||
CHECK(!body_written_);
|
||||
CHECK(out_buf_.Write(name));
|
||||
CHECK(out_buf_.Write(": "));
|
||||
CHECK(out_buf_.Write(value));
|
||||
CHECK(out_buf_.Write("\n"));
|
||||
}
|
||||
|
||||
void FastCGIRequest::WriteBody(const std::string_view& body) {
|
||||
if (!body_written_) {
|
||||
CHECK(out_buf_.Write("\n"));
|
||||
body_written_ = true;
|
||||
}
|
||||
// TODO: make this able to span multiple packets
|
||||
CHECK(out_buf_.Write(body));
|
||||
}
|
||||
|
||||
bool FastCGIRequest::Flush() {
|
||||
std::vector<iovec> vecs;
|
||||
|
||||
auto header = OutputHeader();
|
||||
AppendVec(header, &vecs);
|
||||
|
||||
vecs.push_back(OutputVec());
|
||||
|
||||
if (!conn_->Write(vecs)) {
|
||||
return false;
|
||||
}
|
||||
out_buf_.Commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FastCGIRequest::End() {
|
||||
// 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());
|
||||
}
|
||||
|
||||
FastCGIEndRequest end;
|
||||
FastCGIHeader end_header(3, request_id_, sizeof(end));
|
||||
AppendVec(end_header, &vecs);
|
||||
AppendVec(end, &vecs);
|
||||
|
||||
return conn_->Write(vecs);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "fastcgi_parse.h"
|
||||
|
||||
class FastCGIConn;
|
||||
|
||||
class FastCGIRequest {
|
||||
public:
|
||||
FastCGIRequest(uint16_t request_id, FastCGIConn *conn);
|
||||
|
||||
uint16_t RequestId();
|
||||
|
||||
void AddParam(const std::string_view& key, const std::string_view& value);
|
||||
void AddIn(const std::string_view& in);
|
||||
|
||||
const std::string& GetParam(const std::string& key);
|
||||
|
||||
void WriteHeader(const std::string_view& name, const std::string_view& value);
|
||||
void WriteBody(const std::string_view& body);
|
||||
[[nodiscard]] bool Flush();
|
||||
bool End();
|
||||
|
||||
private:
|
||||
FastCGIHeader OutputHeader();
|
||||
iovec OutputVec();
|
||||
|
||||
const uint16_t request_id_;
|
||||
FastCGIConn *conn_;
|
||||
|
||||
std::unordered_map<std::string, std::string> params_;
|
||||
std::string in_;
|
||||
|
||||
Buffer out_buf_;
|
||||
bool body_written_ = false;
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
#include "stream_buffer.h"
|
||||
|
||||
StreamBuffer::StreamBuffer(int sock, size_t size)
|
||||
: Buffer(size),
|
||||
sock_(sock) {}
|
||||
|
||||
bool StreamBuffer::Refill() {
|
||||
auto read_len = read(sock_, WritePtr(), WriteMaxLen());
|
||||
if (read_len == 0) {
|
||||
return false;
|
||||
}
|
||||
Wrote(read_len);
|
||||
return true;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
class StreamBuffer : public Buffer {
|
||||
public:
|
||||
StreamBuffer(int sock, size_t size);
|
||||
|
||||
[[nodiscard]] bool Refill();
|
||||
|
||||
private:
|
||||
int sock_;
|
||||
};
|
||||
Reference in New Issue
Block a user