example_simple building and working

This commit is contained in:
flamingcow
2019-05-04 23:42:03 -07:00
parent 5c8bd9e095
commit ef98af0ced
9 changed files with 222 additions and 4 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
*.o
*.a
example_simple
connection_afl

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "firebuf"]
path = firebuf
url = git@github.com:firestuff/firebuf.git

37
Makefile Normal file
View File

@@ -0,0 +1,37 @@
FIRE_CXX ?= clang++
FIRE_CXXFLAGS ?= -O3 -std=gnu++2a -Wall -Werror
FIRE_LDLIBS ?= -lgflags -lglog -lpthread
all: firecgi.a example_simple
objects = firecgi.o connection.o request.o parse.o
firecgi.a: $(objects)
$(MAKE) --directory=firebuf
ar rcs $@ $^
example_simple: example_simple.o $(objects)
$(FIRE_CXX) $(FIRE_CXXFLAGS) -o $@ $+ firebuf/firebuf.a $(FIRE_LDLIBS)
%.o: %.cc *.h Makefile
$(FIRE_CXX) $(FIRE_CXXFLAGS) -c -o $@ $<
clean:
$(MAKE) --directory=firebuf clean
rm --force example_simple connection_afl *.o
afl:
$(MAKE) clean
FIRE_CXX=afl-g++ $(MAKE) afl_int
afl_int: connection_afl
connection_afl: connection_afl.o $(objects)
$(FIRE_CXX) $(FIRE_CXXFLAGS) -o $@ $+ $(FIRE_LDLIBS)
test: test_connection
test_connection: connection_afl_afl
@echo "Running $$(ls afl_state/testcases | wc -l) tests"
for FILE in afl_state/testcases/*; do ./connection_afl < $$FILE; done
@printf '\033[0;32mALL TESTS PASSED\033[0m\n'

View File

@@ -13,7 +13,7 @@ Connection::Connection(int sock, const sockaddr_in6& client_addr, const std::fun
: sock_(sock),
callback_(callback),
headers_(headers),
buf_(sock, fastcgi_max_record_len) {
buf_(sock, 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)));
@@ -81,7 +81,7 @@ int Connection::Read() {
return sock_;
}
ConstBuffer param_buf(buf_.Read(header->ContentLength()), header->ContentLength());
firebuf::ConstBuffer param_buf(buf_.Read(header->ContentLength()), header->ContentLength());
while (param_buf.ReadMaxLen() > 0) {
const auto *param_header = param_buf.ReadObj<ParamHeader>();
if (!param_header) {

View File

@@ -5,8 +5,9 @@
#include <unordered_map>
#include <unordered_set>
#include "firebuf/stream_buffer.h"
#include "request.h"
#include "stream_buffer.h"
namespace firecgi {
@@ -25,7 +26,7 @@ class Connection {
uint64_t requests_ = 0;
StreamBuffer buf_;
firebuf::StreamBuffer buf_;
std::unique_ptr<Request> request_;
};

19
example_simple.cc Normal file
View File

@@ -0,0 +1,19 @@
#include <gflags/gflags.h>
#include <glog/logging.h>
#include "firecgi.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);
firecgi::Server server(FLAGS_port, [](std::unique_ptr<firecgi::Request> request) {
request->WriteHeader("Content-Type", "text/plain");
request->WriteBody("Hello world");
request->End();
}, FLAGS_threads);
server.Serve();
}

1
firebuf Submodule

Submodule firebuf added at dd9a0a974f

110
request.cc Normal file
View File

@@ -0,0 +1,110 @@
#include <sys/uio.h>
#include "request.h"
#include "connection.h"
namespace firecgi {
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
Request::Request(uint16_t request_id, Connection* conn)
: request_id_(request_id),
conn_(conn),
out_buf_(max_record_len) {}
uint16_t Request::RequestId() {
return request_id_;
}
void Request::AddParam(const std::string_view& key, const std::string_view& value) {
params_.try_emplace(std::string(key), std::string(value));
}
void Request::AddIn(const std::string_view& in) {
in_.append(in);
}
const std::string& Request::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 Request::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 Request::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 Request::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 Request::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());
}
EndRequest end;
Header end_header(3, request_id_, sizeof(end));
AppendVec(end_header, &vecs);
AppendVec(end, &vecs);
return conn_->Write(vecs);
}
iovec Request::OutputVec() {
const auto output_len = out_buf_.ReadMaxLen();
return iovec{
.iov_base = (void *)(CHECK_NOTNULL(out_buf_.Read(output_len))),
.iov_len = output_len,
};
}
Header Request::OutputHeader() {
return Header(6, request_id_, out_buf_.ReadMaxLen());
}
} // namespace firecgi

43
request.h Normal file
View File

@@ -0,0 +1,43 @@
#pragma once
#include <unordered_map>
#include "firebuf/buffer.h"
#include "parse.h"
namespace firecgi {
class Connection;
class Request {
public:
Request(uint16_t request_id, Connection *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:
Header OutputHeader();
iovec OutputVec();
const uint16_t request_id_;
Connection *conn_;
std::unordered_map<std::string, std::string> params_;
std::string in_;
firebuf::Buffer out_buf_;
bool body_written_ = false;
};
} // namespace firecgi