From 9da4a994bda8af7ccffff41bacd0a43015ac5c17 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Sun, 28 Apr 2019 06:47:30 +0000 Subject: [PATCH] Static "Hello world" page --- Makefile | 8 +-- buffer.cpp | 6 +- buffer.h | 10 +-- example_simple | Bin 0 -> 181480 bytes mirall.cpp => example_simple.cpp | 6 +- fastcgi.cpp | 5 +- fastcgi.h | 8 ++- fastcgi_conn.cpp | 105 ++++++++++++++++++++++++++++--- fastcgi_conn.h | 14 ++++- fastcgi_request.cpp | 68 ++++++++++++++++++++ fastcgi_request.h | 26 ++++++++ 11 files changed, 231 insertions(+), 25 deletions(-) create mode 100755 example_simple rename mirall.cpp => example_simple.cpp (52%) create mode 100644 fastcgi_request.cpp create mode 100644 fastcgi_request.h diff --git a/Makefile b/Makefile index 3f2e5c9..d1b4bfd 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ -mirall: Makefile mirall.o fastcgi.o fastcgi_conn.o buffer.o - g++ -std=gnu++2a -o mirall mirall.o fastcgi.o fastcgi_conn.o buffer.o -lgflags -lglog -lpthread +example_simple: example_simple.o fastcgi.o fastcgi_conn.o fastcgi_request.o buffer.o + g++ -std=gnu++2a -o example_simple example_simple.o fastcgi.o fastcgi_conn.o fastcgi_request.o buffer.o -lgflags -lglog -lpthread clean: - rm --force mirall *.o + rm --force exmaple_simple *.o -.cpp.o: Makefile *.h +.cpp.o: g++ -std=gnu++2a -o $@ -c $< diff --git a/buffer.cpp b/buffer.cpp index 05a1547..2b5cddc 100644 --- a/buffer.cpp +++ b/buffer.cpp @@ -19,7 +19,7 @@ bool ConstBuffer::Discard(size_t len) { if (len > ReadMaxLen()) { return false; } - Read(len); + static_cast(Read(len)); return true; } @@ -40,7 +40,9 @@ Buffer::Buffer(char *buf, size_t size, size_t len) } Buffer::Buffer(size_t size) - : Buffer((own_buf_.reset(new char[size]), own_buf_.get()), size, 0) {} + : Buffer(new char[size], size, 0) { + own_buf_.reset(buf_); +} char *Buffer::WritePtr() { return &buf_[len_]; diff --git a/buffer.h b/buffer.h index 334c8e3..627054b 100644 --- a/buffer.h +++ b/buffer.h @@ -7,9 +7,9 @@ class ConstBuffer { public: ConstBuffer(const char *buf, size_t len); - size_t ReadMaxLen() const; - const char *Read(size_t len); - template const T *ReadObj(); + [[nodiscard]] size_t ReadMaxLen() const; + [[nodiscard]] const char *Read(size_t len); + template [[nodiscard]] const T *ReadObj(); bool Discard(size_t len); // like Read() but don't use the result void ResetRead(); // next read from last commit @@ -28,8 +28,8 @@ class Buffer : public ConstBuffer { Buffer(char *buf, size_t size, size_t len); Buffer(size_t size); - char *WritePtr(); - size_t WriteMaxLen() const; + [[nodiscard]] char *WritePtr(); + [[nodiscard]] size_t WriteMaxLen() const; void Wrote(size_t len); void Consume(); // discard up to last commit diff --git a/example_simple b/example_simple new file mode 100755 index 0000000000000000000000000000000000000000..eb8254635b86b2da9eec50a9dc12975aae04e65d GIT binary patch literal 181480 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 LtgE>Qh+O##mKwc0 literal 0 HcmV?d00001 diff --git a/mirall.cpp b/example_simple.cpp similarity index 52% rename from mirall.cpp rename to example_simple.cpp index d019c2c..fff7ba5 100644 --- a/mirall.cpp +++ b/example_simple.cpp @@ -9,6 +9,10 @@ int main(int argc, char *argv[]) { google::InitGoogleLogging(argv[0]); gflags::ParseCommandLineFlags(&argc, &argv, true); - FastCGIServer server(FLAGS_port); + FastCGIServer server(FLAGS_port, [](std::unique_ptr request) { + LOG(INFO) << "request from " << request->GetParam("REMOTE_ADDR"); + request->Write({{"Content-Type", "text/plain"}}, {"Hello world"}); + request->WriteEnd(); + }); server.Serve(); } diff --git a/fastcgi.cpp b/fastcgi.cpp index d43258f..c8392bc 100644 --- a/fastcgi.cpp +++ b/fastcgi.cpp @@ -6,7 +6,8 @@ #include "fastcgi.h" #include "fastcgi_conn.h" -FastCGIServer::FastCGIServer(int port) { +FastCGIServer::FastCGIServer(int port, const std::function)>& callback) + : callback_(callback) { LOG(INFO) << "listening on [::1]:" << port; listen_sock_ = socket(AF_INET6, SOCK_STREAM, 0); @@ -38,7 +39,7 @@ void FastCGIServer::Serve() { PCHECK(client_sock >= 0) << "accept()"; CHECK_EQ(client_addr.sin6_family, AF_INET6); - auto *conn = new FastCGIConn(client_sock, client_addr); + auto *conn = new FastCGIConn(client_sock, client_addr, callback_); std::thread thread([conn]() { conn->Serve(); }); thread.detach(); } diff --git a/fastcgi.h b/fastcgi.h index 8757110..1097bd8 100644 --- a/fastcgi.h +++ b/fastcgi.h @@ -1,10 +1,16 @@ #pragma once +#include +#include + +#include "fastcgi_request.h" + class FastCGIServer { public: - FastCGIServer(int port); + FastCGIServer(int port, const std::function)>& callback); void Serve(); private: int listen_sock_; + std::function)> callback_; }; diff --git a/fastcgi_conn.cpp b/fastcgi_conn.cpp index 7cb5aac..6b375f2 100644 --- a/fastcgi_conn.cpp +++ b/fastcgi_conn.cpp @@ -1,8 +1,11 @@ #include #include +#include #include "fastcgi_conn.h" +#include "fastcgi_request.h" + namespace { struct fcgi_header { @@ -12,16 +15,39 @@ struct fcgi_header { uint16_t request_id_; // network byte order uint16_t content_length_; // network byte order public: - uint8_t padding_length; - uint8_t reserved; + uint8_t padding_length = 0; + uint8_t reserved = 0; - uint16_t ContentLength() const { return htons(content_length_); } + 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 fcgi_begin_request { - uint16_t role; // network byte order + private: + uint16_t role_; // network byte order + public: uint8_t flags; uint8_t reserved[5]; + + uint16_t Role() const { return ntohs(role_); } +}; + +struct fcgi_end_request { + private: + uint32_t app_status_; + public: + uint8_t protocol_status; + uint8_t reserved[3] = {}; + + void SetAppStatus(uint32_t app_status) { app_status_ = htonl(app_status); } +}; + +struct fcgi_param_header { + uint8_t key_length; + uint8_t value_length; }; constexpr auto fcgi_max_content_len = 65535; @@ -30,8 +56,9 @@ constexpr auto fcgi_max_record_len = sizeof(fcgi_header) + fcgi_max_content_len } // namespace -FastCGIConn::FastCGIConn(int sock, const sockaddr_in6& client_addr) +FastCGIConn::FastCGIConn(int sock, const sockaddr_in6& client_addr, const std::function)>& callback) : sock_(sock), + callback_(callback), buf_(fcgi_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))); @@ -50,6 +77,8 @@ void FastCGIConn::Serve() { PCHECK(read_len >= 0); if (read_len == 0) { LOG(INFO) << "peer closed connection"; + delete this; + return; } buf_.Wrote(read_len); @@ -58,6 +87,47 @@ void FastCGIConn::Serve() { } } +void FastCGIConn::WriteBlock(uint8_t type, uint16_t request_id, const std::vector& vecs) { + std::vector out_vecs; + out_vecs.reserve(vecs.size() + 1); + + fcgi_header header; + header.version = 1; + header.type = type; + header.SetRequestId(request_id); + uint16_t content_length = 0; + for (auto& vec : vecs) { + content_length += vec.iov_len; + } + header.SetContentLength(content_length); + out_vecs.push_back(std::move(iovec{ + .iov_base = &header, + .iov_len = sizeof(header), + })); + + for (auto& vec : vecs) { + out_vecs.push_back(vec); + } + + CHECK_EQ(writev(sock_, out_vecs.data(), out_vecs.size()), content_length + sizeof(header)); +} + +void FastCGIConn::WriteOutput(uint16_t request_id, const std::vector& vecs) { + WriteBlock(6, request_id, vecs); +} + +void FastCGIConn::WriteEnd(uint16_t request_id, uint8_t status) { + fcgi_end_request end; + end.SetAppStatus(status); + + std::vector vecs; + vecs.push_back(std::move(iovec{ + .iov_base = &end, + .iov_len = sizeof(end), + })); + WriteBlock(3, request_id, vecs); +} + void FastCGIConn::ParseBuf() { buf_.ResetRead(); @@ -72,22 +142,39 @@ void FastCGIConn::ParseBuf() { return; } - LOG(INFO) << "type: " << (int)header->type; - switch (header->type) { case 1: { CHECK_EQ(header->ContentLength(), sizeof(fcgi_begin_request)); const auto *begin_request = CHECK_NOTNULL(buf_.ReadObj()); - CHECK_EQ(ntohs(begin_request->role), 1); + CHECK_EQ(begin_request->Role(), 1); + + request_.reset(new FastCGIRequest(header->RequestId(), this)); } break; case 4: { - const auto *params = buf_.Read(header->ContentLength()); + ConstBuffer param_buf(buf_.Read(header->ContentLength()), header->ContentLength()); + while (param_buf.ReadMaxLen() > 0) { + const auto *param_header = param_buf.ReadObj(); + std::string_view key(param_buf.Read(param_header->key_length), param_header->key_length); + std::string_view value(param_buf.Read(param_header->value_length), param_header->value_length); + request_->AddParam(key, value); + } } break; + + case 5: + { + if (header->ContentLength() == 0) { + // Magic signal for completed request (mirrors the HTTP/1.1 protocol) + callback_(std::move(request_)); + } else { + std::string_view in(buf_.Read(header->ContentLength()), header->ContentLength()); + request_->AddIn(in); + } + } } CHECK(buf_.Discard(header->padding_length)); diff --git a/fastcgi_conn.h b/fastcgi_conn.h index d321132..848ca04 100644 --- a/fastcgi_conn.h +++ b/fastcgi_conn.h @@ -1,19 +1,31 @@ #pragma once +#include +#include + #include "buffer.h" struct sockaddr_in6; +class FastCGIRequest; class FastCGIConn { public: - FastCGIConn(int sock, const sockaddr_in6& client_addr); + FastCGIConn(int sock, const sockaddr_in6& client_addr, const std::function)>& callback); ~FastCGIConn(); void Serve(); + void WriteBlock(uint8_t type, uint16_t request_id, const std::vector& vecs); + void WriteOutput(uint16_t request_id, const std::vector& vecs); + void WriteEnd(uint16_t request_id, uint8_t status); + private: void ParseBuf(); const int sock_; + std::function)> callback_; + Buffer buf_; + + std::unique_ptr request_; }; diff --git a/fastcgi_request.cpp b/fastcgi_request.cpp new file mode 100644 index 0000000..a048cfa --- /dev/null +++ b/fastcgi_request.cpp @@ -0,0 +1,68 @@ +#include + +#include "fastcgi_conn.h" + +#include "fastcgi_request.h" + +FastCGIRequest::FastCGIRequest(uint16_t request_id, FastCGIConn* conn) + : request_id_(request_id), + conn_(conn) {} + +void FastCGIRequest::AddParam(const std::string_view& key, const std::string_view& value) { + params_.try_emplace(std::move(std::string(key)), std::move(std::string(value))); +} + +void FastCGIRequest::AddIn(const std::string_view& in) { + in_.append(in); +} + +const std::string& FastCGIRequest::GetParam(const std::string& key) { + return params_.at(key); +} + +void FastCGIRequest::Write(const std::vector>& headers, const std::vector& body) { + std::vector vecs; + vecs.reserve((headers.size() * 4) + 1 + body.size()); + + CHECK(headers.empty() || !body_sent_); + + for (const auto& header : headers) { + vecs.push_back(std::move(iovec{ + .iov_base = const_cast(header.first.data()), + .iov_len = header.first.size(), + })); + vecs.push_back(std::move(iovec{ + .iov_base = const_cast(": "), + .iov_len = 2, + })); + vecs.push_back(std::move(iovec{ + .iov_base = const_cast(header.second.data()), + .iov_len = header.second.size(), + })); + vecs.push_back(std::move(iovec{ + .iov_base = const_cast("\n"), + .iov_len = 1, + })); + } + + if (!body.empty() && !body_sent_) { + body_sent_ = true; + vecs.push_back(std::move(iovec{ + .iov_base = const_cast("\n"), + .iov_len = 1, + })); + } + + for (const auto& chunk : body) { + vecs.push_back(std::move(iovec{ + .iov_base = const_cast(chunk.data()), + .iov_len = chunk.size(), + })); + } + + conn_->WriteOutput(request_id_, vecs); +} + +void FastCGIRequest::WriteEnd() { + conn_->WriteEnd(request_id_, 0); +} diff --git a/fastcgi_request.h b/fastcgi_request.h new file mode 100644 index 0000000..e1547d4 --- /dev/null +++ b/fastcgi_request.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +class FastCGIConn; + +class FastCGIRequest { + public: + FastCGIRequest(uint16_t request_id, FastCGIConn *conn); + + 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 Write(const std::vector>& headers, const std::vector& body); + void WriteEnd(); + + private: + const uint16_t request_id_; + FastCGIConn *conn_; + + std::unordered_map params_; + std::string in_; + bool body_sent_ = false; +};