# Oat++ 1.3.0 Previous release - [1.2.5](1.2.5.md) Feel free to ask questions - [Chat on Gitter!](https://gitter.im/oatpp-framework/Lobby) Contents: - [The New oatpp::String](#the-new-oatppstring) - [ConnectionPool::get() Timeout](#connectionpoolget-timeout) - [JSON Serializer Escape Flags](#json-serializer-escape-flags) - [ConnectionMonitor](#connectionmonitor) - [Request Data Bundle](#request-data-bundle) - [Response::getBody()](#responsegetbody) - [data::stream::FIFOStream](#datastreamfifostream) - [data::stream::BufferedInputStream](#datastreambufferedinputstream) ## The New oatpp::String Now it's much easier to use `oatpp::String` since `oatpp::String` is now wrapper over `std::string` ```cpp { std::string s1 = Hello; oatpp::String s2 = s1; } { oatpp::String s1 = "Hello"; std::string s2 = *s1; // *s1 returns a refernce to the internal std::string object } { oatpp::String s1 = "Hello"; std::string s2 = s1; // s1 is used a l-value with a typecast operator } { oatpp::String s1 = "Hello"; bool b = s1 == "Hello"; // compare s1 with const char* assert(b); } { oatpp::String s1 = "Hello"; std::stringg s2 = "Hello"; bool b = s1 == s2; // compare s1 with std::string assert(b); } { oatpp::String s1 = "Hello"; std::string s2 = "World"; oatpp::String s3 = s1 + " " + s2; // concat oatpp::String with const char* and std::string directly OATPP_LOGD("TEST", "str='%s'", s3->c_str()); // prints 'Hello World' } ``` ## ConnectionPool::get() Timeout [#408](https://github.com/oatpp/oatpp/issues/408) ```cpp { auto connectionProvider = oatpp::network::tcp::client::ConnectionProvider::createShared({"httpbin.org", 80}); auto pool = oatpp::network::ClientConnectionPool::createShared(connectionProvider, 1, std::chrono::seconds(10), std::chrono::seconds(5)); OATPP_LOGD("TEST", "start") auto c1 = pool->get(); //<--- this one will succeed OATPP_LOGD("TEST", "c1=%llu", c1.get()) auto c2 = pool->get(); //<--- this one will fail in 5 sec. Since Max-Resources is 1, Pool timeout is 5 sec. And c1 is not freed. OATPP_LOGD("TEST", "c2=%llu", c2.get()) } ``` Output: ``` D |2021-08-04 01:32:56 1628029976986744| TEST:start D |2021-08-04 01:32:57 1628029977126940| TEST:c1=140716915331208 D |2021-08-04 01:33:02 1628029982128324| TEST:c2=0 ``` ## JSON Serializer Escape Flags [#381](https://github.com/oatpp/oatpp/issues/381) Now you can control if solidus is escaped or not. ### Default Behavior ```cpp oatpp::parser::json::mapping::ObjectMapper mapper; // mapper.getSerializer()->getConfig()->escapeFlags = 0; // by default FLAG_ESCAPE_SOLIDUS is ON auto res = mapper.writeToString(oatpp::String("https://oatpp.io/")); OATPP_LOGD("TEST", "res='%s'", res->c_str()); ``` Output: ``` res='"https:\/\/oatpp.io\/"' # by default, solidus is escaped ``` ### Clear Escape Flags ```cpp oatpp::parser::json::mapping::ObjectMapper mapper; mapper.getSerializer()->getConfig()->escapeFlags = 0; auto res = mapper.writeToString(oatpp::String("https://oatpp.io/")); OATPP_LOGD("TEST", "res='%s'", res->c_str()); ``` Output: ``` res='"https://oatpp.io/"' # solidus isn't escaped ``` ## ConnectionMonitor `oatpp::network::monitor::ConnectionMonitor` is a middleman who's able to monitor provided connections and close those ones that not satisfy selected rules. ```cpp OATPP_CREATE_COMPONENT(std::shared_ptr, serverConnectionProvider)([] { auto connectionProvider = oatpp::network::tcp::server::ConnectionProvider::createShared({"0.0.0.0", 8000, oatpp::network::Address::IP_4}); auto monitor = std::make_shared(connectionProvider); /* close all connections that stay opened for more than 120 seconds */ monitor->addMetricsChecker( std::make_shared( std::chrono::seconds(120) ) ); /* close all connections that have had no successful reads and writes for longer than 5 seconds */ monitor->addMetricsChecker( std::make_shared( std::chrono::seconds(5), std::chrono::seconds(5), ) ); return monitor; }()); ``` **Note:** `ConnectionMonitor` also works with `ClientConnectionProvider` as well. ## Request Data Bundle Now there is a data bundle associated with the Request and the Response which makes it easy to pass data through middleware interceptors and endpoints. Example: ```cpp class MyAuthInterceptor : public oatpp::web::server::interceptor::RequestInterceptor { public: std::shared_ptr intercept(const std::shared_ptr& request) override { /* authorize request and get auth data */ oatpp::Object authData = authorize(request); if(!authData) { return OutgoingResponse::createShared(Status::CODE_401, nullptr); } /* put auth data to bundle for later use at an endpoint */ request->putBundleData("auth", authData); return nullptr; // continue processing } }; ... ENDPOINT("GET", "videos/{videoId}", getVideoById, PATH(String, videoId), BUNDLE(oatpp::Object, authData, "auth")) { ... } ``` ## Response::getBody() `oatpp::web::protocol::http::outgoing::Response` has a new method `getBody()` to retreive the body of the response. This is handy for response interceptors. ## data::stream::FIFOStream The new `FIFOStream` stream is a buffered [`InputStream`](https://oatpp.io/api/latest/oatpp/core/data/stream/Stream/#inputstream) with an [`WriteCallback`](https://oatpp.io/api/latest/oatpp/core/data/stream/Stream/#writecallback). Check the corresponding documentation on how to use these interfaces. Instead of using a static buffer like `BufferInputStream` it is build upon `data::buffer::FIFOBuffer` and is able to dynamically grow when data is written to it that would surpass its capacity. It is especially useful if you need to buffer data from a stream upfront or have multiple data sources that should be buffered in a single stream. However, it is not synchronized, so be careful when using `FIFOStream` in a multithreaded manner. You need to implement your own locking. ## data::stream::BufferedInputStream `FIFOStream` also introduced a new interface [`BufferedInputStream`](https://oatpp.io/api/latest/oatpp/core/data/stream/Stream/#bufferedinputstream) which unifies the bufferd-stream-interface all existing buffered streams (`InputStreamBufferedProxy`, `BufferInputStream`, `FIFOStream`) to allow for generalisation.