diff --git a/src/oatpp/core/data/share/MemoryLabel.hpp b/src/oatpp/core/data/share/MemoryLabel.hpp index ed43d196..c4d57526 100644 --- a/src/oatpp/core/data/share/MemoryLabel.hpp +++ b/src/oatpp/core/data/share/MemoryLabel.hpp @@ -68,17 +68,28 @@ public: bool equals(const void* data, v_int32 size) const { return m_size == size && base::StrBuffer::equals(m_data, data, m_size); } - + + /** + * Create oatpp::String from memory label + * @return oatpp::String(data, size) + */ oatpp::String toString() const { return oatpp::String((const char*) m_data, m_size, true); } - - std::string toStdString() const { + + /** + * Create std::string from memory label + * @return std::string(data, size) + */ + std::string std_str() const { return std::string((const char*) m_data, m_size); } }; - + +/** + * MemoryLabel which can be used as a key in unordered_map + */ class StringKeyLabel : public MemoryLabel { public: @@ -97,7 +108,10 @@ public: } }; - + +/** + * MemoryLabel which can be used as a case-insensitive key in unordered_map + */ class StringKeyLabelCI : public MemoryLabel { public: @@ -116,7 +130,12 @@ public: } }; - + +/** + * MemoryLabel which can be used as a case-insensitive-fast key in unordered_map. + * CI_FAST - is appropriate for strings consisting of [a..z] + [A..Z] only. + * for other symbols undefined collisions may occur. + */ class StringKeyLabelCI_FAST : public MemoryLabel { public: diff --git a/src/oatpp/core/data/stream/ChunkedBuffer.hpp b/src/oatpp/core/data/stream/ChunkedBuffer.hpp index 1f41f1ee..119c3866 100644 --- a/src/oatpp/core/data/stream/ChunkedBuffer.hpp +++ b/src/oatpp/core/data/stream/ChunkedBuffer.hpp @@ -125,7 +125,7 @@ private: data::v_io_size& outChunkPos); public: - + ChunkedBuffer() : m_size(0) , m_chunkPos(0) @@ -136,6 +136,11 @@ public: ~ChunkedBuffer() { clear(); } + +public: + + ChunkedBuffer(const ChunkedBuffer&) = delete; + ChunkedBuffer& operator=(const ChunkedBuffer&) = delete; public: diff --git a/src/oatpp/core/data/stream/Stream.cpp b/src/oatpp/core/data/stream/Stream.cpp index 478be45e..d7f3b0d2 100644 --- a/src/oatpp/core/data/stream/Stream.cpp +++ b/src/oatpp/core/data/stream/Stream.cpp @@ -77,43 +77,105 @@ data::v_io_size OutputStream::writeAsString(bool value) { // Functions -const std::shared_ptr& operator << -(const std::shared_ptr& s, const oatpp::String& str) { - s->write(str); +OutputStream& operator << (OutputStream& s, const oatpp::String& str) { + if(str) { + s.write(str); + } else { + s.write("[]"); + } return s; } -const std::shared_ptr& operator << -(const std::shared_ptr& s, const char* str) { - s->write(str); +OutputStream& operator << (OutputStream& s, const Int8& value) { + if(value.getPtr()) { + return operator << (s, value->getValue()); + } + s.write("[]"); + return s; +} + +OutputStream& operator << (OutputStream& s, const Int16& value) { + if(value.getPtr()) { + return operator << (s, value->getValue()); + } + s.write("[]"); + return s; +} + +OutputStream& operator << (OutputStream& s, const Int32& value) { + if(value.getPtr()) { + return operator << (s, value->getValue()); + } + s.write("[]"); + return s; +} + +OutputStream& operator << (OutputStream& s, const Int64& value) { + if(value.getPtr()) { + return operator << (s, value->getValue()); + } + s.write("[]"); + return s; +} + +OutputStream& operator << (OutputStream& s, const Float32& value) { + if(value.getPtr()) { + return operator << (s, value->getValue()); + } + s.write("[]"); + return s; +} + +OutputStream& operator << (OutputStream& s, const Float64& value) { + if(value.getPtr()) { + return operator << (s, value->getValue()); + } + s.write("[]"); + return s; +} + +OutputStream& operator << (OutputStream& s, const Boolean& value) { + if(value.getPtr()) { // use getPtr() here to avoid false to nullptr conversion + return operator << (s, value->getValue()); + } + s.write("[]"); + return s; +} + +OutputStream& operator << (OutputStream& s, const char* str) { + if(str != nullptr) { + s.write(str); + } else { + s.write("[]"); + } return s; } -const std::shared_ptr& operator << (const std::shared_ptr& s, v_int32 value) { - s->writeAsString(value); +OutputStream& operator << (OutputStream& s, v_int32 value) { + s.writeAsString(value); return s; } -const std::shared_ptr& operator << (const std::shared_ptr& s, v_int64 value) { - s->writeAsString(value); +OutputStream& operator << (OutputStream& s, v_int64 value) { + s.writeAsString(value); return s; } -const std::shared_ptr& operator << (const std::shared_ptr& s, v_float32 value) { - s->writeAsString(value); +OutputStream& operator << (OutputStream& s, v_float32 value) { + s.writeAsString(value); return s; } -const std::shared_ptr& operator << (const std::shared_ptr& s, v_float64 value) { - s->writeAsString(value); +OutputStream& operator << (OutputStream& s, v_float64 value) { + s.writeAsString(value); return s; } -const std::shared_ptr& operator << (const std::shared_ptr& s, bool value) { +OutputStream& operator << (OutputStream& s, bool value) { if(value) { - s->OutputStream::write("true"); + s.OutputStream::write("true"); } else { - s->OutputStream::write("false"); + s.OutputStream::write("false"); } return s; } diff --git a/src/oatpp/core/data/stream/Stream.hpp b/src/oatpp/core/data/stream/Stream.hpp index 6fe90710..30934e50 100644 --- a/src/oatpp/core/data/stream/Stream.hpp +++ b/src/oatpp/core/data/stream/Stream.hpp @@ -125,21 +125,22 @@ public: }; -const std::shared_ptr& operator << -(const std::shared_ptr& s, const oatpp::String& str); +OutputStream& operator << (OutputStream& s, const oatpp::String& str); +OutputStream& operator << (OutputStream& s, const Int8& value); +OutputStream& operator << (OutputStream& s, const Int16& value); +OutputStream& operator << (OutputStream& s, const Int32& value); +OutputStream& operator << (OutputStream& s, const Int64& value); +OutputStream& operator << (OutputStream& s, const Float32& value); +OutputStream& operator << (OutputStream& s, const Float64& value); +OutputStream& operator << (OutputStream& s, const Boolean& value); -const std::shared_ptr& operator << -(const std::shared_ptr& s, const char* str); - -const std::shared_ptr& operator << (const std::shared_ptr& s, v_int32 value); +OutputStream& operator << (OutputStream& s, const char* str); +OutputStream& operator << (OutputStream& s, v_int32 value); +OutputStream& operator << (OutputStream& s, v_int64 value); +OutputStream& operator << (OutputStream& s, v_float32 value); +OutputStream& operator << (OutputStream& s, v_float64 value); +OutputStream& operator << (OutputStream& s, bool value); -const std::shared_ptr& operator << (const std::shared_ptr& s, v_int64 value); - -const std::shared_ptr& operator << (const std::shared_ptr& s, v_float32 value); - -const std::shared_ptr& operator << (const std::shared_ptr& s, v_float64 value); - -const std::shared_ptr& operator << (const std::shared_ptr& s, bool value); /** * Read bytes from @fromStream" and write to @toStream" using @buffer of size @bufferSize diff --git a/src/oatpp/core/utils/ConversionUtils.cpp b/src/oatpp/core/utils/ConversionUtils.cpp index cde457d4..6622b46a 100644 --- a/src/oatpp/core/utils/ConversionUtils.cpp +++ b/src/oatpp/core/utils/ConversionUtils.cpp @@ -139,7 +139,7 @@ namespace oatpp { namespace utils { namespace conversion { oatpp::String float64ToStr(v_float64 value){ v_char8 buff [100]; - v_int32 size = float32ToCharSequence(value, &buff[0]); + v_int32 size = float64ToCharSequence(value, &buff[0]); if(size > 0){ return oatpp::String((const char*)&buff[0], size, true); } diff --git a/src/oatpp/network/Url.cpp b/src/oatpp/network/Url.cpp index ff41625c..7c9d05c3 100644 --- a/src/oatpp/network/Url.cpp +++ b/src/oatpp/network/Url.cpp @@ -110,12 +110,15 @@ void Url::Parser::parseQueryParamsToMap(Url::Parameters& params, oatpp::parser:: do { caret.inc(); auto nameLabel = caret.putLabel(); - if(caret.findChar('=')) { + v_int32 charFound = caret.findCharFromSet("=&"); + if(charFound == '=') { nameLabel.end(); caret.inc(); auto valueLabel = caret.putLabel(); caret.findChar('&'); - params.put(nameLabel.toString(), valueLabel.toString()); + params[nameLabel.toString()] = valueLabel.toString(); + } else { + params[nameLabel.toString()] = oatpp::String("", false); } } while (caret.canContinueAtChar('&')); @@ -128,33 +131,74 @@ void Url::Parser::parseQueryParamsToMap(Url::Parameters& params, const oatpp::St parseQueryParamsToMap(params, caret); } -std::shared_ptr Url::Parser::parseQueryParams(oatpp::parser::Caret& caret) { - auto params = Url::Parameters::createShared(); - parseQueryParamsToMap(*params, caret); +Url::Parameters Url::Parser::parseQueryParams(oatpp::parser::Caret& caret) { + Url::Parameters params; + parseQueryParamsToMap(params, caret); return params; } -std::shared_ptr Url::Parser::parseQueryParams(const oatpp::String& str) { - auto params = Url::Parameters::createShared(); - parseQueryParamsToMap(*params, str); +Url::Parameters Url::Parser::parseQueryParams(const oatpp::String& str) { + Url::Parameters params; + parseQueryParamsToMap(params, str); return params; } +Url::ParametersAsLabels Url::Parser::labelQueryParams(const oatpp::String& str) { + + Url::ParametersAsLabels params; + oatpp::parser::Caret caret(str); + + if(caret.findChar('?')) { + + do { + caret.inc(); + auto nameLabel = caret.putLabel(); + v_int32 charFound = caret.findCharFromSet("=&"); + if(charFound == '=') { + nameLabel.end(); + caret.inc(); + auto valueLabel = caret.putLabel(); + caret.findChar('&'); + params[StringKeyLabel(str.getPtr(), nameLabel.getData(), nameLabel.getSize())] = + StringKeyLabel(str.getPtr(), valueLabel.getData(), valueLabel.getSize()); + } else { + params[StringKeyLabel(str.getPtr(), nameLabel.getData(), nameLabel.getSize())] = ""; + } + } while (caret.canContinueAtChar('&')); + + } + + return params; + +} + Url Url::Parser::parseUrl(oatpp::parser::Caret& caret) { + Url result; - result.scheme = parseScheme(caret); - if(caret.canContinueAtChar(':', 1)) { - if(caret.isAtText((p_char8)"//", 2, true)) { - if(!caret.isAtChar('/')) { - result.authority = parseAuthority(caret); - } - result.path = parsePath(caret); - result.queryParams = parseQueryParams(caret); - } else { - result.authority = parseAuthority(caret); - } + + if(caret.findChar(':')) { + caret.setPosition(0); + result.scheme = parseScheme(caret); + caret.canContinueAtChar(':', 1); + } else { + caret.setPosition(0); } + + caret.isAtText((p_char8)"//", 2, true); + + if(!caret.isAtChar('/')) { + result.authority = parseAuthority(caret); + } + + result.path = parsePath(caret); + result.queryParams = parseQueryParams(caret); + return result; } + +Url Url::Parser::parseUrl(const oatpp::String& str) { + oatpp::parser::Caret caret(str); + return parseUrl(caret); +} }} diff --git a/src/oatpp/network/Url.hpp b/src/oatpp/network/Url.hpp index 720dc69d..7633e04a 100644 --- a/src/oatpp/network/Url.hpp +++ b/src/oatpp/network/Url.hpp @@ -25,17 +25,23 @@ #ifndef oatpp_network_Url_hpp #define oatpp_network_Url_hpp +#include "oatpp/core/data/share/MemoryLabel.hpp" #include "oatpp/core/parser/Caret.hpp" #include "oatpp/core/collection/ListMap.hpp" #include "oatpp/core/Types.hpp" +#include + namespace oatpp { namespace network { // TODO - refactor to use oatpp::data::share::MemoryLabel class Url : public oatpp::base::Controllable { public: - typedef oatpp::collection::ListMap Parameters; + typedef oatpp::data::share::StringKeyLabel StringKeyLabel; +public: + typedef std::unordered_map Parameters; + typedef std::unordered_map ParametersAsLabels; public: struct Authority { @@ -58,7 +64,7 @@ public: static oatpp::String parseScheme(oatpp::parser::Caret& caret); /** - * parse utl authority components. + * parse url authority components. * userinfo is not parsed into login and password separately as * inclusion of password in userinfo is deprecated and ignored here * caret should be at the first char of the authority (not at "//") @@ -86,18 +92,34 @@ public: /** * parse query params in form of "?=&=..." referred by ParsingCaret */ - static std::shared_ptr parseQueryParams(oatpp::parser::Caret& caret); + static Url::Parameters parseQueryParams(oatpp::parser::Caret& caret); /** * parse query params in form of "?=&=..." referred by str */ - static std::shared_ptr parseQueryParams(const oatpp::String& str); - + static Url::Parameters parseQueryParams(const oatpp::String& str); + /** - * parse Url + * Same as parseQueryParams() but use StringKeyLabel instead of a String. + * Zero allocations. Use this method for better performance. + * @param str + * @return std::unordered_map + */ + static ParametersAsLabels labelQueryParams(const oatpp::String& str); + + /** + * Parse Url + * @param caret + * @return parsed URL structure */ static Url parseUrl(oatpp::parser::Caret& caret); - + + /** + * Parse Url + * @param str + * @return parsed URL structure + */ + static Url parseUrl(const oatpp::String& str); }; @@ -106,7 +128,7 @@ public: oatpp::String scheme; Authority authority; oatpp::String path; - std::shared_ptr queryParams; + Parameters queryParams; }; diff --git a/src/oatpp/web/protocol/http/incoming/BodyDecoder.cpp b/src/oatpp/web/protocol/http/incoming/BodyDecoder.cpp index 5f3a42c0..e5ca3d23 100644 --- a/src/oatpp/web/protocol/http/incoming/BodyDecoder.cpp +++ b/src/oatpp/web/protocol/http/incoming/BodyDecoder.cpp @@ -28,6 +28,21 @@ namespace oatpp { namespace web { namespace protocol { namespace http { namespace incoming { +BodyDecoder::ToStringDecoder::ToStringDecoder(const BodyDecoder* decoder, + const Protocol::Headers& headers, + const std::shared_ptr& bodyStream) + : m_decoder(decoder) + , m_headers(headers) + , m_bodyStream(bodyStream) + , m_chunkedBuffer(oatpp::data::stream::ChunkedBuffer::createShared()) +{} +async::Action BodyDecoder::ToStringDecoder::act() { + return m_decoder->decodeAsync(this, yieldTo(&ToStringDecoder::onDecoded), m_headers, m_bodyStream, m_chunkedBuffer); +} + +async::Action BodyDecoder::ToStringDecoder::onDecoded() { + return _return(m_chunkedBuffer->toString()); +} }}}}} diff --git a/src/oatpp/web/protocol/http/incoming/BodyDecoder.hpp b/src/oatpp/web/protocol/http/incoming/BodyDecoder.hpp index bf2a6821..6066eced 100644 --- a/src/oatpp/web/protocol/http/incoming/BodyDecoder.hpp +++ b/src/oatpp/web/protocol/http/incoming/BodyDecoder.hpp @@ -39,24 +39,15 @@ private: const BodyDecoder* m_decoder; Protocol::Headers m_headers; std::shared_ptr m_bodyStream; - std::shared_ptr m_chunkedBuffer = oatpp::data::stream::ChunkedBuffer::createShared(); + std::shared_ptr m_chunkedBuffer; public: ToStringDecoder(const BodyDecoder* decoder, const Protocol::Headers& headers, - const std::shared_ptr& bodyStream) - : m_decoder(decoder) - , m_headers(headers) - , m_bodyStream(bodyStream) - {} + const std::shared_ptr& bodyStream); - Action act() override { - return m_decoder->decodeAsync(this, yieldTo(&ToStringDecoder::onDecoded), m_headers, m_bodyStream, m_chunkedBuffer); - } - - Action onDecoded() { - return _return(m_chunkedBuffer->toString()); - } + Action act() override; + Action onDecoded(); }; diff --git a/src/oatpp/web/protocol/http/incoming/Request.cpp b/src/oatpp/web/protocol/http/incoming/Request.cpp index 7c84bc7d..fa0ab7dd 100644 --- a/src/oatpp/web/protocol/http/incoming/Request.cpp +++ b/src/oatpp/web/protocol/http/incoming/Request.cpp @@ -23,3 +23,100 @@ ***************************************************************************/ #include "Request.hpp" + +namespace oatpp { namespace web { namespace protocol { namespace http { namespace incoming { + +Request::Request(const http::RequestStartingLine& startingLine, + const url::mapping::Pattern::MatchMap& pathVariables, + const http::Protocol::Headers& headers, + const std::shared_ptr& bodyStream, + const std::shared_ptr& bodyDecoder) + : m_startingLine(startingLine) + , m_pathVariables(pathVariables) + , m_headers(headers) + , m_bodyStream(bodyStream) + , m_bodyDecoder(bodyDecoder) + , m_queryParamsParsed(false) +{} + +std::shared_ptr Request::createShared(const http::RequestStartingLine& startingLine, + const url::mapping::Pattern::MatchMap& pathVariables, + const http::Protocol::Headers& headers, + const std::shared_ptr& bodyStream, + const std::shared_ptr& bodyDecoder) { + return Shared_Incoming_Request_Pool::allocateShared(startingLine, pathVariables, headers, bodyStream, bodyDecoder); +} + +const http::RequestStartingLine& Request::getStartingLine() const { + return m_startingLine; +} + +const url::mapping::Pattern::MatchMap& Request::getPathVariables() const { + return m_pathVariables; +} + +const http::Protocol::Headers& Request::getHeaders() const { + return m_headers; +} + +const http::Protocol::QueryParams& Request::getQueryParameters() const { + if(!m_queryParamsParsed) { + m_queryParams = oatpp::network::Url::Parser::labelQueryParams(m_pathVariables.getTail()); + m_queryParamsParsed = true; + } + return m_queryParams; +} + +oatpp::String Request::getQueryParameter(const oatpp::data::share::StringKeyLabel& name) const { + auto iter = getQueryParameters().find(name); + if (iter == getQueryParameters().end()) { + return nullptr; + } else { + return iter->second.toString(); + } +} + +oatpp::String Request::getQueryParameter(const oatpp::data::share::StringKeyLabel& name, const oatpp::String& defaultValue) const { + auto value = getQueryParameter(name); + return value ? value : defaultValue; +} + +std::shared_ptr Request::getBodyStream() const { + return m_bodyStream; +} + +std::shared_ptr Request::getBodyDecoder() const { + return m_bodyDecoder; +} + +oatpp::String Request::getHeader(const oatpp::data::share::StringKeyLabelCI_FAST& headerName) const{ + auto it = m_headers.find(headerName); + if(it != m_headers.end()) { + return it->second.toString(); + } + return nullptr; +} + +oatpp::String Request::getPathVariable(const oatpp::data::share::StringKeyLabel& name) const { + return m_pathVariables.getVariable(name); +} + +oatpp::String Request::getPathTail() const { + return m_pathVariables.getTail(); +} + +void Request::streamBody(const std::shared_ptr& toStream) const { + m_bodyDecoder->decode(m_headers, m_bodyStream, toStream); +} + +oatpp::String Request::readBodyToString() const { + return m_bodyDecoder->decodeToString(m_headers, m_bodyStream); +} + +oatpp::async::Action Request::streamBodyAsync(oatpp::async::AbstractCoroutine* parentCoroutine, + const oatpp::async::Action& actionOnReturn, + const std::shared_ptr& toStream) const { + return m_bodyDecoder->decodeAsync(parentCoroutine, actionOnReturn, m_headers, m_bodyStream, toStream); +} + +}}}}} \ No newline at end of file diff --git a/src/oatpp/web/protocol/http/incoming/Request.hpp b/src/oatpp/web/protocol/http/incoming/Request.hpp index 9a2b2c92..ae5ca47f 100644 --- a/src/oatpp/web/protocol/http/incoming/Request.hpp +++ b/src/oatpp/web/protocol/http/incoming/Request.hpp @@ -31,7 +31,10 @@ #include "oatpp/network/Url.hpp" namespace oatpp { namespace web { namespace protocol { namespace http { namespace incoming { - + +/** + * Class http::incoming::Request AKA IncomingRequest represents client's incoming request + */ class Request : public oatpp::base::Controllable { public: OBJECT_POOL(Incoming_Request_Pool, Request, 32) @@ -42,53 +45,30 @@ private: url::mapping::Pattern::MatchMap m_pathVariables; http::Protocol::Headers m_headers; std::shared_ptr m_bodyStream; - - mutable bool m_queryParamsParsed; // used for lazy parsing of QueryParams - mutable http::Protocol::QueryParams m_queryParams; - /** + /* * Request should be preconfigured with default BodyDecoder. * Custom BodyDecoder can be set on demand */ std::shared_ptr m_bodyDecoder; + mutable bool m_queryParamsParsed; // used for lazy parsing of QueryParams + mutable http::Protocol::QueryParams m_queryParams; + public: - /* - Request(const std::shared_ptr& pBodyDecoder) - : bodyDecoder(pBodyDecoder) - {} - */ Request(const http::RequestStartingLine& startingLine, const url::mapping::Pattern::MatchMap& pathVariables, const http::Protocol::Headers& headers, const std::shared_ptr& bodyStream, - const std::shared_ptr& bodyDecoder - ) - : m_startingLine(startingLine) - , m_pathVariables(pathVariables) - , m_headers(headers) - , m_bodyStream(bodyStream) - , m_bodyDecoder(bodyDecoder) - , m_queryParamsParsed(false) - {} + const std::shared_ptr& bodyDecoder); public: static std::shared_ptr createShared(const http::RequestStartingLine& startingLine, const url::mapping::Pattern::MatchMap& pathVariables, const http::Protocol::Headers& headers, const std::shared_ptr& bodyStream, - const std::shared_ptr& bodyDecoder) { - return Shared_Incoming_Request_Pool::allocateShared(startingLine, pathVariables, headers, bodyStream, bodyDecoder); - } - - const http::RequestStartingLine& getStartingLine() const { - return m_startingLine; - } - - const url::mapping::Pattern::MatchMap& getPathVariables() const { - return m_pathVariables; - } + const std::shared_ptr& bodyDecoder); /** * Get map of url query parameters. @@ -96,74 +76,109 @@ public: * Please note: lazy parsing of query parameters is not thread-safe! * @return map for "&key=value" */ - const http::Protocol::QueryParams& getQueryParameters() const { - if(!m_queryParamsParsed) { - auto params = oatpp::network::Url::Parser::parseQueryParams(m_pathVariables.getTail()); - auto param = params->getFirstEntry(); - while(param != nullptr) { - m_queryParams[param->getKey()] = param->getValue(); - param = param->getNext(); - } - m_queryParamsParsed = true; - } - return m_queryParams; - } + const http::Protocol::QueryParams& getQueryParameters() const; - const http::Protocol::Headers& getHeaders() const { - return m_headers; - } - - std::shared_ptr getBodyStream() const { - return m_bodyStream; - } - - std::shared_ptr getBodyDecoder() const { - return m_bodyDecoder; - } - - oatpp::String getHeader(const oatpp::String& headerName) const{ - auto it = m_headers.find(headerName); - if(it != m_headers.end()) { - return it->second.toString(); - } - return nullptr; - } - - oatpp::String getPathVariable(const oatpp::data::share::StringKeyLabel& name) const { - return m_pathVariables.getVariable(name); - } - - oatpp::String getPathTail() const { - return m_pathVariables.getTail(); - } - - oatpp::String getQueryParameter(const oatpp::data::share::StringKeyLabel& name) const { - auto iter = getQueryParameters().find(name); - if (iter == getQueryParameters().end()) { - return nullptr; - } else { - return iter->second.toString(); - } - } - - oatpp::String getQueryParameter(const oatpp::data::share::StringKeyLabel& name, const oatpp::String& defaultValue) const { - auto value = getQueryParameter(name); - return value ? value : defaultValue; - } - - void streamBody(const std::shared_ptr& toStream) const { - m_bodyDecoder->decode(m_headers, m_bodyStream, toStream); - } - - oatpp::String readBodyToString() const { - return m_bodyDecoder->decodeToString(m_headers, m_bodyStream); - } - + /** + * Get query parameter value by name + * @param name + * @return query parameter value + */ + oatpp::String getQueryParameter(const oatpp::data::share::StringKeyLabel& name) const; + + /** + * + * @param name + * @param defaultValue + * @return query parameter value or defaultValue if no such parameter found + */ + oatpp::String getQueryParameter(const oatpp::data::share::StringKeyLabel& name, const oatpp::String& defaultValue) const; + + /** + * Get request starting line. (method, path, protocol) + * @return starting line structure + */ + const http::RequestStartingLine& getStartingLine() const; + + /** + * Get path variables according to path-pattern. + * Ex. given request path="/sum/19/1" for path-pattern="/sum/{a}/{b}" + * getPathVariables().getVariable("a") == 19, getPathVariables().getVariable("b") == 1. + * + * @return url MatchMap + */ + const url::mapping::Pattern::MatchMap& getPathVariables() const; + + /** + * Get request's headers map + * @return Headers map + */ + const http::Protocol::Headers& getHeaders() const; + + /** + * Get request's body stream + * @return body stream + */ + std::shared_ptr getBodyStream() const; + + /** + * Get body decoder. + * @return Body decoder + */ + std::shared_ptr getBodyDecoder() const; + + /** + * Get header value + * @param headerName + * @return header value + */ + oatpp::String getHeader(const oatpp::data::share::StringKeyLabelCI_FAST& headerName) const; + + /** + * Get path variable according to path-pattern + * @param name + * @return matched value for path-pattern + */ + oatpp::String getPathVariable(const oatpp::data::share::StringKeyLabel& name) const; + + /** + * Get path tail according to path-pattern + * Ex. given request path="/hello/path/tail" for path-pattern="/hello/\*" + * tail == "path/tail" + * note '/' symbol is required before '*' + * @return matched tail-value for path-pattern + */ + oatpp::String getPathTail() const; + + /** + * Stream content of the body-stream to toStream + * @param toStream + */ + void streamBody(const std::shared_ptr& toStream) const; + + /** + * Transfer body stream to string + * @return body as string + */ + oatpp::String readBodyToString() const; + + /** + * Transfer body to String and parse it as DTO + * @tparam Type + * @param objectMapper + * @return DTO + */ template typename Type::ObjectWrapper readBodyToDto(const std::shared_ptr& objectMapper) const { return objectMapper->readFromString(m_bodyDecoder->decodeToString(m_headers, m_bodyStream)); } - + + /** + * Transfer body to String and parse it as DTO + * (used in ApiController's codegens) + * @tparam Type + * @param objectMapper + * @return DTO + */ template void readBodyToDto(oatpp::data::mapping::type::PolymorphicWrapper& objectWrapper, const std::shared_ptr& objectMapper) const { @@ -171,19 +186,40 @@ public: } // Async - + + /** + * Transfer body stream to toStream Async + * @param parentCoroutine + * @param actionOnReturn + * @param toStream + * @return Start Coroutine Action + */ oatpp::async::Action streamBodyAsync(oatpp::async::AbstractCoroutine* parentCoroutine, const oatpp::async::Action& actionOnReturn, - const std::shared_ptr& toStream) const { - return m_bodyDecoder->decodeAsync(parentCoroutine, actionOnReturn, m_headers, m_bodyStream, toStream); - } - + const std::shared_ptr& toStream) const; + + /** + * Transfer body stream to string Async + * @tparam ParentCoroutineType + * @param parentCoroutine + * @param callback + * @return Start Coroutine Action + */ template oatpp::async::Action readBodyToStringAsync(oatpp::async::AbstractCoroutine* parentCoroutine, oatpp::async::Action (ParentCoroutineType::*callback)(const oatpp::String&)) const { return m_bodyDecoder->decodeToStringAsync(parentCoroutine, callback, m_headers, m_bodyStream); } - + + /** + * Transfer body to String and parse it as DTO + * @tparam DtoType + * @tparam ParentCoroutineType + * @param parentCoroutine + * @param callback + * @param objectMapper + * @return Start Coroutine Action + */ template oatpp::async::Action readBodyToDtoAsync(oatpp::async::AbstractCoroutine* parentCoroutine, oatpp::async::Action (ParentCoroutineType::*callback)(const typename DtoType::ObjectWrapper&), diff --git a/src/oatpp/web/protocol/http/incoming/Response.cpp b/src/oatpp/web/protocol/http/incoming/Response.cpp index 0e43d1e4..18094c7d 100644 --- a/src/oatpp/web/protocol/http/incoming/Response.cpp +++ b/src/oatpp/web/protocol/http/incoming/Response.cpp @@ -25,5 +25,59 @@ #include "./Response.hpp" namespace oatpp { namespace web { namespace protocol { namespace http { namespace incoming { - + +Response::Response(v_int32 statusCode, + const oatpp::String& statusDescription, + const http::Protocol::Headers& headers, + const std::shared_ptr& bodyStream, + const std::shared_ptr& bodyDecoder) + : m_statusCode(statusCode) + , m_statusDescription(statusDescription) + , m_headers(headers) + , m_bodyStream(bodyStream) + , m_bodyDecoder(bodyDecoder) +{} + +std::shared_ptr Response::createShared(v_int32 statusCode, + const oatpp::String& statusDescription, + const http::Protocol::Headers& headers, + const std::shared_ptr& bodyStream, + const std::shared_ptr& bodyDecoder) { + return Shared_Incoming_Response_Pool::allocateShared(statusCode, statusDescription, headers, bodyStream, bodyDecoder); +} + +v_int32 Response::getStatusCode() const { + return m_statusCode; +} + +oatpp::String Response::getStatusDescription() const { + return m_statusDescription; +} + +const http::Protocol::Headers& Response::getHeaders() const { + return m_headers; +} + +std::shared_ptr Response::getBodyStream() const { + return m_bodyStream; +} + +std::shared_ptr Response::getBodyDecoder() const { + return m_bodyDecoder; +} + +void Response::streamBody(const std::shared_ptr& toStream) const { + m_bodyDecoder->decode(m_headers, m_bodyStream, toStream); +} + +oatpp::String Response::readBodyToString() const { + return m_bodyDecoder->decodeToString(m_headers, m_bodyStream); +} + +oatpp::async::Action Response::streamBodyAsync(oatpp::async::AbstractCoroutine* parentCoroutine, + const oatpp::async::Action& actionOnReturn, + const std::shared_ptr& toStream) const { + return m_bodyDecoder->decodeAsync(parentCoroutine, actionOnReturn, m_headers, m_bodyStream, toStream); +} + }}}}} diff --git a/src/oatpp/web/protocol/http/incoming/Response.hpp b/src/oatpp/web/protocol/http/incoming/Response.hpp index aa3058ca..10903e9c 100644 --- a/src/oatpp/web/protocol/http/incoming/Response.hpp +++ b/src/oatpp/web/protocol/http/incoming/Response.hpp @@ -29,7 +29,10 @@ #include "oatpp/web/protocol/http/incoming/BodyDecoder.hpp" namespace oatpp { namespace web { namespace protocol { namespace http { namespace incoming { - + +/** + * Class http::incoming::Response AKA IncomingResponse represents server's incoming response + */ class Response : public oatpp::base::Controllable { public: OBJECT_POOL(Incoming_Response_Pool, Response, 32) @@ -54,50 +57,28 @@ public: const oatpp::String& statusDescription, const http::Protocol::Headers& headers, const std::shared_ptr& bodyStream, - const std::shared_ptr& bodyDecoder) - : m_statusCode(statusCode) - , m_statusDescription(statusDescription) - , m_headers(headers) - , m_bodyStream(bodyStream) - , m_bodyDecoder(bodyDecoder) - {} + const std::shared_ptr& bodyDecoder); public: static std::shared_ptr createShared(v_int32 statusCode, const oatpp::String& statusDescription, const http::Protocol::Headers& headers, const std::shared_ptr& bodyStream, - const std::shared_ptr& bodyDecoder) { - return Shared_Incoming_Response_Pool::allocateShared(statusCode, statusDescription, headers, bodyStream, bodyDecoder); - } + const std::shared_ptr& bodyDecoder); - v_int32 getStatusCode() const { - return m_statusCode; - } + v_int32 getStatusCode() const; - oatpp::String getStatusDescription() const { - return m_statusDescription; - } + oatpp::String getStatusDescription() const; - const http::Protocol::Headers& getHeaders() const { - return m_headers; - } + const http::Protocol::Headers& getHeaders() const; - std::shared_ptr getBodyStream() const { - return m_bodyStream; - } + std::shared_ptr getBodyStream() const; - std::shared_ptr getBodyDecoder() const { - return m_bodyDecoder; - } + std::shared_ptr getBodyDecoder() const; - void streamBody(const std::shared_ptr& toStream) const { - m_bodyDecoder->decode(m_headers, m_bodyStream, toStream); - } + void streamBody(const std::shared_ptr& toStream) const; - oatpp::String readBodyToString() const { - return m_bodyDecoder->decodeToString(m_headers, m_bodyStream); - } + oatpp::String readBodyToString() const; template typename Type::ObjectWrapper readBodyToDto(const std::shared_ptr& objectMapper) const { @@ -108,9 +89,7 @@ public: oatpp::async::Action streamBodyAsync(oatpp::async::AbstractCoroutine* parentCoroutine, const oatpp::async::Action& actionOnReturn, - const std::shared_ptr& toStream) const { - return m_bodyDecoder->decodeAsync(parentCoroutine, actionOnReturn, m_headers, m_bodyStream, toStream); - } + const std::shared_ptr& toStream) const; template oatpp::async::Action readBodyToStringAsync(oatpp::async::AbstractCoroutine* parentCoroutine, diff --git a/src/oatpp/web/protocol/http/outgoing/BufferBody.cpp b/src/oatpp/web/protocol/http/outgoing/BufferBody.cpp index 0425790e..da33072f 100644 --- a/src/oatpp/web/protocol/http/outgoing/BufferBody.cpp +++ b/src/oatpp/web/protocol/http/outgoing/BufferBody.cpp @@ -23,3 +23,42 @@ ***************************************************************************/ #include "BufferBody.hpp" + +namespace oatpp { namespace web { namespace protocol { namespace http { namespace outgoing { + +BufferBody::WriteToStreamCoroutine::WriteToStreamCoroutine(const std::shared_ptr& body, + const std::shared_ptr& stream) + : m_body(body) + , m_stream(stream) + , m_currData(m_body->m_buffer->getData()) + , m_currDataSize(m_body->m_buffer->getSize()) +{} + +async::Action BufferBody::WriteToStreamCoroutine::act() { + return oatpp::data::stream::writeExactSizeDataAsyncInline(m_stream.get(), m_currData, m_currDataSize, finish()); +} + +BufferBody::BufferBody(const oatpp::String& buffer) + : m_buffer(buffer) +{} + +std::shared_ptr BufferBody::createShared(const oatpp::String& buffer) { + return Shared_Http_Outgoing_BufferBody_Pool::allocateShared(buffer); +} + +void BufferBody::declareHeaders(Headers& headers) noexcept { + headers[oatpp::web::protocol::http::Header::CONTENT_LENGTH] = oatpp::utils::conversion::int32ToStr(m_buffer->getSize()); +} + +void BufferBody::writeToStream(const std::shared_ptr& stream) noexcept { + oatpp::data::stream::writeExactSizeData(stream.get(), m_buffer->getData(), m_buffer->getSize()); +} + + +async::Action BufferBody::writeToStreamAsync(oatpp::async::AbstractCoroutine* parentCoroutine, + const Action& actionOnReturn, + const std::shared_ptr& stream) { + return parentCoroutine->startCoroutine(actionOnReturn, getSharedPtr(), stream); +} + +}}}}} \ No newline at end of file diff --git a/src/oatpp/web/protocol/http/outgoing/BufferBody.hpp b/src/oatpp/web/protocol/http/outgoing/BufferBody.hpp index e8bf964d..13291fec 100644 --- a/src/oatpp/web/protocol/http/outgoing/BufferBody.hpp +++ b/src/oatpp/web/protocol/http/outgoing/BufferBody.hpp @@ -38,22 +38,12 @@ public: private: oatpp::String m_buffer; public: - BufferBody(const oatpp::String& buffer) - : m_buffer(buffer) - {} + BufferBody(const oatpp::String& buffer); public: - static std::shared_ptr createShared(const oatpp::String& buffer) { - return Shared_Http_Outgoing_BufferBody_Pool::allocateShared(buffer); - } - - void declareHeaders(Headers& headers) noexcept override { - headers[oatpp::web::protocol::http::Header::CONTENT_LENGTH] = oatpp::utils::conversion::int32ToStr(m_buffer->getSize()); - } - - void writeToStream(const std::shared_ptr& stream) noexcept override { - oatpp::data::stream::writeExactSizeData(stream.get(), m_buffer->getData(), m_buffer->getSize()); - } + static std::shared_ptr createShared(const oatpp::String& buffer); + void declareHeaders(Headers& headers) noexcept override; + void writeToStream(const std::shared_ptr& stream) noexcept override; public: @@ -66,16 +56,9 @@ public: public: WriteToStreamCoroutine(const std::shared_ptr& body, - const std::shared_ptr& stream) - : m_body(body) - , m_stream(stream) - , m_currData(m_body->m_buffer->getData()) - , m_currDataSize(m_body->m_buffer->getSize()) - {} + const std::shared_ptr& stream); - Action act() override { - return oatpp::data::stream::writeExactSizeDataAsyncInline(m_stream.get(), m_currData, m_currDataSize, finish()); - } + Action act() override; }; @@ -83,9 +66,7 @@ public: Action writeToStreamAsync(oatpp::async::AbstractCoroutine* parentCoroutine, const Action& actionOnReturn, - const std::shared_ptr& stream) override { - return parentCoroutine->startCoroutine(actionOnReturn, getSharedPtr(), stream); - } + const std::shared_ptr& stream) override; }; diff --git a/src/oatpp/web/protocol/http/outgoing/ChunkedBufferBody.cpp b/src/oatpp/web/protocol/http/outgoing/ChunkedBufferBody.cpp index 9c8ccfdc..e4afa3df 100644 --- a/src/oatpp/web/protocol/http/outgoing/ChunkedBufferBody.cpp +++ b/src/oatpp/web/protocol/http/outgoing/ChunkedBufferBody.cpp @@ -27,5 +27,105 @@ namespace oatpp { namespace web { namespace protocol { namespace http { namespace outgoing { const char* ChunkedBufferBody::ERROR_FAILED_TO_WRITE_DATA = "ERROR_FAILED_TO_WRITE_DATA"; - + +ChunkedBufferBody::ChunkedBufferBody(const std::shared_ptr& buffer, bool chunked) + : m_buffer(buffer) + , m_chunked(chunked) +{} + + +std::shared_ptr ChunkedBufferBody::createShared(const std::shared_ptr& buffer) { + return Shared_Http_Outgoing_ChunkedBufferBody_Pool::allocateShared(buffer, false); +} + +std::shared_ptr ChunkedBufferBody::createShared(const std::shared_ptr& buffer, bool chunked) { + return Shared_Http_Outgoing_ChunkedBufferBody_Pool::allocateShared(buffer, chunked); +} + +void ChunkedBufferBody::declareHeaders(Headers& headers) noexcept { + if(m_chunked){ + headers[oatpp::web::protocol::http::Header::TRANSFER_ENCODING] = oatpp::web::protocol::http::Header::Value::TRANSFER_ENCODING_CHUNKED; + } else { + headers[oatpp::web::protocol::http::Header::CONTENT_LENGTH] = oatpp::utils::conversion::int64ToStr(m_buffer->getSize()); + } +} + +void ChunkedBufferBody::writeToStream(const std::shared_ptr& stream) noexcept { + if(m_chunked) { + auto chunks = m_buffer->getChunks(); + auto curr = chunks->getFirstNode(); + while (curr != nullptr) { + stream->write(oatpp::utils::conversion::primitiveToStr(curr->getData()->size, "%X")); + stream->write("\r\n", 2); + stream->write(curr->getData()->data, curr->getData()->size); + stream->write("\r\n", 2); + curr = curr->getNext(); + } + stream->write("0\r\n\r\n", 5); + } else { + m_buffer->flushToStream(stream); + } +} + +ChunkedBufferBody::WriteToStreamCoroutine::WriteToStreamCoroutine(const std::shared_ptr& body, + const std::shared_ptr& stream) + : m_body(body) + , m_stream(stream) + , m_chunks(m_body->m_buffer->getChunks()) + , m_currChunk(m_chunks->getFirstNode()) + , m_currData(nullptr) + , m_currDataSize(0) + , m_nextAction(Action(Action::TYPE_FINISH, nullptr, nullptr)) +{} + +async::Action ChunkedBufferBody::WriteToStreamCoroutine::act() { + if(m_currChunk == nullptr) { + return yieldTo(&WriteToStreamCoroutine::writeEndOfChunks); + } + return yieldTo(&WriteToStreamCoroutine::writeChunkSize); +} + +async::Action ChunkedBufferBody::WriteToStreamCoroutine::writeChunkSize() { + m_currDataSize = oatpp::utils::conversion::primitiveToCharSequence(m_currChunk->getData()->size, m_buffer, "%X\r\n"); + m_currData = m_buffer; + m_nextAction = yieldTo(&WriteToStreamCoroutine::writeChunkData); + return yieldTo(&WriteToStreamCoroutine::writeCurrData); +} + +async::Action ChunkedBufferBody::WriteToStreamCoroutine::writeChunkData() { + m_currData = m_currChunk->getData()->data; + m_currDataSize = (v_int32) m_currChunk->getData()->size; + m_nextAction = yieldTo(&WriteToStreamCoroutine::writeChunkSeparator); + return yieldTo(&WriteToStreamCoroutine::writeCurrData); +} + +async::Action ChunkedBufferBody::WriteToStreamCoroutine::writeChunkSeparator() { + m_currData = (void*) "\r\n"; + m_currDataSize = 2; + m_currChunk = m_currChunk->getNext(); + m_nextAction = yieldTo(&WriteToStreamCoroutine::act); + return yieldTo(&WriteToStreamCoroutine::writeCurrData); +} + +async::Action ChunkedBufferBody::WriteToStreamCoroutine::writeEndOfChunks() { + m_currData = (void*) "0\r\n\r\n"; + m_currDataSize = 5; + m_nextAction = finish(); + return yieldTo(&WriteToStreamCoroutine::writeCurrData); +} + +async::Action ChunkedBufferBody::WriteToStreamCoroutine::writeCurrData() { + return oatpp::data::stream::writeExactSizeDataAsyncInline(m_stream.get(), m_currData, m_currDataSize, m_nextAction); +} + +async::Action ChunkedBufferBody::writeToStreamAsync(oatpp::async::AbstractCoroutine* parentCoroutine, + const Action& actionOnFinish, + const std::shared_ptr& stream) { + if(m_chunked) { + return parentCoroutine->startCoroutine(actionOnFinish, getSharedPtr(), stream); + } else { + return m_buffer->flushToStreamAsync(parentCoroutine, actionOnFinish, stream); + } +} + }}}}} diff --git a/src/oatpp/web/protocol/http/outgoing/ChunkedBufferBody.hpp b/src/oatpp/web/protocol/http/outgoing/ChunkedBufferBody.hpp index f43a59d0..2219b565 100644 --- a/src/oatpp/web/protocol/http/outgoing/ChunkedBufferBody.hpp +++ b/src/oatpp/web/protocol/http/outgoing/ChunkedBufferBody.hpp @@ -42,46 +42,16 @@ protected: std::shared_ptr m_buffer; bool m_chunked; public: - ChunkedBufferBody(const std::shared_ptr& buffer, - bool chunked) - : m_buffer(buffer) - , m_chunked(chunked) - {} + ChunkedBufferBody(const std::shared_ptr& buffer, bool chunked); public: - static std::shared_ptr createShared(const std::shared_ptr& buffer) { - return Shared_Http_Outgoing_ChunkedBufferBody_Pool::allocateShared(buffer, false); - } + static std::shared_ptr createShared(const std::shared_ptr& buffer); - static std::shared_ptr createShared(const std::shared_ptr& buffer, - bool chunked) { - return Shared_Http_Outgoing_ChunkedBufferBody_Pool::allocateShared(buffer, chunked); - } + static std::shared_ptr createShared(const std::shared_ptr& buffer, bool chunked); - void declareHeaders(Headers& headers) noexcept override { - if(m_chunked){ - headers[oatpp::web::protocol::http::Header::TRANSFER_ENCODING] = oatpp::web::protocol::http::Header::Value::TRANSFER_ENCODING_CHUNKED; - } else { - headers[oatpp::web::protocol::http::Header::CONTENT_LENGTH] = oatpp::utils::conversion::int64ToStr(m_buffer->getSize()); - } - } + void declareHeaders(Headers& headers) noexcept override; - void writeToStream(const std::shared_ptr& stream) noexcept override { - if(m_chunked){ - auto chunks = m_buffer->getChunks(); - auto curr = chunks->getFirstNode(); - while (curr != nullptr) { - stream->write(oatpp::utils::conversion::primitiveToStr(curr->getData()->size, "%X")); - stream->write("\r\n", 2); - stream->write(curr->getData()->data, curr->getData()->size); - stream->write("\r\n", 2); - curr = curr->getNext(); - } - stream->write("0\r\n\r\n", 5); - } else { - m_buffer->flushToStream(stream); - } - } + void writeToStream(const std::shared_ptr& stream) noexcept override; public: @@ -98,67 +68,20 @@ public: public: WriteToStreamCoroutine(const std::shared_ptr& body, - const std::shared_ptr& stream) - : m_body(body) - , m_stream(stream) - , m_chunks(m_body->m_buffer->getChunks()) - , m_currChunk(m_chunks->getFirstNode()) - , m_currData(nullptr) - , m_currDataSize(0) - , m_nextAction(Action(Action::TYPE_FINISH, nullptr, nullptr)) - {} + const std::shared_ptr& stream); - Action act() override { - if(m_currChunk == nullptr) { - return yieldTo(&WriteToStreamCoroutine::writeEndOfChunks); - } - return yieldTo(&WriteToStreamCoroutine::writeChunkSize); - } - - Action writeChunkSize() { - m_currDataSize = oatpp::utils::conversion::primitiveToCharSequence(m_currChunk->getData()->size, m_buffer, "%X\r\n"); - m_currData = m_buffer; - m_nextAction = yieldTo(&WriteToStreamCoroutine::writeChunkData); - return yieldTo(&WriteToStreamCoroutine::writeCurrData); - } - - Action writeChunkData() { - m_currData = m_currChunk->getData()->data; - m_currDataSize = (v_int32) m_currChunk->getData()->size; - m_nextAction = yieldTo(&WriteToStreamCoroutine::writeChunkSeparator); - return yieldTo(&WriteToStreamCoroutine::writeCurrData); - } - - Action writeChunkSeparator() { - m_currData = (void*) "\r\n"; - m_currDataSize = 2; - m_currChunk = m_currChunk->getNext(); - m_nextAction = yieldTo(&WriteToStreamCoroutine::act); - return yieldTo(&WriteToStreamCoroutine::writeCurrData); - } - - Action writeEndOfChunks() { - m_currData = (void*) "0\r\n\r\n"; - m_currDataSize = 5; - m_nextAction = finish(); - return yieldTo(&WriteToStreamCoroutine::writeCurrData); - } - - Action writeCurrData() { - return oatpp::data::stream::writeExactSizeDataAsyncInline(m_stream.get(), m_currData, m_currDataSize, m_nextAction); - } + Action act() override; + Action writeChunkSize(); + Action writeChunkData(); + Action writeChunkSeparator(); + Action writeEndOfChunks(); + Action writeCurrData(); }; Action writeToStreamAsync(oatpp::async::AbstractCoroutine* parentCoroutine, const Action& actionOnFinish, - const std::shared_ptr& stream) override { - if(m_chunked) { - return parentCoroutine->startCoroutine(actionOnFinish, getSharedPtr(), stream); - } else { - return m_buffer->flushToStreamAsync(parentCoroutine, actionOnFinish, stream); - } - } + const std::shared_ptr& stream) override; }; diff --git a/src/oatpp/web/protocol/http/outgoing/DtoBody.cpp b/src/oatpp/web/protocol/http/outgoing/DtoBody.cpp index e85f229e..584dbb71 100644 --- a/src/oatpp/web/protocol/http/outgoing/DtoBody.cpp +++ b/src/oatpp/web/protocol/http/outgoing/DtoBody.cpp @@ -23,3 +23,38 @@ ***************************************************************************/ #include "./DtoBody.hpp" + +namespace oatpp { namespace web { namespace protocol { namespace http { namespace outgoing { + +DtoBody::DtoBody(const oatpp::data::mapping::type::AbstractObjectWrapper& dto, + oatpp::data::mapping::ObjectMapper* objectMapper, + bool chunked) + : ChunkedBufferBody(oatpp::data::stream::ChunkedBuffer::createShared(), chunked) + , m_dto(dto) + , m_objectMapper(objectMapper) +{} + +std::shared_ptr DtoBody::createShared(const oatpp::data::mapping::type::AbstractObjectWrapper& dto, + oatpp::data::mapping::ObjectMapper* objectMapper) { + return Shared_Http_Outgoing_DtoBody_Pool::allocateShared(dto, objectMapper, false); +} + +std::shared_ptr DtoBody::createShared(const oatpp::data::mapping::type::AbstractObjectWrapper& dto, + oatpp::data::mapping::ObjectMapper* objectMapper, + bool chunked) { + return Shared_Http_Outgoing_DtoBody_Pool::allocateShared(dto, objectMapper, chunked); +} + +void DtoBody::declareHeaders(Headers& headers) noexcept { + if(m_dto) { + m_objectMapper->write(m_buffer, m_dto); + } + ChunkedBufferBody::declareHeaders(headers); + + auto it = headers.find(Header::CONTENT_TYPE); + if(it == headers.end()) { + headers[Header::CONTENT_TYPE] = m_objectMapper->getInfo().http_content_type; + } +} + +}}}}} \ No newline at end of file diff --git a/src/oatpp/web/protocol/http/outgoing/DtoBody.hpp b/src/oatpp/web/protocol/http/outgoing/DtoBody.hpp index 4f8940be..1590c306 100644 --- a/src/oatpp/web/protocol/http/outgoing/DtoBody.hpp +++ b/src/oatpp/web/protocol/http/outgoing/DtoBody.hpp @@ -42,35 +42,17 @@ private: public: DtoBody(const oatpp::data::mapping::type::AbstractObjectWrapper& dto, oatpp::data::mapping::ObjectMapper* objectMapper, - bool chunked) - : ChunkedBufferBody(oatpp::data::stream::ChunkedBuffer::createShared(), chunked) - , m_dto(dto) - , m_objectMapper(objectMapper) - {} + bool chunked); public: static std::shared_ptr createShared(const oatpp::data::mapping::type::AbstractObjectWrapper& dto, - oatpp::data::mapping::ObjectMapper* objectMapper) { - return Shared_Http_Outgoing_DtoBody_Pool::allocateShared(dto, objectMapper, false); - } + oatpp::data::mapping::ObjectMapper* objectMapper); static std::shared_ptr createShared(const oatpp::data::mapping::type::AbstractObjectWrapper& dto, oatpp::data::mapping::ObjectMapper* objectMapper, - bool chunked) { - return Shared_Http_Outgoing_DtoBody_Pool::allocateShared(dto, objectMapper, chunked); - } + bool chunked); - void declareHeaders(Headers& headers) noexcept override { - if(m_dto) { - m_objectMapper->write(m_buffer, m_dto); - } - ChunkedBufferBody::declareHeaders(headers); - - auto it = headers.find(Header::CONTENT_TYPE); - if(it == headers.end()) { - headers[Header::CONTENT_TYPE] = m_objectMapper->getInfo().http_content_type; - } - } + void declareHeaders(Headers& headers) noexcept override; }; diff --git a/src/oatpp/web/protocol/http/outgoing/Request.cpp b/src/oatpp/web/protocol/http/outgoing/Request.cpp index 4fbafb64..ac9172b7 100644 --- a/src/oatpp/web/protocol/http/outgoing/Request.cpp +++ b/src/oatpp/web/protocol/http/outgoing/Request.cpp @@ -26,7 +26,55 @@ #include "oatpp/core/data/stream/ChunkedBuffer.hpp" namespace oatpp { namespace web { namespace protocol { namespace http { namespace outgoing { - + +Request::Request() {} + +Request::Request(const oatpp::data::share::StringKeyLabel& method, + const oatpp::data::share::StringKeyLabel& path, + const Headers& headers, + const std::shared_ptr& body) + : m_method(method) + , m_path(path) + , m_headers(headers) + , m_body(body) +{} + +std::shared_ptr Request::createShared(const oatpp::data::share::StringKeyLabel& method, + const oatpp::data::share::StringKeyLabel& path, + const Headers& headers, + const std::shared_ptr& body) { + return Shared_Outgoing_Request_Pool::allocateShared(method, path, headers, body); +} + +const oatpp::data::share::StringKeyLabel& Request::getMethod() const { + return m_method; +} + +const oatpp::data::share::StringKeyLabel& Request::getPath() const { + return m_path; +} + +protocol::http::Protocol::Headers& Request::getHeaders() { + return m_headers; +} + +void Request::putHeader(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value) { + m_headers[key] = value; +} + +bool Request::putHeaderIfNotExists(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value) { + auto it = m_headers.find(key); + if(it == m_headers.end()) { + m_headers.insert({key, value}); + return true; + } + return false; +} + +std::shared_ptr Request::getBody() { + return m_body; +} + void Request::send(const std::shared_ptr& stream){ if(m_body){ diff --git a/src/oatpp/web/protocol/http/outgoing/Request.hpp b/src/oatpp/web/protocol/http/outgoing/Request.hpp index 52515ee4..9d2d7fc4 100644 --- a/src/oatpp/web/protocol/http/outgoing/Request.hpp +++ b/src/oatpp/web/protocol/http/outgoing/Request.hpp @@ -43,55 +43,31 @@ private: std::shared_ptr m_body; public: - Request() {} + Request(); Request(const oatpp::data::share::StringKeyLabel& method, const oatpp::data::share::StringKeyLabel& path, const Headers& headers, - const std::shared_ptr& body) - : m_method(method) - , m_path(path) - , m_headers(headers) - , m_body(body) - {} + const std::shared_ptr& body); public: static std::shared_ptr createShared(const oatpp::data::share::StringKeyLabel& method, const oatpp::data::share::StringKeyLabel& path, const Headers& headers, - const std::shared_ptr& body) { - return Shared_Outgoing_Request_Pool::allocateShared(method, path, headers, body); - } + const std::shared_ptr& body); - const oatpp::data::share::StringKeyLabel& getMethod() const { - return m_method; - } + const oatpp::data::share::StringKeyLabel& getMethod() const; - const oatpp::data::share::StringKeyLabel& getPath() const { - return m_path; - } + const oatpp::data::share::StringKeyLabel& getPath() const; - Headers& getHeaders() { - return m_headers; - } + Headers& getHeaders(); - void putHeader(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value) { - m_headers[key] = value; - } + void putHeader(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value); - bool putHeaderIfNotExists(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value) { - auto it = m_headers.find(key); - if(it == m_headers.end()) { - m_headers.insert({key, value}); - return true; - } - return false; - } + bool putHeaderIfNotExists(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value); - std::shared_ptr getBody() { - return m_body; - } + std::shared_ptr getBody(); void send(const std::shared_ptr& stream); diff --git a/src/oatpp/web/protocol/http/outgoing/Response.cpp b/src/oatpp/web/protocol/http/outgoing/Response.cpp index 760de47b..c8d39aca 100644 --- a/src/oatpp/web/protocol/http/outgoing/Response.cpp +++ b/src/oatpp/web/protocol/http/outgoing/Response.cpp @@ -27,7 +27,47 @@ #include "oatpp/core/data/stream/ChunkedBuffer.hpp" namespace oatpp { namespace web { namespace protocol { namespace http { namespace outgoing { - + +Response::Response(const Status& status, + const std::shared_ptr& body) + : m_status(status) + , m_body(body) +{} + +std::shared_ptr Response::createShared(const Status& status, + const std::shared_ptr& body) { + return Shared_Outgoing_Response_Pool::allocateShared(status, body); +} + +const Status& Response::getStatus() const { + return m_status; +} + +protocol::http::Protocol::Headers& Response::getHeaders() { + return m_headers; +} + +void Response::putHeader(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value) { + m_headers[key] = value; +} + +bool Response::putHeaderIfNotExists(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value) { + auto it = m_headers.find(key); + if(it == m_headers.end()) { + m_headers.insert({key, value}); + return true; + } + return false; +} + +void Response::setConnectionUpgradeHandler(const std::shared_ptr& handler) { + m_connectionUpgradeHandler = handler; +} + +std::shared_ptr Response::getConnectionUpgradeHandler() { + return m_connectionUpgradeHandler; +} + void Response::send(const std::shared_ptr& stream) { if(m_body){ diff --git a/src/oatpp/web/protocol/http/outgoing/Response.hpp b/src/oatpp/web/protocol/http/outgoing/Response.hpp index 31db02b2..ef9a7bef 100644 --- a/src/oatpp/web/protocol/http/outgoing/Response.hpp +++ b/src/oatpp/web/protocol/http/outgoing/Response.hpp @@ -44,46 +44,22 @@ private: std::shared_ptr m_body; std::shared_ptr m_connectionUpgradeHandler; public: - Response(const Status& status, - const std::shared_ptr& body) - : m_status(status) - , m_body(body) - {} + Response(const Status& status, const std::shared_ptr& body); public: - static std::shared_ptr createShared(const Status& status, - const std::shared_ptr& body) { - return Shared_Outgoing_Response_Pool::allocateShared(status, body); - } + static std::shared_ptr createShared(const Status& status, const std::shared_ptr& body); - const Status& getStatus() const { - return m_status; - } + const Status& getStatus() const; - Headers& getHeaders() { - return m_headers; - } + Headers& getHeaders(); - void putHeader(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value) { - m_headers[key] = value; - } + void putHeader(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value); - bool putHeaderIfNotExists(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value) { - auto it = m_headers.find(key); - if(it == m_headers.end()) { - m_headers.insert({key, value}); - return true; - } - return false; - } + bool putHeaderIfNotExists(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value); - void setConnectionUpgradeHandler(const std::shared_ptr& handler) { - m_connectionUpgradeHandler = handler; - } + void setConnectionUpgradeHandler(const std::shared_ptr& handler); - std::shared_ptr getConnectionUpgradeHandler() { - return m_connectionUpgradeHandler; - } + std::shared_ptr getConnectionUpgradeHandler(); void send(const std::shared_ptr& stream); diff --git a/src/oatpp/web/server/api/Endpoint.cpp b/src/oatpp/web/server/api/Endpoint.cpp index 13106b51..75049eed 100644 --- a/src/oatpp/web/server/api/Endpoint.cpp +++ b/src/oatpp/web/server/api/Endpoint.cpp @@ -29,7 +29,7 @@ namespace oatpp { namespace web { namespace server { namespace api { oatpp::String Endpoint::Info::toString() { - auto stream = oatpp::data::stream::ChunkedBuffer::createShared(); + oatpp::data::stream::ChunkedBuffer stream; stream << "\nEndpoint\n"; @@ -61,7 +61,7 @@ oatpp::String Endpoint::Info::toString() { stream << "pathParam: '" << param.name << "', type: '" << param.type->name << "'\n"; } - return stream->toString(); + return stream.toString(); } }}}} diff --git a/src/oatpp/web/server/handler/ErrorHandler.cpp b/src/oatpp/web/server/handler/ErrorHandler.cpp index 12c10e84..3220f02f 100644 --- a/src/oatpp/web/server/handler/ErrorHandler.cpp +++ b/src/oatpp/web/server/handler/ErrorHandler.cpp @@ -33,12 +33,10 @@ std::shared_ptr DefaultErrorHandler::handleError(const protocol::http::Status& status, const oatpp::String& message) { auto stream = oatpp::data::stream::ChunkedBuffer::createShared(); - stream << "server=" << protocol::http::Header::Value::SERVER << "\n"; - stream << "code="; - stream->writeAsString(status.code); - stream << "\n"; - stream << "description=" << status.description << "\n"; - stream << "message=" << message << "\n"; + *stream << "server=" << protocol::http::Header::Value::SERVER << "\n"; + *stream << "code=" << status.code << "\n"; + *stream << "description=" << status.description << "\n"; + *stream << "message=" << message << "\n"; auto response = protocol::http::outgoing::Response::createShared (status, protocol::http::outgoing::ChunkedBufferBody::createShared(stream)); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cc033a11..b55fdf73 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -15,10 +15,14 @@ add_executable(oatppAllTests oatpp/core/data/mapping/type/TypeTest.hpp oatpp/core/data/share/MemoryLabelTest.cpp oatpp/core/data/share/MemoryLabelTest.hpp + oatpp/core/data/stream/ChunkedBufferTest.cpp + oatpp/core/data/stream/ChunkedBufferTest.hpp oatpp/encoding/Base64Test.cpp oatpp/encoding/Base64Test.hpp oatpp/encoding/UnicodeTest.cpp oatpp/encoding/UnicodeTest.hpp + oatpp/network/UrlTest.cpp + oatpp/network/UrlTest.hpp oatpp/network/virtual_/InterfaceTest.cpp oatpp/network/virtual_/InterfaceTest.hpp oatpp/network/virtual_/PipeTest.cpp diff --git a/test/oatpp/AllTestsMain.cpp b/test/oatpp/AllTestsMain.cpp index 005c9a9d..14a819b0 100644 --- a/test/oatpp/AllTestsMain.cpp +++ b/test/oatpp/AllTestsMain.cpp @@ -4,7 +4,9 @@ #include "oatpp/network/virtual_/PipeTest.hpp" #include "oatpp/network/virtual_/InterfaceTest.hpp" +#include "oatpp/network/UrlTest.hpp" +#include "oatpp/core/data/stream/ChunkedBufferTest.hpp" #include "oatpp/core/data/share/MemoryLabelTest.hpp" #include "oatpp/parser/json/mapping/DeserializerTest.hpp" @@ -51,18 +53,25 @@ void runTests() { OATPP_RUN_TEST(oatpp::test::base::RegRuleTest); OATPP_RUN_TEST(oatpp::test::base::CommandLineArgumentsTest); + OATPP_RUN_TEST(oatpp::test::memory::MemoryPoolTest); OATPP_RUN_TEST(oatpp::test::memory::PerfTest); + OATPP_RUN_TEST(oatpp::test::collection::LinkedListTest); + + OATPP_RUN_TEST(oatpp::test::core::data::share::MemoryLabelTest); + OATPP_RUN_TEST(oatpp::test::core::data::stream::ChunkedBufferTest); OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::TypeTest); + OATPP_RUN_TEST(oatpp::test::parser::CaretTest); OATPP_RUN_TEST(oatpp::test::parser::json::mapping::DeserializerTest); OATPP_RUN_TEST(oatpp::test::parser::json::mapping::DTOMapperPerfTest); OATPP_RUN_TEST(oatpp::test::parser::json::mapping::DTOMapperTest); + OATPP_RUN_TEST(oatpp::test::encoding::Base64Test); OATPP_RUN_TEST(oatpp::test::encoding::UnicodeTest); - OATPP_RUN_TEST(oatpp::test::core::data::share::MemoryLabelTest); + OATPP_RUN_TEST(oatpp::test::network::UrlTest); OATPP_RUN_TEST(oatpp::test::network::virtual_::PipeTest); OATPP_RUN_TEST(oatpp::test::network::virtual_::InterfaceTest); diff --git a/test/oatpp/core/data/stream/ChunkedBufferTest.cpp b/test/oatpp/core/data/stream/ChunkedBufferTest.cpp new file mode 100644 index 00000000..a039db46 --- /dev/null +++ b/test/oatpp/core/data/stream/ChunkedBufferTest.cpp @@ -0,0 +1,129 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present, Leonid Stryzhevskyi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ***************************************************************************/ + +#include "ChunkedBufferTest.hpp" + +#include "oatpp/core/data/stream/ChunkedBuffer.hpp" +#include "oatpp/core/utils/ConversionUtils.hpp" + +namespace oatpp { namespace test { namespace core { namespace data { namespace stream { + +void ChunkedBufferTest::onRun() { + + typedef oatpp::data::stream::ChunkedBuffer ChunkedBuffer; + + { + ChunkedBuffer stream; + + stream << "int=" << 1 << ", float=" << 1.1 << ", " + << "bool=" << true << " or " << false; + + OATPP_LOGD(TAG, "str='%s'", stream.toString()->c_str()); + + stream.clear(); + stream << 101; + OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::int32ToStr(101)); + + stream.clear(); + stream << (v_float32)101.1; + OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::float32ToStr(101.1)); + + stream.clear(); + stream << (v_float64)101.1; + OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::float64ToStr(101.1)); + + stream.clear(); + stream << true; + OATPP_ASSERT(stream.toString() == "true"); + + stream.clear(); + stream << false; + OATPP_ASSERT(stream.toString() == "false"); + + stream.clear(); + stream << oatpp::String("oat++"); + OATPP_ASSERT(stream.toString() == "oat++"); + + stream.clear(); + stream << oatpp::Int8(8); + OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::int32ToStr(8)); + + stream.clear(); + stream << oatpp::Int16(16); + OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::int32ToStr(16)); + + stream.clear(); + stream << oatpp::Int32(32); + OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::int32ToStr(32)); + + stream.clear(); + stream << oatpp::Int64(64); + OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::int32ToStr(64)); + + stream.clear(); + stream << oatpp::Float32(0.32); + OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::float32ToStr(0.32)); + + stream.clear(); + stream << oatpp::Float64(0.64); + OATPP_ASSERT(stream.toString() == oatpp::utils::conversion::float64ToStr(0.64)); + + stream.clear(); + stream << oatpp::Boolean(true); + OATPP_ASSERT(stream.toString() == "true"); + + stream.clear(); + stream << oatpp::Boolean(false); + OATPP_ASSERT(stream.toString() == "false"); + + } + + { + + ChunkedBuffer stream; + + for(v_int32 i = 0; i < ChunkedBuffer::CHUNK_ENTRY_SIZE * 10; i++) { + stream.write("0123456789", 10); + } + + auto wholeText = stream.toString(); + + OATPP_ASSERT(wholeText->getSize() == ChunkedBuffer::CHUNK_ENTRY_SIZE * 10 * 10); + + v_int32 substringSize = 10; + for(v_int32 i = 0; i < wholeText->getSize() - substringSize; i ++) { + OATPP_ASSERT(oatpp::String((const char*)&wholeText->getData()[i], substringSize, false) == stream.getSubstring(i, substringSize)); + } + + substringSize = ChunkedBuffer::CHUNK_ENTRY_SIZE * 2; + for(v_int32 i = 0; i < wholeText->getSize() - substringSize; i ++) { + OATPP_ASSERT(oatpp::String((const char*)&wholeText->getData()[i], substringSize, false) == stream.getSubstring(i, substringSize)); + } + + } + + +} + +}}}}} \ No newline at end of file diff --git a/test/oatpp/core/data/stream/ChunkedBufferTest.hpp b/test/oatpp/core/data/stream/ChunkedBufferTest.hpp new file mode 100644 index 00000000..efabbb70 --- /dev/null +++ b/test/oatpp/core/data/stream/ChunkedBufferTest.hpp @@ -0,0 +1,43 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present, Leonid Stryzhevskyi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ***************************************************************************/ + +#ifndef oatpp_test_core_data_stream_ChunkedBufferTest_hpp +#define oatpp_test_core_data_stream_ChunkedBufferTest_hpp + +#include "oatpp-test/UnitTest.hpp" + +namespace oatpp { namespace test { namespace core { namespace data { namespace stream { + +class ChunkedBufferTest : public UnitTest{ +public: + + ChunkedBufferTest():UnitTest("TEST[core::data::stream::ChunkedBufferTest]"){} + void onRun() override; + +}; + +}}}}} + + +#endif //oatpp_test_core_data_stream_ChunkedBufferTest_hpp diff --git a/test/oatpp/network/UrlTest.cpp b/test/oatpp/network/UrlTest.cpp new file mode 100644 index 00000000..8641d541 --- /dev/null +++ b/test/oatpp/network/UrlTest.cpp @@ -0,0 +1,183 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present, Leonid Stryzhevskyi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ***************************************************************************/ + +#include "UrlTest.hpp" + +#include "oatpp/network/Url.hpp" + +#include "oatpp-test/Checker.hpp" + +namespace oatpp { namespace test { namespace network { + +void UrlTest::onRun() { + + typedef oatpp::network::Url Url; + + { + const char* urlText = "http://root@127.0.0.1:8000/path/to/resource/?q1=1&q2=2"; + OATPP_LOGD(TAG, "urlText='%s'", urlText); + auto url = Url::Parser::parseUrl(urlText); + + OATPP_ASSERT(url.scheme && url.scheme == "http"); + OATPP_ASSERT(url.authority.userInfo && url.authority.userInfo == "root"); + OATPP_ASSERT(url.authority.host && url.authority.host == "127.0.0.1"); + OATPP_ASSERT(url.authority.port == 8000); + OATPP_ASSERT(url.path && url.path == "/path/to/resource/"); + OATPP_ASSERT(url.queryParams.size() == 2); + OATPP_ASSERT(url.queryParams["q1"] == "1"); + OATPP_ASSERT(url.queryParams["q2"] == "2"); + } + + { + const char* urlText = "ftp://root@oatpp.io:8000/path/to/resource?q1=1&q2=2"; + OATPP_LOGD(TAG, "urlText='%s'", urlText); + auto url = Url::Parser::parseUrl(urlText); + + OATPP_ASSERT(url.scheme && url.scheme == "ftp"); + OATPP_ASSERT(url.authority.userInfo && url.authority.userInfo == "root"); + OATPP_ASSERT(url.authority.host && url.authority.host == "oatpp.io"); + OATPP_ASSERT(url.authority.port == 8000); + OATPP_ASSERT(url.path && url.path == "/path/to/resource"); + OATPP_ASSERT(url.queryParams.size() == 2); + OATPP_ASSERT(url.queryParams["q1"] == "1"); + OATPP_ASSERT(url.queryParams["q2"] == "2"); + } + + { + const char* urlText = "https://oatpp.io/?q1=1&q2=2"; + OATPP_LOGD(TAG, "urlText='%s'", urlText); + auto url = Url::Parser::parseUrl(urlText); + + OATPP_ASSERT(url.scheme && url.scheme == "https"); + OATPP_ASSERT(url.authority.userInfo == nullptr); + OATPP_ASSERT(url.authority.host && url.authority.host == "oatpp.io"); + OATPP_ASSERT(url.authority.port == -1); + OATPP_ASSERT(url.path && url.path == "/"); + OATPP_ASSERT(url.queryParams.size() == 2); + OATPP_ASSERT(url.queryParams["q1"] == "1"); + OATPP_ASSERT(url.queryParams["q2"] == "2"); + } + + { + const char* urlText = "https://oatpp.io/"; + OATPP_LOGD(TAG, "urlText='%s'", urlText); + auto url = Url::Parser::parseUrl(urlText); + + OATPP_ASSERT(url.scheme && url.scheme == "https"); + OATPP_ASSERT(url.authority.userInfo == nullptr); + OATPP_ASSERT(url.authority.host && url.authority.host == "oatpp.io"); + OATPP_ASSERT(url.authority.port == -1); + OATPP_ASSERT(url.path && url.path == "/"); + OATPP_ASSERT(url.queryParams.size() == 0); + } + + { + const char* urlText = "https://oatpp.io"; + OATPP_LOGD(TAG, "urlText='%s'", urlText); + auto url = Url::Parser::parseUrl(urlText); + + OATPP_ASSERT(url.scheme && url.scheme == "https"); + OATPP_ASSERT(url.authority.userInfo == nullptr); + OATPP_ASSERT(url.authority.host && url.authority.host == "oatpp.io"); + OATPP_ASSERT(url.authority.port == -1); + OATPP_ASSERT(url.path == nullptr); + OATPP_ASSERT(url.queryParams.size() == 0); + } + + { + const char* urlText = "oatpp.io"; + OATPP_LOGD(TAG, "urlText='%s'", urlText); + auto url = Url::Parser::parseUrl(urlText); + + OATPP_ASSERT(url.scheme == nullptr); + OATPP_ASSERT(url.authority.userInfo == nullptr); + OATPP_ASSERT(url.authority.host && url.authority.host == "oatpp.io"); + OATPP_ASSERT(url.authority.port == -1); + OATPP_ASSERT(url.path == nullptr); + OATPP_ASSERT(url.queryParams.size() == 0); + } + + { + const char* urlText = "?key1=value1&key2=value2&key3=value3"; + OATPP_LOGD(TAG, "urlText='%s'", urlText); + auto params = Url::Parser::parseQueryParams(urlText); + OATPP_ASSERT(params.size() == 3); + OATPP_ASSERT(params["key1"] == "value1"); + OATPP_ASSERT(params["key2"] == "value2"); + OATPP_ASSERT(params["key2"] == "value2"); + } + + { + const char *urlText = "?key1=value1&key2&key3=value3"; + OATPP_LOGD(TAG, "urlText='%s'", urlText); + auto params = Url::Parser::parseQueryParams(urlText); + OATPP_ASSERT(params.size() == 3); + OATPP_ASSERT(params["key1"] == "value1"); + OATPP_ASSERT(params["key2"] == ""); + OATPP_ASSERT(params["key3"] == "value3"); + } + + { + const char *urlText = "?key1=value1&key2&key3"; + OATPP_LOGD(TAG, "urlText='%s'", urlText); + auto params = Url::Parser::parseQueryParams(urlText); + OATPP_ASSERT(params.size() == 3); + OATPP_ASSERT(params["key1"] == "value1"); + OATPP_ASSERT(params["key2"] == ""); + OATPP_ASSERT(params["key3"] == ""); + } + + { + const char *urlText = "label?key1=value1&key2=value2&key3=value3"; + OATPP_LOGD(TAG, "urlText='%s'", urlText); + auto params = Url::Parser::labelQueryParams(urlText); + OATPP_ASSERT(params.size() == 3); + OATPP_ASSERT(params["key1"] == "value1"); + OATPP_ASSERT(params["key2"] == "value2"); + OATPP_ASSERT(params["key2"] == "value2"); + } + + { + const char* urlText = "label?key1=value1&key2&key3=value3"; + OATPP_LOGD(TAG, "urlText='%s'", urlText); + auto params = Url::Parser::labelQueryParams(urlText); + OATPP_ASSERT(params.size() == 3); + OATPP_ASSERT(params["key1"] == "value1"); + OATPP_ASSERT(params["key2"] == ""); + OATPP_ASSERT(params["key3"] == "value3"); + } + + { + const char* urlText = "label?key1=value1&key2&key3"; + OATPP_LOGD(TAG, "urlText='%s'", urlText); + auto params = Url::Parser::labelQueryParams(urlText); + OATPP_ASSERT(params.size() == 3); + OATPP_ASSERT(params["key1"] == "value1"); + OATPP_ASSERT(params["key2"] == ""); + OATPP_ASSERT(params["key3"] == ""); + } + +} + +}}} \ No newline at end of file diff --git a/test/oatpp/network/UrlTest.hpp b/test/oatpp/network/UrlTest.hpp new file mode 100644 index 00000000..86be4d70 --- /dev/null +++ b/test/oatpp/network/UrlTest.hpp @@ -0,0 +1,43 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present, Leonid Stryzhevskyi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ***************************************************************************/ + +#ifndef oatpp_test_network_UrlTest_hpp +#define oatpp_test_network_UrlTest_hpp + +#include "oatpp-test/UnitTest.hpp" + +namespace oatpp { namespace test { namespace network { + +class UrlTest : public UnitTest { +public: + + UrlTest():UnitTest("TEST[network::UrlTest]"){} + void onRun() override; + +}; + +}}} + + +#endif //oatpp_test_network_UrlTest_hpp diff --git a/test/oatpp/web/FullAsyncTest.cpp b/test/oatpp/web/FullAsyncTest.cpp index e782bffd..5e48a9e1 100644 --- a/test/oatpp/web/FullAsyncTest.cpp +++ b/test/oatpp/web/FullAsyncTest.cpp @@ -118,12 +118,14 @@ void FullAsyncTest::onRun() { { // test simple GET auto response = client->getRoot(connection); + OATPP_ASSERT(response->getStatusCode() == 200); auto value = response->readBodyToString(); OATPP_ASSERT(value == "Hello World Async!!!"); } { // test GET with path parameter auto response = client->getWithParams("my_test_param-Async", connection); + OATPP_ASSERT(response->getStatusCode() == 200); auto dto = response->readBodyToDto(objectMapper); OATPP_ASSERT(dto); OATPP_ASSERT(dto->testValue == "my_test_param-Async"); @@ -131,8 +133,7 @@ void FullAsyncTest::onRun() { { // test GET with header parameter auto response = client->getWithHeaders("my_test_header-Async", connection); - //auto str = response->readBodyToString(); - //OATPP_LOGE("AAA", "code=%d, str='%s'", response->statusCode, str->c_str()); + OATPP_ASSERT(response->getStatusCode() == 200); auto dto = response->readBodyToDto(objectMapper); OATPP_ASSERT(dto); OATPP_ASSERT(dto->testValue == "my_test_header-Async"); @@ -140,6 +141,7 @@ void FullAsyncTest::onRun() { { // test POST with body auto response = client->postBody("my_test_body-Async", connection); + OATPP_ASSERT(response->getStatusCode() == 200); auto dto = response->readBodyToDto(objectMapper); OATPP_ASSERT(dto); OATPP_ASSERT(dto->testValue == "my_test_body-Async"); @@ -152,6 +154,7 @@ void FullAsyncTest::onRun() { } auto data = stream.toString(); auto response = client->echoBody(data, connection); + OATPP_ASSERT(response->getStatusCode() == 200); auto returnedData = response->readBodyToString(); diff --git a/test/oatpp/web/FullTest.cpp b/test/oatpp/web/FullTest.cpp index 3546f662..cfb8b974 100644 --- a/test/oatpp/web/FullTest.cpp +++ b/test/oatpp/web/FullTest.cpp @@ -118,26 +118,42 @@ void FullTest::onRun() { { // test simple GET auto response = client->getRoot(connection); + OATPP_ASSERT(response->getStatusCode() == 200); auto value = response->readBodyToString(); OATPP_ASSERT(value == "Hello World!!!"); } { // test GET with path parameter auto response = client->getWithParams("my_test_param", connection); + OATPP_ASSERT(response->getStatusCode() == 200); auto dto = response->readBodyToDto(objectMapper); OATPP_ASSERT(dto); OATPP_ASSERT(dto->testValue == "my_test_param"); } - + { // test GET with query parameters - auto response = client->getWithQueries("oatpp", 1); + auto response = client->getWithQueries("oatpp", 1, connection); + OATPP_ASSERT(response->getStatusCode() == 200); auto dto = response->readBodyToDto(objectMapper); OATPP_ASSERT(dto); OATPP_ASSERT(dto->testValue == "name=oatpp&age=1"); } + { // test GET with query parameters + auto response = client->getWithQueriesMap("value1", 32, 0.32, connection); + OATPP_ASSERT(response->getStatusCode() == 200); + auto dto = response->readBodyToDto(objectMapper); + OATPP_ASSERT(dto); + OATPP_ASSERT(dto->testMap); + OATPP_ASSERT(dto->testMap->count() == 3); + OATPP_ASSERT(dto->testMap->get("key1", "") == "value1"); + OATPP_ASSERT(dto->testMap->get("key2", "") == "32"); + OATPP_ASSERT(dto->testMap->get("key3", "") == oatpp::utils::conversion::float32ToStr(0.32)); + } + { // test GET with header parameter auto response = client->getWithHeaders("my_test_header", connection); + OATPP_ASSERT(response->getStatusCode() == 200); auto dto = response->readBodyToDto(objectMapper); OATPP_ASSERT(dto); OATPP_ASSERT(dto->testValue == "my_test_header"); @@ -145,6 +161,7 @@ void FullTest::onRun() { { // test POST with body auto response = client->postBody("my_test_body", connection); + OATPP_ASSERT(response->getStatusCode() == 200); auto dto = response->readBodyToDto(objectMapper); OATPP_ASSERT(dto); OATPP_ASSERT(dto->testValue == "my_test_body"); @@ -157,6 +174,7 @@ void FullTest::onRun() { } auto data = stream.toString(); auto response = client->echoBody(data, connection); + OATPP_ASSERT(response->getStatusCode() == 200); auto returnedData = response->readBodyToString(); OATPP_ASSERT(returnedData); OATPP_ASSERT(returnedData == data); diff --git a/test/oatpp/web/app/Client.hpp b/test/oatpp/web/app/Client.hpp index ba414429..14efb5ac 100644 --- a/test/oatpp/web/app/Client.hpp +++ b/test/oatpp/web/app/Client.hpp @@ -38,6 +38,7 @@ class Client : public oatpp::web::client::ApiClient { API_CALL("GET", "/", getRoot) API_CALL("GET", "params/{param}", getWithParams, PATH(String, param)) API_CALL("GET", "queries", getWithQueries, QUERY(String, name), QUERY(Int32, age)) + API_CALL("GET", "queries/map", getWithQueriesMap, QUERY(String, key1), QUERY(Int32, key2), QUERY(Float32, key3)) API_CALL("GET", "headers", getWithHeaders, HEADER(String, param, "X-TEST-HEADER")) API_CALL("POST", "body", postBody, BODY_STRING(String, body)) API_CALL("POST", "echo", echoBody, BODY_STRING(String, body)) diff --git a/test/oatpp/web/app/Controller.hpp b/test/oatpp/web/app/Controller.hpp index eb22473f..5b5c07bd 100644 --- a/test/oatpp/web/app/Controller.hpp +++ b/test/oatpp/web/app/Controller.hpp @@ -65,22 +65,21 @@ public: } ENDPOINT("GET", "queries", getWithQueries, - QUERIES(QueryParams, queries), QUERY(String, name), QUERY(Int32, age)) { - std::ostringstream builder; - for (auto i = queries.begin(); i != queries.end(); ++i) { - if (i != queries.begin()) { - builder << "&"; - } - builder << i->first.toStdString() << "=" << i->second.toStdString(); - } - auto queryString = builder.str(); - OATPP_LOGD(TAG, "GET queries?%s =>(name=%s, age=%d)", queryString.c_str(), name->c_str(), age->getValue()); + QUERY(String, name), QUERY(Int32, age)) { auto dto = TestDto::createShared(); - - // return ordered key-value string instead of unordered from builder dto->testValue = "name=" + name + "&age=" + oatpp::utils::conversion::int32ToStr(age->getValue()); return createDtoResponse(Status::CODE_200, dto); } + + ENDPOINT("GET", "queries/map", getWithQueriesMap, + QUERIES(QueryParams, queries)) { + auto dto = TestDto::createShared(); + dto->testMap = dto->testMap->createShared(); + for(auto& it : queries) { + dto->testMap->put(it.first.toString(), it.second.toString()); + } + return createDtoResponse(Status::CODE_200, dto); + } ENDPOINT("GET", "headers", getWithHeaders, HEADER(String, param, "X-TEST-HEADER")) { diff --git a/test/oatpp/web/app/DTOs.hpp b/test/oatpp/web/app/DTOs.hpp index f91af937..18b05634 100644 --- a/test/oatpp/web/app/DTOs.hpp +++ b/test/oatpp/web/app/DTOs.hpp @@ -37,6 +37,7 @@ class TestDto : public oatpp::data::mapping::type::Object { DTO_INIT(TestDto, Object) DTO_FIELD(String, testValue); + DTO_FIELD(Fields::ObjectWrapper, testMap); };