Remove redundant files, break build

This commit is contained in:
flamingcow
2019-05-04 23:54:38 -07:00
parent eb585259e5
commit 2e7207fd23
58 changed files with 0 additions and 705 deletions

6
afl.sh
View File

@@ -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

View File

@@ -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;
}

View File

@@ -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)));
}

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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_;
};

View File

@@ -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;
}

View File

@@ -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_;
};

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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());
}

View File

@@ -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;
};

View File

@@ -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;
}

View File

@@ -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_;
};