#ifndef FCGI_PROTOCOL_HH #define FCGI_PROTOCOL_HH #include #include #include class Buffer; class RoBuffer; namespace fcgi { enum RecordType { BeginRequest = 1, AbortRequest = 2, EndRequest = 3, Params = 4, Stdin = 5, Stdout = 6, Stderr = 7, Data = 8, GetValues = 9, GetValuesResult = 10, UnknownType = 11, }; enum Role { Responder = 1, Authorizer = 2, Filter = 3, }; enum Flags { KeepConn = 1, }; enum ProtocolStatus { RequestComplete = 0, CantMpxConn = 1, Overloaded = 2, UnknownRole = 3, }; class Record { public: virtual ~Record() = default; virtual bool good() const = 0; virtual uint8_t type() const = 0; virtual uint16_t request_id() const = 0; virtual uint16_t content_length() const = 0; virtual uint8_t padding_length() const = 0; static std::unique_ptr parse(RoBuffer* buffer); protected: Record() = default; Record(Record const&) = delete; Record& operator=(Record const&) = delete; }; class BeginRequestBody { public: virtual ~BeginRequestBody() = default; virtual bool good() const = 0; virtual uint16_t role() const = 0; virtual uint8_t flags() const = 0; static std::unique_ptr parse(Record const* record, RoBuffer* buffer); protected: BeginRequestBody() = default; BeginRequestBody(BeginRequestBody const&) = delete; BeginRequestBody& operator=(BeginRequestBody const&) = delete; }; class RecordStream { public: virtual ~RecordStream() = default; // True if all data has been read from stream. virtual bool end_of_stream() const = 0; // True if all data from last added record has been read. virtual bool end_of_record() const = 0; // True if no more data is coming, ie. what rbuf() returned last is all // there will ever be. virtual bool all_available() = 0; virtual char const* rbuf(RoBuffer* buf, size_t want, size_t& avail) = 0; virtual void rcommit(RoBuffer* buf, size_t bytes) = 0; // Call when next package for stream arrives. virtual void add(Record const* record) = 0; // Create stream with record as the first package in stream. static std::unique_ptr create_stream(Record const* record); // Create stream with record as the only package in stream. static std::unique_ptr create_single(Record const* record); protected: RecordStream() = default; RecordStream(RecordStream const&) = delete; RecordStream& operator=(RecordStream const&) = delete; }; class Pair { public: virtual ~Pair() = default; // Returns false if bad encoding or an invalid stream was found. // Calling next() will NOT change a false value back to true. virtual bool good() const = 0; virtual std::string const& name() const = 0; virtual std::string const& value() const = 0; // Returns nullptr if stream and buf needs more data. static std::unique_ptr start( RecordStream* stream, RoBuffer* buf); // Returns false if stream and buf needs more data. In that case Pair // is not modified. virtual bool next(RecordStream* stream, RoBuffer* buf) = 0; protected: Pair() = default; Pair(Pair const&) = delete; Pair& operator=(Pair const&) = delete; }; class RecordBuilder { public: virtual ~RecordBuilder() = default; virtual bool build(Buffer* dst) const = 0; virtual bool build(char* dst, size_t avail) const = 0; virtual bool padding(Buffer* dst) const = 0; virtual bool padding(char* dst, size_t avail) const = 0; virtual size_t size() const = 0; static std::unique_ptr create( RecordType type, uint16_t request_id, uint16_t content_length, int16_t padding_length = -1); static std::unique_ptr create( RecordType type, uint16_t request_id, std::string body); static std::unique_ptr create_unknown_type( uint8_t unknown_type); static std::unique_ptr create_begin_request( uint16_t request_id, Role role, uint8_t flags); static std::unique_ptr create_end_request( uint16_t request_id, uint32_t app_status, ProtocolStatus protocol_status); protected: RecordBuilder() = default; RecordBuilder(RecordBuilder const&) = delete; RecordBuilder& operator=(RecordBuilder const&) = delete; }; class PairBuilder { public: virtual ~PairBuilder() = default; virtual void add(std::string name, std::string value) = 0; virtual size_t size() const = 0; virtual bool build(Buffer* buf) const = 0; static std::unique_ptr create(); protected: PairBuilder() = default; PairBuilder(PairBuilder const&) = delete; PairBuilder& operator=(PairBuilder const&) = delete; }; } // namespace fcgi #endif // FCGI_PROTOCOL_HH