misc header only libiraries depend on only C++ standard libiraries.
copy yu
directory to your project, then include it.
namespace yu {
namespace utf8 {
std::string yu::utf8::encode(uint32_t);
class Decoder {
public:
class Error : public std::runtime_error {
public:
Error(const std::string& message);
};
explicit Decoder(std::istream& in, uint32_t invalid_char = 0xfffd);
bool has_next();
uint32_t next(); // decode UTF-8 next string and return code point, or invalid_char if the sequence is invalid as UTF-8
const std::string& last_error() const;
size_t num_processed_bytes();
size_t num_processed_chars(); // num of code points returned
size_t num_processed_errors(); // num of invalid_char returned
};
}
}
example: sample/utf8_sample.cpp
uint32_t code_point = 0x1f363;
std::string str = yu::utf8::encode(code_point);
std::cout << str << std::endl;
// invalid char '\xff' will be replaced by U+FFFD
std::istringstream iss("ABCあいう\xff" + str);
yu::utf8::Decoder decoder(iss);
while (decoder.has_next()) {
code_point = decoder.next();
std::cout << yu::utf8::encode(code_point) << " U+" << std::hex << std::uppercase << code_point << std::endl;
}
std::cout << std::dec
<< decoder.num_processed_bytes() << " bytes, "
<< decoder.num_processed_chars() << " chars, "
<< decoder.num_processed_errors() << " errors" << std::endl;
// 🍣
// A U+41
// B U+42
// C U+43
// あ U+3042
// い U+3044
// う U+3046
// � U+FFFD
// 🍣 U+1F363
// 17 bytes, 8 chars, 1 errors
namespace yu {
namespace crypt {
class Blowfish {
public:
Blowfish(bool decrypt, const std::string& key);
void process(char *p, size_t size);
};
template <class ECB>
class CBC {
public:
CBC(bool decrypt, const std::string& key, const std::string& iv);
void process(char *p, size_t size);
};
template <class ECB>
class CFB {
public:
CFB(bool decrypt, const std::string& key, const std::string& iv);
void process(char *p, size_t size);
};
template <class ECB>
class OFB {
public:
OFB(bool /* decrypt */, const std::string& key, const std::string& iv);
void process(char *p, size_t size);
};
template <class Cipher, class Padding = yu::crypt::PKCS7Padding>
class cipher_enc_ostream : public std::ostream {
public:
template <class... Args>
cipher_enc_ostream(std::ostream& out, Args... args);
void finish();
};
template <class Cipher, class Padding = yu::crypt::PKCS7Padding>
class cipher_dec_ostream : public std::ostream {
public:
template <class... Args>
cipher_dec_ostream(std::ostream& out, Args... args);
void finish();
};
template <class Cipher, class Padding = yu::crypt::PKCS7Padding>
class cipher_enc_istream : public std::istream {
public:
template <class... Args>
cipher_enc_istream(std::istream& out, Args... args);
void finish();
};
template <class Cipher, class Padding = yu::crypt::PKCS7Padding>
class cipher_dec_istream : public std::istream {
public:
template <class... Args>
cipher_dec_istream(std::istream& out, Args... args);
void finish();
};
using Blowfish_ECB = Blowfish;
using Blowfish_CBC = CBC<Blowfish>;
using Blowfish_OFB = OFB<Blowfish>;
using Blowfish_CFB = CFB<Blowfish>;
using blowfish_ecb_enc_ostream = cipher_enc_ostream<Blowfish_ECB, PKCS7Padding>;
using blowfish_ecb_dec_ostream = cipher_dec_ostream<Blowfish_ECB, PKCS7Padding>;
using blowfish_cbc_enc_ostream = cipher_enc_ostream<Blowfish_CBC, PKCS7Padding>;
using blowfish_cbc_dec_ostream = cipher_dec_ostream<Blowfish_CBC, PKCS7Padding>;
using blowfish_ofb_enc_ostream = cipher_enc_ostream<Blowfish_OFB, NoPadding>;
using blowfish_ofb_dec_ostream = cipher_dec_ostream<Blowfish_OFB, NoPadding>;
using blowfish_cfb_enc_ostream = cipher_enc_ostream<Blowfish_CFB, NoPadding>;
using blowfish_cfb_dec_ostream = cipher_dec_ostream<Blowfish_CFB, NoPadding>;
using blowfish_ecb_enc_istream = cipher_enc_istream<Blowfish_ECB, PKCS7Padding>;
using blowfish_ecb_dec_istream = cipher_dec_istream<Blowfish_ECB, PKCS7Padding>;
using blowfish_cbc_enc_istream = cipher_enc_istream<Blowfish_CBC, PKCS7Padding>;
using blowfish_cbc_dec_istream = cipher_dec_istream<Blowfish_CBC, PKCS7Padding>;
using blowfish_ofb_enc_istream = cipher_enc_istream<Blowfish_OFB, NoPadding>;
using blowfish_ofb_dec_istream = cipher_dec_istream<Blowfish_OFB, NoPadding>;
using blowfish_cfb_enc_istream = cipher_enc_istream<Blowfish_CFB, NoPadding>;
using blowfish_cfb_dec_istream = cipher_dec_istream<Blowfish_CFB, NoPadding>;
// see sample for usage
}
}
example: sample/crypt_blowfish_sample.cpp
{ // ECB
std::ostringstream oss;
yu::crypt::blowfish_ecb_dec_ostream ds(oss, "key");
yu::crypt::blowfish_ecb_enc_ostream es(ds, "key");
es << "Hello blowfish!!";
es.finish();
ds.finish();
std::cout << oss.str() << std::endl;
}
{ // CBC, CFB and OFB
std::ostringstream oss;
yu::crypt::blowfish_cbc_dec_ostream ds(oss, "key", "Init Vec");
yu::crypt::blowfish_cbc_enc_ostream es(ds, "key", "Init Vec");
es << "Hello blowfish!!";
es.finish();
ds.finish();
std::cout << oss.str() << std::endl;
}
{ // istream and ostream
std::ostringstream oss;
{
yu::crypt::blowfish_cfb_enc_ostream oes(oss, "key", "Init Vec");
oes << "Hello blowfish!!";
oes.finish();
}
std::istringstream iss(oss.str());
{
yu::crypt::blowfish_cfb_dec_istream ids(iss, "key", "Init Vec");
std::vector<char> buffer(1024);
ids.read(buffer.data(), static_cast<std::streamsize>(buffer.size()));
std::string message(buffer.data(), static_cast<size_t>(ids.gcount()));
std::cout << message << std::endl;
}
}
// Hello blowfish!!
// Hello blowfish!!
// Hello blowfish!!
namespace yu {
namespace data {
template <typename T, typename Compare = std::less<T>, typename Allocator = std::allocator<T>>
class Heap {
public:
Heap();
explicit Heap(const std::vector<T>& values);
explicit Heap(std::vector<T>&& values);
Heap(const Heap&) = delete;
Heap& operator=(const Heap&) = delete;
Heap(Heap&&) = default;
Heap& operator=(Heap&&) = default;
void push(const T& value);
void push(T&& value);
template <class... Args>
void emplace(Args&&... args);
const T& top() const;
T pop();
void drain(std::vector<T>& values);
void clear();
size_t size() noexcept const;
bool empty() noexcept const;
size_t capacity() noexcept const;
void reserve(size_t size);
};
} // namespace data
} // namespace yu
example: sample/data_heap_sample.cpp
std::vector<int> vec{5, 2, 6, 1, 3, 4};
{
yu::data::Heap<int> heap;
for (auto i : vec) {
heap.push(i);
}
std::cout << "asc: ";
while (!heap.empty()) {
std::cout << " " << heap.pop();
}
std::cout << std::endl;
}
{
yu::data::Heap<int, std::greater<int>> heap;
for (auto i : vec) {
heap.push(i);
}
std::cout << "desc:";
while (!heap.empty()) {
std::cout << " " << heap.pop();
}
std::cout << std::endl;
}
// asc: 1 2 3 4 5 6
// desc: 6 5 4 3 2 1
namespace yu {
namespace digest {
class sha256_stream : public std::ostream {
public:
sha256_stream();
std::string hash_hex();
std::string hash_bin();
std::string hash_base64();
void reset();
};
std::string sha256_hex(const std::string& str);
std::string sha256_bin(const std::string& str);
std::string sha256_base64(const std::string& str);
// 224, 512, 384, 512_224 and 512_256 are same as 256
}
}
example: sample/digest_sha2_sample.cpp
std::string message = "Hello World.";
std::cout << yu::digest::sha256_hex(message) << std::endl;
std::cout << yu::digest::sha224_hex(message) << std::endl;
std::cout << yu::digest::sha512_hex(message) << std::endl;
std::cout << yu::digest::sha384_hex(message) << std::endl;
std::cout << yu::digest::sha512_256_hex(message) << std::endl;
std::cout << yu::digest::sha512_224_hex(message) << std::endl;
// f4bb1975bf1f81f76ce824f7536c1e101a8060a632a52289d530a6f600d52c92
// f871ab68ccdf47a7afb935f9f2f05365a61dee3aa6ebb7ef22be5de1
// fee4e02329c0e1c9005d0590f4773d8e519e0cda859775ac9c83641e3a960c57e7ad461354e4860722b6e3c161e493e04f5ef07d9169ff7bdab659d6a57cc316
// ded020e0ea23fd2d983f7d833c44811f9e3fa96e412f84f7427250af07a5630e26366a69c44bac94fd31ec73b1b847d1
// cc296ed308cbe384e0de66c8580b3373ac2ae88dd53a9bd8542df1431e87f01d
// 53a8f45fd2b7631b90d2c84b5dd223389b90ef503059f4c86fe6857d
TODO: $1$
$2b$
namespace yu {
namespace digest {
std::string bcrypt_sha256(const std::string& salt, const std::string& password);
std::string bcrypt_sha512(const std::string& salt, const std::string& password);
bool bcrypt_check(const std::string& digest, const std::string& password);
}
}
example: sample/digest_bcrypt_sample.cpp
std::cout << yu::digest::bcrypt_sha256("salt", "password") << std::endl;
std::cout << yu::digest::bcrypt_sha512("salt", "password") << std::endl;
std::string digest = yu::digest::bcrypt_sha512("", "password"); // random salt
std::cout << yu::digest::bcrypt_check(digest, "password") << std::endl;
std::cout << yu::digest::bcrypt_check(digest, "Password") << std::endl;
// $5$salt$Gcm6FsVtF/Qa77ZKD.iwsJlCVPY0XSMgLJL0Hnww/c1
// $6$salt$IxDD3jeSOb5eB1CX5LBsqZFVkJdido3OUILO5Ifz5iwMuTS4XMS130MTSuDDl3aCI6WouIL9AjRbLCelDCy.g.
// 1
// 0
template <typename T1, typename T2>
T1 lexical_cast(const T2& val);
example: sample/lexical_cast_sample.cpp
std::cout << (yu::lang::lexical_cast<int>("42") * 10) << std::endl;
std::cout << (yu::lang::lexical_cast<std::string>(42) + "0") << std::endl;
// 420
// 420
namespace yu {
namespace stream {
class fdstream : public std::iostream {
public:
explicit fdstream(int fd);
};
}
}
example: sample/stream_fdstream_sample.cpp
yu::stream::fdstream fds(1);
fds << "Hello World." << std::endl;
// Hello World.
namespace yu {
namespace stream {
class repeatstream : public std::iostream {
public:
explicit repeatstream(const std::string&);
};
}
}
example: sample/stream_repeatstream_sample.cpp
yu::stream::repeatstream repeat("yes\n");
std::string line;
for (size_t i = 0; i < 10; ++i) {
std::getline(repeat, line);
std::cout << line << std::endl;
}
// yes
// yes
// yes
// yes
// yes
// yes
// yes
// yes
// yes
// yes
namespace yu {
namespace stream {
class nullstream : public std::iostream {
public:
nullstream();
};
}
}
example: sample/stream_nullstream_sample.cpp
yu::stream::nullstream ns;
std::vector<char> buffer(1024);
// empty read
ns.read(buffer.data(), static_cast<std::streamsize>(buffer.size()));
std::cout << "read = " << ns.gcount() << " bytes, eof = " << ns.eof() << std::endl;
// infinity write
size_t write_count = 0;
for (size_t i = 0; i < 1024 * 1024; ++i) {
ns.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
write_count += buffer.size();
}
std::cout << "write = " << write_count << " bytes" << std::endl;
// read = 0 bytes, eof = 1
// write = 1073741824 bytes
namespace yu {
namespace stream {
class oteestream : public std::ostream {
public:
template<class.. Args>
oteestream(Args&&... ostreams);
};
class iteestream : public std::ostream {
public:
oteestream(std::istream& in, std::ostream& out);
};
}
}
example: sample/stream_teestream_sample.cpp
{
std::ostringstream out1;
std::ostringstream out2;
std::ostringstream out3;
yu::stream::oteestream ots(out1, out2, out3);
ots << "Hello World!";
std::cout << "out1 = " << out1.str() << std::endl;
std::cout << "out2 = " << out2.str() << std::endl;
std::cout << "out3 = " << out3.str() << std::endl;
}
{
std::istringstream iss("Hello World!");
std::ostringstream oss;
yu::stream::iteestream its(iss, oss);
std::string str;
its >> str;
std::cout << "str = " << str << std::endl;
std::cout << "oss = " << oss.str() << std::endl; // ostream recieve whole buffer
its >> str;
std::cout << "str = " << str << std::endl;
}
// out1 = Hello World!
// out2 = Hello World!
// out3 = Hello World!
// str = Hello
// oss = Hello World!
// str = World!
see also: app/sha2.cpp
namespace yu {
namespace string {
inline std::string lstrip(const std::string& str, const std::string& spaces = "\r\n\t ");
inline std::string rstrip(const std::string& str, const std::string& spaces = "\r\n\t ");
inline std::string strip(const std::string& str, const std::string& spaces = "\r\n\t ");
inline std::vector<std::string> split(const std::string& str, char delim = ',', bool strip_token = false, size_t max_tokens = 0);
inline std::string join(const std::vector<std::string>& strs, const std::string& delim = ",");
template <typename T>
inline std::string join(const std::vector<T>& strs, const std::string& delim = ",");
inline bool starts_with(const std::string& str, const std::string& prefix);
inline bool ends_with(const std::string& str, const std::string& suffix);
inline std::string remove_prefix(const std::string& str, const std::string& prefix);
inline std::string remove_suffix(const std::string& str, const std::string& suffix);
inline int icompare(const std::string& lhs, const std::string& rhs);
inline bool iless(const std::string& lhs, const std::string& rhs);
class iLess {
public:
bool operator()(const std::string& lhs, const std::string& rhs) const { return iless(lhs, rhs); }
using first_argument_type = std::string;
using second_argument_type = std::string;
using result_type = bool;
};
inline bool igreater(const std::string& lhs, const std::string& rhs);
class iGreater {
public:
bool operator()(const std::string& lhs, const std::string& rhs) const { return igreater(lhs, rhs); }
using first_argument_type = std::string;
using second_argument_type = std::string;
using result_type = bool;
};
} // namespace string
} // namespace yu
example: sample/string_utils_sample.cpp
std::cout << "lstrip: [" << yu::string::lstrip(" hello world ") << "]" << std::endl;
std::cout << "rstrip: [" << yu::string::rstrip(" hello world ") << "]" << std::endl;
std::cout << " strip: [" << yu::string::strip(" hello world ") << "]" << std::endl;
std::vector<std::string> strs = yu::string::split("hello world", ' ');
for (const auto& str : strs) {
std::cout << "split: [" << str << "]" << std::endl;
}
std::cout << "join: [" << yu::string::join(strs, ",") << "]" << std::endl;
std::cout << "foobar is " << (yu::string::starts_with("foobar", "foo") ? "" : "not ") << "starts with foo" << std::endl;
std::cout << "foobar is " << (yu::string::starts_with("foobar", "bar") ? "" : "not ") << "starts with bar" << std::endl;
std::cout << "foobar is " << (yu::string::ends_with("foobar", "foo") ? "" : "not ") << "ends with foo" << std::endl;
std::cout << "foobar is " << (yu::string::ends_with("foobar", "bar") ? "" : "not ") << "ends with bar" << std::endl;
std::cout << "remove prefix foo from foobar: " << yu::string::remove_prefix("foobar", "foo") << std::endl;
std::cout << "remove prefix bar from foobar: " << yu::string::remove_prefix("foobar", "bar") << std::endl;
std::cout << "remove suffix foo from foobar: " << yu::string::remove_suffix("foobar", "foo") << std::endl;
std::cout << "remove suffix bar from foobar: " << yu::string::remove_suffix("foobar", "bar") << std::endl;
std::vector<std::string> vs = { "a", "B", "c", "D" };
std::sort(vs.begin(), vs.end());
std::cout << "asc (case sensitive):";
for (const auto& v : vs) { std::cout << " " << v; } std::cout << std::endl;
std::sort(vs.begin(), vs.end(), yu::string::iLess());
std::cout << "asc (case insensitive):";
for (const auto& v : vs) { std::cout << " " << v; } std::cout << std::endl;
std::sort(vs.begin(), vs.end(), std::greater<std::string>());
std::cout << "desc(case sensitive):";
for (const auto& v : vs) { std::cout << " " << v; } std::cout << std::endl;
std::sort(vs.begin(), vs.end(), yu::string::iGreater());
std::cout << "desc(case insensitive):";
for (const auto& v : vs) { std::cout << " " << v; } std::cout << std::endl;
// lstrip: [hello world ]
// rstrip: [ hello world]
// strip: [hello world]
// split: [hello]
// split: [world]
// join: [hello,world]
// foobar is starts with foo
// foobar is not starts with bar
// foobar is not ends with foo
// foobar is ends with bar
// remove prefix foo from foobar: bar
// remove prefix bar from foobar: foobar
// remove suffix foo from foobar: foobar
// remove suffix bar from foobar: foo
// asc (case sensitive): B D a c
// asc (case insensitive): a B c D
// desc(case sensitive): c a D B
// desc(case insensitive): D c B a
namespace yu {
namespace base64 {
class Encoder {
public:
Encoder(size_t wrap_width = 76, char char62 = '+', char char63 = '/', char pad = '=', const std::string& newline = "\n");
// read from in, encode, and write to out. return CRC24 for Radix-64
uint32_t encode(std::istream& in, std::ostream& out) const;
};
// base64 encode
std::string encode(const std::string& str, size_t wrap_width = 76);
// base64 encode using '-' and '_' instead of '+' and '/'
std::string encodeURL(const std::string& str);
class Decoder {
public:
Decoder(char char62 = '+', char char63 = '/', char pad = '=', const std::string& allowed_white_space = " \r\n");
// read from in, decode, and write to out. return CRC24 for Radix-64
uint32_t decode(std::istream& in, std::ostream& out) const;
};
// base64 decode
std::string decode(const std::string& str);
// base64 decode using '-' and '_' instead of '+' and '/'
std::string decodeURL(const std::string& str);
}
}
example: sample/base64_sample.cpp
std::cout << yu::base64::encode("Hello World.") << std::endl;;
std::cout << yu::base64::decode("SGVsbG8gV29ybGQu") << std::endl;
// SGVsbG8gV29ybGQu
// Hello World.
class Stringifier {
public:
explicit Stringifier(std::ostream& out, bool pretty = false);
template <typename T>
void stringify(const T& value);
}
class Parser {
public:
explicit Parser(std::istream& in) : in_(in) {}
template <typename T>
void parse(std::ostream& out, const T& v);
};
// stream interface
template <typename T>
inline void stringify(std::ostream& out, const T& val);
template <typename T>
inline void parse(std::istream& in, T& val);
// string interface
template <typename T>
inline std::string to_json(const T& v);
template <typename T>
inline T from_json(const std::string& str);
// Macros: Object mappring
// Usage
class Klass {
private:
std::string str;
int num;
public:
void stringifyJson(yu::json::Stringifier& stringifier) {
JSON_MEMBER_STRINGIFIER(stringifier)
<< JSON_GETTER(str)
<< JSON_NAMED_GETTER("number", num)
<< JSON_STRINGIFY;
}
void parseJson(yu::json::Parser& parser) {
JSON_MEMBER_PARSER(parser)
<< JSON_SETTER(str)
<< JSON_NAMED_SETTER("number", num)
<< JSON_PARSE;
}
}
example: sample/json_sample.cpp
class Klass {
public:
Klass() : str(), num(), map(), vec() {}
private:
std::string str;
int num;
std::map<std::string, float> map;
std::vector<bool> vec;
public:
void stringifyJson(yu::json::Stringifier& stringifier) const {
JSON_MEMBER_STRINGIFIER(stringifier)
<< JSON_GETTER(str) << JSON_GETTER(num)
<< JSON_GETTER(map) << JSON_GETTER(vec)
<< JSON_STRINGIFY;
}
void parseJson(yu::json::Parser& parser) {
JSON_MEMBER_PARSER(parser)
<< JSON_SETTER(str) << JSON_SETTER(num)
<< JSON_SETTER(map) << JSON_SETTER(vec)
<< JSON_PARSE;
}
};
std::string json = R"(
{
"str": "Hello World.", "num": 42,
"map": { "a": 3.14 }, "vec": [ true, false ]
}
)";
Klass obj = yu::json::from_json<Klass>(json);
std::cout << yu::json::to_json(obj) << std::endl;
// {"str":"Hello World.","num":42,"map":{"a":3.14},"vec":[true,false]}
namespace yu {
namespace http {
class ClientStream {
public:
explicit ClientStream(std::iostream& stream);
void set_header(const std::string& key, const std::string& value);
std::unique_ptr<std::ostream> request(const std::string& request_method,
const std::string& request_target,
const std::string& request_version = "HTTP/1.1");
std::unique_ptr<std::istream> parse_respose();
const std::string& response_version() const;
int response_code() const;
const std::string& response_code_message() const;
const Header& response_header() const;
};
}
}
example: sample/http_client_stream_sample.cpp
int fds[2];
::socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
yu::stream::fdstream user_agent(fds[0]);
yu::stream::fdstream server(fds[1]);
std::cout << "* Send request" << std::endl;
yu::http::ClientStream cs(user_agent);
cs.set_header("Host", "example.com");
{
std::unique_ptr<std::ostream> request_body_stream = cs.request("POST", "/");
*request_body_stream << "Hello World!!";
}
std::cout << "* Recieve request" << std::endl;
std::string line;
// header
while (std::getline(server, line)) {
line = yu::string::rstrip(line, "\r");
if (line.empty()) break;
std::cout << line << std::endl;
}
std::cout << std::endl;
// body
while (std::getline(server, line)) {
line = yu::string::rstrip(line, "\r");
if (line.empty()) break;
std::cout << line << std::endl;
}
std::cout << "* Send response" << std::endl;
server
<< "HTTP/1.1 200 OK\r\n"
<< "Server: test\r\n"
<< "Set-Cookie: foo=1; path=/\r\n"
<< "Transfer-Encoding: chunked\r\n"
<< "\r\n"
<< "6\r\n"
<< "Hello \r\n"
<< "7\r\n"
<< "World!!\r\n"
<< "0\r\n"
<< "\r\n";
server.flush();
std::cout << "* Recieve response" << std::endl;
{
std::unique_ptr<std::istream> response_body_stream = cs.parse_respose();
std::cout << cs.response_version() << " " << cs.response_code() << " " << cs.response_code_message() << std::endl;
cs.response_header().write(std::cout);
std::vector<char> buffer(1024);
response_body_stream->read(buffer.data(), static_cast<std::streamsize>(buffer.size()));
std::string response_body(buffer.data(), buffer.data() + response_body_stream->gcount());
std::cout << response_body << std::endl;
}
// * Send request
// * Recieve request
// POST / HTTP/1.1
// Host: example.com
// Transfer-Encoding: chunked
//
// D
// Hello World!!
// 0
// * Send response
// * Recieve response
// HTTP/1.1 200 OK
// Set-Cookie: foo=1; path=/
// Server: test
// Transfer-Encoding: chunked
//
// Hello World!!
namespace yu {
namespace http {
class ServerStream {
public:
explicit ServerStream(std::iostream& stream);
std::unique_ptr<std::istream> parse_request();
const std::string& request_method() const;
const std::string& request_target() const;
const std::string& request_version() const;
const std::unordered_map<std::string, std::string>& request_headers() const;
void set_status(int status, const std::string& messgae = "");
void set_header(const std::string& key, const std::string& value);
std::unique_ptr<chunked_ostream> send_header();
};
}
}
example: sample/http_server_stream_sample.cpp
int fds[2];
::socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
yu::stream::fdstream user_agent(fds[0]);
yu::stream::fdstream server(fds[1]);
yu::http::ServerStream ss(server);
std::cout << "* Send request" << std::endl;
user_agent
<< "POST / HTTP/1.1\r\n"
<< "Host: example.com\r\n"
<< "User-Agent: test\r\n"
<< "Transfer-Encoding: chunked\r\n"
<< "\r\n"
<< "6\r\n"
<< "Hello \r\n"
<< "6\r\n"
<< "World!\r\n"
<< "0\r\n"
<< "\r\n";
user_agent.flush();
std::cout << "* Recieve request" << std::endl;
{
std::unique_ptr<std::istream> request_body_stream = ss.parse_request();
std::cout << ss.request_method() << " " << ss.request_target() << " " << ss.request_version() << std::endl;
ss.request_header().write(std::cout);
std::vector<char> buffer(1024);
request_body_stream->read(buffer.data(), static_cast<std::streamsize>(buffer.size()));
std::string request_body(buffer.data(), buffer.data() + request_body_stream->gcount());
std::cout << request_body << std::endl;
}
std::cout << "* Send response" << std::endl;
ss.set_status(200);
ss.set_header("Server", "libyu http::ServerStream");
ss.set_header("Set-Cookie", "foo=1; path=/");
ss.set_header("Server", "version 0.0.0");
ss.set_header("Set-Cookie", "bar=2; path=/");
{
std::unique_ptr<std::ostream> response_body_stream = ss.send_header();
*response_body_stream << "It's ";
*response_body_stream << "wonderful ";
*response_body_stream << "wordl!!";
}
std::cout << "* Recieve response" << std::endl;
std::string line;
// header
while (std::getline(user_agent, line)) {
line = yu::string::rstrip(line, "\r");
if (line.empty()) break;
std::cout << line << std::endl;
}
std::cout << std::endl;
// body
while (std::getline(user_agent, line)) {
line = yu::string::rstrip(line, "\r");
if (line.empty()) break;
std::cout << line << std::endl;
}
close(fds[0]);
close(fds[1]);
// * Send request
// * Recieve request
// POST / HTTP/1.1
// Host: example.com
// Transfer-Encoding: chunked
// User-Agent: test
//
// Hello World!
// * Send response
// * Recieve response
// HTTP/1.1 200 OK
// Set-Cookie: foo=1; path=/
// Set-Cookie: bar=2; path=/
// Server: libyu http::ServerStream,version 0.0.0
// Transfer-Encoding: chunked
//
// 16
// It's wonderful wordl!!
// 0
see test/*_test.cpp
- なんで今更C++?
- 書きたかったから
- base64とかOpenSSLとかにあるよ?
- 書きたかったから書いた
- 実装の優先度は?
- 書きたくなった順
- バグを見つけた/実装がいけていない
- つ Pull Request
see LICENSE file
Copyright 2023 TAKEI Yuya (https://github.com/takei-yuya)