From 3944412fa67708725bd4fe49e72e8e275fcbaf20 Mon Sep 17 00:00:00 2001 From: lganzzzo Date: Tue, 23 Jul 2019 01:29:39 +0400 Subject: [PATCH] Feature Multipart. Add Simple-API http::outgoing::MultipartBody. --- src/CMakeLists.txt | 2 + .../core/data/stream/BufferInputStream.cpp | 22 +- .../core/data/stream/BufferInputStream.hpp | 25 ++- src/oatpp/web/mime/multipart/Part.cpp | 19 ++ src/oatpp/web/mime/multipart/Part.hpp | 21 ++ src/oatpp/web/protocol/http/Http.cpp | 37 ++- src/oatpp/web/protocol/http/Http.hpp | 15 ++ .../protocol/http/outgoing/ChunkedBody.hpp | 4 +- .../protocol/http/outgoing/MultipartBody.cpp | 211 ++++++++++++++++++ .../protocol/http/outgoing/MultipartBody.hpp | 139 ++++++++++++ .../web/protocol/http/outgoing/Request.cpp | 11 +- .../web/protocol/http/outgoing/Response.cpp | 11 +- 12 files changed, 485 insertions(+), 32 deletions(-) create mode 100644 src/oatpp/web/protocol/http/outgoing/MultipartBody.cpp create mode 100644 src/oatpp/web/protocol/http/outgoing/MultipartBody.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7ade3247..0fd4878c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -175,6 +175,8 @@ add_library(oatpp oatpp/web/protocol/http/outgoing/CommunicationUtils.hpp oatpp/web/protocol/http/outgoing/DtoBody.cpp oatpp/web/protocol/http/outgoing/DtoBody.hpp + oatpp/web/protocol/http/outgoing/MultipartBody.cpp + oatpp/web/protocol/http/outgoing/MultipartBody.hpp oatpp/web/protocol/http/outgoing/Request.cpp oatpp/web/protocol/http/outgoing/Request.hpp oatpp/web/protocol/http/outgoing/Response.cpp diff --git a/src/oatpp/core/data/stream/BufferInputStream.cpp b/src/oatpp/core/data/stream/BufferInputStream.cpp index c4db0eb0..797ac734 100644 --- a/src/oatpp/core/data/stream/BufferInputStream.cpp +++ b/src/oatpp/core/data/stream/BufferInputStream.cpp @@ -34,6 +34,24 @@ BufferInputStream::BufferInputStream(const std::shared_ptr& mem , m_ioMode(IOMode::NON_BLOCKING) {} +BufferInputStream::BufferInputStream(const oatpp::String& data) + : BufferInputStream(data.getPtr(), data->getData(), data->getSize()) +{} + +void BufferInputStream::reset(const std::shared_ptr& memoryHandle, p_char8 data, v_io_size size) { + m_memoryHandle = memoryHandle; + m_data = data; + m_size = size; + m_position = 0; +} + +void BufferInputStream::reset() { + m_memoryHandle = nullptr; + m_data = nullptr; + m_size = 0; + m_position = 0; +} + data::v_io_size BufferInputStream::read(void *data, data::v_io_size count) { data::v_io_size desiredAmount = count; if(desiredAmount > m_size - m_position) { @@ -84,8 +102,8 @@ v_io_size BufferInputStream::getCurrentPosition() { return m_position; } -void BufferInputStream::resetPosition() { - m_position = 0; +void BufferInputStream::setCurrentPosition(v_io_size position) { + m_position = position; } }}} \ No newline at end of file diff --git a/src/oatpp/core/data/stream/BufferInputStream.hpp b/src/oatpp/core/data/stream/BufferInputStream.hpp index 06488c78..3aef07a1 100644 --- a/src/oatpp/core/data/stream/BufferInputStream.hpp +++ b/src/oatpp/core/data/stream/BufferInputStream.hpp @@ -46,6 +46,26 @@ public: */ BufferInputStream(const std::shared_ptr& memoryHandle, p_char8 data, v_io_size size); + /** + * Constructor. + * @param data - buffer. + */ + BufferInputStream(const oatpp::String& data); + + /** + * Reset stream data and set position to `0`. + * @param memoryHandle - buffer memory handle. May be nullptr. + * @param data - pointer to buffer data. + * @param size - size of the buffer. + */ + void reset(const std::shared_ptr& memoryHandle, p_char8 data, v_io_size size); + + + /** + * Same as `reset(nullptr, nullptr, 0);.` + */ + void reset(); + /** * Read data from stream.
* It is a legal case if return result < count. Caller should handle this! @@ -101,9 +121,10 @@ public: v_io_size getCurrentPosition(); /** - * Reset current data read position to zero. + * Set current data read position. + * @param position - data read position. */ - void resetPosition(); + void setCurrentPosition(v_io_size position); }; diff --git a/src/oatpp/web/mime/multipart/Part.cpp b/src/oatpp/web/mime/multipart/Part.cpp index b28cea77..554cb078 100644 --- a/src/oatpp/web/mime/multipart/Part.cpp +++ b/src/oatpp/web/mime/multipart/Part.cpp @@ -66,6 +66,12 @@ void Part::setDataInfo(const std::shared_ptr& inputSt m_knownSize = knownSize; } +void Part::setDataInfo(const std::shared_ptr& inputStream) { + m_inputStream = inputStream; + m_inMemoryData = nullptr; + m_knownSize = -1; +} + oatpp::String Part::getName() const { return m_name; } @@ -88,6 +94,19 @@ oatpp::String Part::getHeader(const oatpp::data::share::StringKeyLabelCI_FAST &h return nullptr; } +void Part::putHeader(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value) { + m_headers[key] = value; +} + +bool Part::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 Part::getInputStream() const { return m_inputStream; } diff --git a/src/oatpp/web/mime/multipart/Part.hpp b/src/oatpp/web/mime/multipart/Part.hpp index 514ca6d8..6778af18 100644 --- a/src/oatpp/web/mime/multipart/Part.hpp +++ b/src/oatpp/web/mime/multipart/Part.hpp @@ -79,6 +79,12 @@ public: const oatpp::String inMemoryData, data::v_io_size knownSize); + /** + * Same as `setDataInfo(inputStream, nullptr, -1);.` + * @param inputStream - input stream of the part data. + */ + void setDataInfo(const std::shared_ptr& inputStream); + /** * Get name of the part. * @return - name of the part. @@ -104,6 +110,21 @@ public: */ oatpp::String getHeader(const oatpp::data::share::StringKeyLabelCI_FAST& headerName) const; + /** + * Add http header. + * @param key - &id:oatpp::data::share::StringKeyLabelCI_FAST;. + * @param value - &id:oatpp::data::share::StringKeyLabel;. + */ + void putHeader(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value); + + /** + * Add http header if not already exists. + * @param key - &id:oatpp::data::share::StringKeyLabelCI_FAST;. + * @param value - &id:oatpp::data::share::StringKeyLabel;. + * @return - `true` if header was added. + */ + bool putHeaderIfNotExists(const oatpp::data::share::StringKeyLabelCI_FAST& key, const oatpp::data::share::StringKeyLabel& value); + /** * Get input stream of the part data. * @return - input stream of the part data. diff --git a/src/oatpp/web/protocol/http/Http.cpp b/src/oatpp/web/protocol/http/Http.cpp index 13cbd6ee..a8a9b3c7 100644 --- a/src/oatpp/web/protocol/http/Http.cpp +++ b/src/oatpp/web/protocol/http/Http.cpp @@ -244,6 +244,9 @@ oatpp::String HeaderValueData::getTitleParamValue(const data::share::StringKeyLa } return nullptr; } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Parser oatpp::data::share::StringKeyLabelCI_FAST Parser::parseHeaderNameLabel(const std::shared_ptr& headersText, oatpp::parser::Caret& caret) { @@ -367,36 +370,38 @@ void Parser::parseHeaderValueData(HeaderValueData& data, const oatpp::data::shar v_char8 charSet[5] = {' ', '=', separator, '\r', '\n'}; v_char8 charSet2[4] = {' ', separator, '\r', '\n'}; - while(caret.canContinue()) { + while (caret.canContinue()) { caret.skipChar(' '); auto label = caret.putLabel(); auto res = caret.findCharFromSet(charSet, 5); - if(res == '=') { + if (res == '=') { data::share::StringKeyLabelCI key(headerValue.getMemoryHandle(), label.getData(), label.getSize()); caret.inc(); - if(caret.isAtChar('"')) { + if (caret.isAtChar('"')) { label = caret.parseStringEnclosed('"', '"', '\\'); - } else if(caret.isAtChar('\'')) { + } else if (caret.isAtChar('\'')) { label = caret.parseStringEnclosed('\'', '\'', '\\'); } else { label = caret.putLabel(); auto r = caret.findCharFromSet(charSet2, 4); } - data.titleParams[key] = data::share::StringKeyLabel(headerValue.getMemoryHandle(), label.getData(), label.getSize()); + data.titleParams[key] = data::share::StringKeyLabel(headerValue.getMemoryHandle(), label.getData(), + label.getSize()); } else { - data.tokens.insert(data::share::StringKeyLabelCI(headerValue.getMemoryHandle(), label.getData(), label.getSize())); + data.tokens.insert( + data::share::StringKeyLabelCI(headerValue.getMemoryHandle(), label.getData(), label.getSize())); } - if(caret.isAtCharFromSet((p_char8)"\r\n", 2)) { + if (caret.isAtCharFromSet((p_char8) "\r\n", 2)) { break; - } else if(caret.isAtChar(separator)) { + } else if (caret.isAtChar(separator)) { caret.inc(); } @@ -404,4 +409,20 @@ void Parser::parseHeaderValueData(HeaderValueData& data, const oatpp::data::shar } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Utils + +void Utils::writeHeaders(const Headers& headers, data::stream::ConsistentOutputStream* stream) { + + auto it = headers.begin(); + while(it != headers.end()) { + stream->write(it->first.getData(), it->first.getSize()); + stream->write(": ", 2); + stream->write(it->second.getData(), it->second.getSize()); + stream->write("\r\n", 2); + it ++; + } + +} + }}}} diff --git a/src/oatpp/web/protocol/http/Http.hpp b/src/oatpp/web/protocol/http/Http.hpp index ef4ccc3a..3a1a7779 100644 --- a/src/oatpp/web/protocol/http/Http.hpp +++ b/src/oatpp/web/protocol/http/Http.hpp @@ -684,6 +684,21 @@ public: static void parseHeaderValueData(HeaderValueData& data, const oatpp::data::share::StringKeyLabel& headerValue, v_char8 separator); }; + +/** + * Http utils. + */ +class Utils { +public: + + /** + * Write headers map to stream. + * @param headers + * @param stream + */ + static void writeHeaders(const Headers& headers, data::stream::ConsistentOutputStream* stream); + +}; }}}} diff --git a/src/oatpp/web/protocol/http/outgoing/ChunkedBody.hpp b/src/oatpp/web/protocol/http/outgoing/ChunkedBody.hpp index ced819ef..22a8370c 100644 --- a/src/oatpp/web/protocol/http/outgoing/ChunkedBody.hpp +++ b/src/oatpp/web/protocol/http/outgoing/ChunkedBody.hpp @@ -70,7 +70,7 @@ public: ~ChunkedBody(); /** - * Declare `Transfer-Encoding: chunked` header + * Declare `Transfer-Encoding: chunked` header. * @param headers - &id:oatpp::web::protocol::http::Headers;. */ void declareHeaders(Headers& headers) noexcept override; @@ -82,7 +82,7 @@ public: void writeToStream(OutputStream* stream) noexcept override; /** - * Start &l:ChunkedBody::WriteToStreamCoroutine; to write buffer data to stream. + * Write body data to stream in asynchronous manner. * @param stream - &id:oatpp::data::stream::OutputStream;. * @return - &id:oatpp::async::CoroutineStarter;. */ diff --git a/src/oatpp/web/protocol/http/outgoing/MultipartBody.cpp b/src/oatpp/web/protocol/http/outgoing/MultipartBody.cpp new file mode 100644 index 00000000..6df85500 --- /dev/null +++ b/src/oatpp/web/protocol/http/outgoing/MultipartBody.cpp @@ -0,0 +1,211 @@ +/*************************************************************************** + * + * 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 "MultipartBody.hpp" + +#include "oatpp/core/data/stream/ChunkedBuffer.hpp" + +namespace oatpp { namespace web { namespace protocol { namespace http { namespace outgoing { + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// MultipartReadCallback + +MultipartBody::MultipartReadCallback::MultipartReadCallback(const std::shared_ptr& multipart) + : m_multipart(multipart) + , m_iterator(multipart->getAllParts().begin()) + , m_state(STATE_BOUNDARY) + , m_readStream(nullptr, nullptr, 0) +{} + +data::v_io_size MultipartBody::MultipartReadCallback::readBoundary(void *buffer, data::v_io_size count) { + + if (!m_readStream.getDataMemoryHandle()) { + + oatpp::String boundary; + + if (m_iterator == m_multipart->getAllParts().end()) { + boundary = "\r\n--" + m_multipart->getBoundary() + "--\r\n"; + } else if (m_iterator == m_multipart->getAllParts().begin()) { + boundary = "--" + m_multipart->getBoundary() + "\r\n"; + } else { + boundary = "\r\n--" + m_multipart->getBoundary() + "\r\n"; + } + + m_readStream.reset(boundary.getPtr(), boundary->getData(), boundary->getSize()); + + } + + auto res = m_readStream.read(buffer, count); + if(res == 0) { + m_readStream.reset(); + } + return res; + +} + +data::v_io_size MultipartBody::MultipartReadCallback::readHeaders(void *buffer, data::v_io_size count) { + + if (!m_readStream.getDataMemoryHandle()) { + + oatpp::data::stream::ChunkedBuffer stream; + auto& part = *m_iterator; + http::Utils::writeHeaders(part->getHeaders(), &stream); + stream.write("\r\n", 2); + auto buffer = stream.toString(); + m_readStream.reset(buffer.getPtr(), buffer->getData(), buffer->getSize()); + + } + + auto res = m_readStream.read(buffer, count); + if(res == 0) { + m_readStream.reset(); + } + return res; + +} + +data::v_io_size MultipartBody::MultipartReadCallback::readBody(void *buffer, data::v_io_size count) { + auto& part = *m_iterator; + const auto& stream = part->getInputStream(); + if(!stream) { + OATPP_LOGE("[oatpp::web::protocol::http::outgoing::MultipartBody::MultipartReadCallback::readBody()]", "Error. Part has no input stream", m_state); + m_iterator ++; + return 0; + } + auto res = stream->read(buffer, count); + if(res == 0) { + m_iterator ++; + } + return res; +} + +data::v_io_size MultipartBody::MultipartReadCallback::read(void *buffer, data::v_io_size count) { + + if(m_state == STATE_FINISHED) { + return 0; + } + + p_char8 currBufferPtr = (p_char8) buffer; + data::v_io_size bytesLeft = count; + + data::v_io_size res = 0; + + while(bytesLeft > 0) { + + switch (m_state) { + + case STATE_BOUNDARY: + res = readBoundary(currBufferPtr, bytesLeft); + break; + + case STATE_HEADERS: + res = readHeaders(currBufferPtr, bytesLeft); + break; + + case STATE_BODY: + res = readBody(currBufferPtr, bytesLeft); + break; + + default: + OATPP_LOGE("[oatpp::web::protocol::http::outgoing::MultipartBody::MultipartReadCallback::read()]", "Error. Invalid state %d", m_state); + return 0; + + } + + if(res > 0) { + currBufferPtr = &currBufferPtr[res]; + bytesLeft -= res; + } else if(res == 0) { + + if(m_state == STATE_BOUNDARY && m_iterator == m_multipart->getAllParts().end()) { + m_state = STATE_FINISHED; + break; + } + + m_state += 1; + if(m_state == STATE_ROUND) { + m_state = 0; + } + + } else { + OATPP_LOGE("[oatpp::web::protocol::http::outgoing::MultipartBody::MultipartReadCallback::read()]", "Error. Invalid read result %d. State=%d", res, m_state); + return 0; + } + + } + + return count - bytesLeft; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AsyncMultipartReadCallback + +MultipartBody::AsyncMultipartReadCallback::AsyncMultipartReadCallback(const std::shared_ptr& multipart) + : m_multipart(multipart) +{} + +oatpp::async::Action MultipartBody::AsyncMultipartReadCallback::readAsyncInline(oatpp::async::AbstractCoroutine* coroutine, + void*& currBufferPtr, + data::v_io_size& bytesLeftToRead, + oatpp::async::Action&& nextAction) +{ + return std::forward(nextAction); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// MultipartBody + +MultipartBody::MultipartBody(const std::shared_ptr& multipart) + : ChunkedBody(std::make_shared(multipart), + std::make_shared(multipart), + 4096) + , m_multipart(multipart) +{} + +void MultipartBody::declareHeaders(Headers& headers) noexcept { + if(m_multipart->getAllParts().empty()) { + headers[oatpp::web::protocol::http::Header::CONTENT_LENGTH] = "0"; + return; + } + ChunkedBody::declareHeaders(headers); + headers[oatpp::web::protocol::http::Header::CONTENT_TYPE] = "multipart/form-data; boundary=" + m_multipart->getBoundary(); +} + +void MultipartBody::writeToStream(OutputStream* stream) noexcept { + if(m_multipart->getAllParts().empty()) { + return; + } + ChunkedBody::writeToStream(stream); +} + +oatpp::async::CoroutineStarter MultipartBody::writeToStreamAsync(const std::shared_ptr& stream) { + if(m_multipart->getAllParts().empty()) { + return nullptr; + } + return ChunkedBody::writeToStreamAsync(stream); +} + + + +}}}}} diff --git a/src/oatpp/web/protocol/http/outgoing/MultipartBody.hpp b/src/oatpp/web/protocol/http/outgoing/MultipartBody.hpp new file mode 100644 index 00000000..d642f763 --- /dev/null +++ b/src/oatpp/web/protocol/http/outgoing/MultipartBody.hpp @@ -0,0 +1,139 @@ +/*************************************************************************** + * + * 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_web_protocol_http_outgoing_MultipartBody_hpp +#define oatpp_web_protocol_http_outgoing_MultipartBody_hpp + +#include "./Body.hpp" +#include "./ChunkedBody.hpp" + +#include "oatpp/web/mime/multipart/Multipart.hpp" + +#include "oatpp/core/data/stream/BufferInputStream.hpp" + +namespace oatpp { namespace web { namespace protocol { namespace http { namespace outgoing { + +class MultipartBody : public ChunkedBody { +public: + + /** + * Convenience typedef for &id:oatpp::web::mime::multipart::Multipart;. + */ + typedef oatpp::web::mime::multipart::Multipart Multipart; + + /** + * Convenience typedef for &id:oatpp::web::mime::multipart::Part;. + */ + typedef oatpp::web::mime::multipart::Part Part; +private: + + /* + * Convenience typedef for &id:oatpp::data::stream::ReadCallback;. + */ + typedef oatpp::data::stream::ReadCallback ReadCallback; + + /* + * Convenience typedef for &id:oatpp::data::stream::AsyncReadCallback;. + */ + typedef oatpp::data::stream::AsyncReadCallback AsyncReadCallback; + +private: + + static constexpr v_int32 STATE_BOUNDARY = 0; + static constexpr v_int32 STATE_HEADERS = 1; + static constexpr v_int32 STATE_BODY = 2; + static constexpr v_int32 STATE_ROUND = 3; // number of possible states. used to round the state. + static constexpr v_int32 STATE_FINISHED = 4; + +private: + + class MultipartReadCallback : public ReadCallback { + private: + std::shared_ptr m_multipart; + std::list>::const_iterator m_iterator; + v_int32 m_state; + oatpp::data::stream::BufferInputStream m_readStream; + private: + data::v_io_size readBoundary(void *buffer, data::v_io_size count); + data::v_io_size readHeaders(void *buffer, data::v_io_size count); + data::v_io_size readBody(void *buffer, data::v_io_size count); + public: + + MultipartReadCallback(const std::shared_ptr& multipart); + + data::v_io_size read(void *buffer, data::v_io_size count) override; + + }; + +private: + + class AsyncMultipartReadCallback : public AsyncReadCallback { + private: + std::shared_ptr m_multipart; + public: + + AsyncMultipartReadCallback(const std::shared_ptr& multipart); + + oatpp::async::Action readAsyncInline(oatpp::async::AbstractCoroutine* coroutine, + void*& currBufferPtr, + data::v_io_size& bytesLeftToRead, + oatpp::async::Action&& nextAction) override; + + }; + +private: + std::shared_ptr m_multipart; +public: + + /** + * Constructor. + * @param multipart - multipart object. + */ + MultipartBody(const std::shared_ptr& multipart); + + + /** + * Declare `Transfer-Encoding: chunked`, `Content-Type: multipart/` header. + * @param headers - &id:oatpp::web::protocol::http::Headers;. + */ + void declareHeaders(Headers& headers) noexcept override; + + /** + * Write body data to stream. + * @param stream - pointer to &id:oatpp::data::stream::OutputStream;. + */ + void writeToStream(OutputStream* stream) noexcept override; + + /** + * Write body data to stream in asynchronous manner. + * @param stream - &id:oatpp::data::stream::OutputStream;. + * @return - &id:oatpp::async::CoroutineStarter;. + */ + oatpp::async::CoroutineStarter writeToStreamAsync(const std::shared_ptr& stream) override; + +}; + +}}}}} + +#endif // oatpp_web_protocol_http_outgoing_MultipartBody_hpp diff --git a/src/oatpp/web/protocol/http/outgoing/Request.cpp b/src/oatpp/web/protocol/http/outgoing/Request.cpp index c1f0bc81..95ccb5fb 100644 --- a/src/oatpp/web/protocol/http/outgoing/Request.cpp +++ b/src/oatpp/web/protocol/http/outgoing/Request.cpp @@ -134,15 +134,8 @@ oatpp::async::CoroutineStarter Request::sendAsync(const std::shared_ptrwrite(" ", 1); m_buffer->write("HTTP/1.1", 8); m_buffer->write("\r\n", 2); - - auto it = m_request->m_headers.begin(); - while(it != m_request->m_headers.end()){ - m_buffer->write(it->first.getData(), it->first.getSize()); - m_buffer->write(": ", 2); - m_buffer->write(it->second.getData(), it->second.getSize()); - m_buffer->write("\r\n", 2); - it++; - } + + http::Utils::writeHeaders(m_request->m_headers, m_buffer.get()); m_buffer->write("\r\n", 2); diff --git a/src/oatpp/web/protocol/http/outgoing/Response.cpp b/src/oatpp/web/protocol/http/outgoing/Response.cpp index 756a5832..9b21e24e 100644 --- a/src/oatpp/web/protocol/http/outgoing/Response.cpp +++ b/src/oatpp/web/protocol/http/outgoing/Response.cpp @@ -138,15 +138,8 @@ oatpp::async::CoroutineStarter Response::sendAsync(const std::shared_ptrwrite(" ", 1); m_buffer->OutputStream::write(m_response->m_status.description); m_buffer->write("\r\n", 2); - - auto it = m_response->m_headers.begin(); - while(it != m_response->m_headers.end()) { - m_buffer->write(it->first.getData(), it->first.getSize()); - m_buffer->write(": ", 2); - m_buffer->write(it->second.getData(), it->second.getSize()); - m_buffer->write("\r\n", 2); - it ++; - } + + http::Utils::writeHeaders(m_response->m_headers, m_buffer.get()); m_buffer->write("\r\n", 2);